From f07140940c4ef5c062fbf1c2f7d3743b3d1fd29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Sat, 21 Jul 2018 18:15:31 +0200 Subject: Eevee: Principled: Fix Subsurface input behaviour Match Cycles behaviour of scalling the SSS radius and don't interpolate between diffuse and SSS result. --- source/blender/gpu/shaders/gpu_shader_material.glsl | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'source') diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 961837f6b16..464851bae21 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1145,15 +1145,18 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs clearcoat *= 0.25; clearcoat *= 1.0 - transmission; + vec3 mixed_ss_base_color = mix(diffuse, subsurface_color.rgb, subsurface); + #ifdef USE_SSS - diffuse = mix(diffuse, vec3(0.0), subsurface); + diffuse = vec3(0.0); #else - diffuse = mix(diffuse, subsurface_color.rgb, subsurface); + diffuse = mixed_ss_base_color; #endif + f0 = mix(f0, vec3(1.0), transmission); - float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)); - eevee_closure_principled(N, diffuse, f0, int(ssr_id), roughness, + float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0)) * subsurface; + eevee_closure_principled(N, mixed_ss_base_color, f0, int(ssr_id), roughness, CN, clearcoat, clearcoat_roughness, 1.0, sss_scalef, ior, out_diff, out_trans, out_spec, out_refr, ssr_spec); @@ -1177,11 +1180,11 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs #ifdef USE_SSS result.sss_data.a = sss_scalef; result.sss_data.rgb = out_diff + out_trans; -#ifdef USE_SSS_ALBEDO - result.sss_albedo.rgb = mix(vec3(0.0), subsurface_color.rgb, subsurface); -#else - result.sss_data.rgb *= mix(vec3(0.0), subsurface_color.rgb, subsurface); -#endif +# ifdef USE_SSS_ALBEDO + result.sss_albedo.rgb = mixed_ss_base_color; +# else + result.sss_data.rgb *= mixed_ss_base_color; +# endif result.sss_data.rgb *= (1.0 - transmission); #endif } -- cgit v1.2.3 From d432a239adee7e04b264303ec7e3ef6ffc8ce403 Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Mon, 23 Jul 2018 11:20:31 +0200 Subject: Outliner Keymap: E key to Exclude collections from View Layer Alt+E to include. --- source/blender/editors/space_outliner/outliner_ops.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source') diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 0dd492839c9..8b4ae029876 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -570,6 +570,9 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "OBJECT_OT_move_to_collection", MKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_link_to_collection", MKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_collection_exclude_set", EKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_collection_include_set", EKEY, KM_PRESS, KM_ALT, 0); + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "select", false); kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_set", HKEY, KM_PRESS, 0, 0); -- cgit v1.2.3 From 96abec41ccf0a58b085095640faadf36c5d9ed9a Mon Sep 17 00:00:00 2001 From: Ines Almeida Date: Sun, 27 May 2018 10:33:34 +0200 Subject: Cleanup: comments and UI descriptions for cursor snapping --- source/blender/editors/space_view3d/view3d_snap.c | 58 +++++++++++++++-------- 1 file changed, 37 insertions(+), 21 deletions(-) (limited to 'source') diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 7799854db49..6a8589f5468 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -72,6 +72,7 @@ static bool snap_calc_active_center(bContext *C, const bool select_only, float r /* *********************** operators ******************** */ +/** Snaps every individual object center to its nearest point on the grid. **/ static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) { Depsgraph *depsgraph = CTX_data_depsgraph(C); @@ -212,7 +213,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Selection to Grid"; - ot->description = "Snap selected item(s) to nearest grid division"; + ot->description = "Snap selected item(s) to their nearest grid division"; ot->idname = "VIEW3D_OT_snap_selected_to_grid"; /* api callbacks */ @@ -225,6 +226,12 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) /* *************************************************** */ +/** Snaps the selection as a whole (use_offset=true) or each selected object to the given location. + * + * \param snap_target_global: a location in global space to snap to (eg. 3D cursor or active object). + * \param use_offset: if the selected objects should maintain their relative offsets and be snapped by the selection + * pivot point (median, active), or if every object origin should be snapped to the given location. +**/ static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset) { Depsgraph *depsgraph = CTX_data_depsgraph(C); @@ -434,7 +441,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Selection to Cursor"; - ot->description = "Snap selected item(s) to cursor"; + ot->description = "Snap selected item(s) to the 3D cursor"; ot->idname = "VIEW3D_OT_snap_selected_to_cursor"; /* api callbacks */ @@ -445,9 +452,13 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* rna */ - RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", ""); + RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", + "If the selection should be snapped as a whole or by each object center"); } +/* *************************************************** */ + +/** Snaps each selected object to the location of the active selected object. **/ static int snap_selected_to_active_exec(bContext *C, wmOperator *op) { float snap_target_global[3]; @@ -478,6 +489,7 @@ void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot) /* *************************************************** */ +/** Snaps the 3D cursor location to its nearest point on the grid. **/ static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -502,7 +514,7 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Cursor to Grid"; - ot->description = "Snap cursor to nearest grid division"; + ot->description = "Snap 3D cursor to the nearest grid division"; ot->idname = "VIEW3D_OT_snap_cursor_to_grid"; /* api callbacks */ @@ -515,7 +527,8 @@ void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot) /* **************************************************** */ -static void bundle_midpoint(Depsgraph *depsgraph, Scene *scene, Object *ob, float vec[3]) +/** Returns the center position of a tracking marker visible on the viewport (useful to snap to). **/ +static void bundle_midpoint(Depsgraph *depsgraph, Scene *scene, Object *ob, float r_vec[3]) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); MovieTracking *tracking; @@ -563,10 +576,11 @@ static void bundle_midpoint(Depsgraph *depsgraph, Scene *scene, Object *ob, floa } if (ok) { - mid_v3_v3v3(vec, min, max); + mid_v3_v3v3(r_vec, min, max); } } +/** Snaps the 3D cursor location to the median point of the selection. **/ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) { Depsgraph *depsgraph = CTX_data_depsgraph(C); @@ -690,7 +704,7 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Cursor to Selected"; - ot->description = "Snap cursor to center of selected item(s)"; + ot->description = "Snap 3D cursor to the middle of the selected item(s)"; ot->idname = "VIEW3D_OT_snap_cursor_to_selected"; /* api callbacks */ @@ -703,9 +717,11 @@ void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot) /* ********************************************** */ -/* this could be exported to be a generic function - * see: calculateCenterActive */ - +/** Calculates the center position of the active object in global space. + * + * Note: this could be exported to be a generic function. + * see: calculateCenterActive +**/ static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]) { const Depsgraph *depsgraph = CTX_data_depsgraph(C); @@ -770,7 +786,7 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Cursor to Active"; - ot->description = "Snap cursor to active item"; + ot->description = "Snap 3D cursor to the active item"; ot->idname = "VIEW3D_OT_snap_cursor_to_active"; /* api callbacks */ @@ -782,7 +798,8 @@ void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot) } /* **************************************************** */ -/*New Code - Snap Cursor to Center -*/ + +/** Snaps the 3D cursor location to the origin. **/ static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -802,7 +819,7 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot) { /* identifiers */ ot->name = "Snap Cursor to Center"; - ot->description = "Snap cursor to world origin"; + ot->description = "Snap 3D cursor to the world origin"; ot->idname = "VIEW3D_OT_snap_cursor_to_center"; /* api callbacks */ @@ -815,23 +832,22 @@ void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot) /* **************************************************** */ - -bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3]) +/** Calculates the bounding box corners (min and max) for \a obedit. The returned values are in global space. **/ +bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3]) { TransVertStore tvs = {NULL}; TransVert *tv; float centroid[3], vec[3], bmat[3][3]; - int a; - /* metaballs are an exception */ + /* Metaballs are an exception. */ if (obedit->type == OB_MBALL) { float ob_min[3], ob_max[3]; bool changed; changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT); if (changed) { - minmax_v3v3_v3(min, max, ob_min); - minmax_v3v3_v3(min, max, ob_max); + minmax_v3v3_v3(r_min, r_max, ob_min); + minmax_v3v3_v3(r_min, r_max, ob_max); } return changed; } @@ -845,12 +861,12 @@ bool ED_view3d_minmax_verts(Object *obedit, float min[3], float max[3]) copy_m3_m4(bmat, obedit->obmat); tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { + for (int a = 0; a < tvs.transverts_tot; a++, tv++) { copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit->obmat[3]); add_v3_v3(centroid, vec); - minmax_v3v3_v3(min, max, vec); + minmax_v3v3_v3(r_min, r_max, vec); } ED_transverts_free(&tvs); -- cgit v1.2.3 From f0dd7dd4c01d2c1b2c4d9a6cbec9bfab1566b795 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jul 2018 11:42:44 +0200 Subject: Mark view layer renderability and scene single layer render as non-animatable We can not support animation of those flags reliably in the pipeline, so just mark them as non-animatable. --- source/blender/makesrna/intern/rna_scene.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 339d3841b30..dd08be4c943 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4255,6 +4255,7 @@ static void rna_def_scene_render_view(BlenderRNA *brna) prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "viewflag", SCE_VIEW_DISABLE); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Enabled", "Disable or enable the render view"); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); } @@ -5412,6 +5413,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_single_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_SINGLE_LAYER); RNA_def_property_ui_text(prop, "Render Single Layer", "Only render the active layer"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); /* views (stereoscopy et al) */ -- cgit v1.2.3 From d7b472c19898a04a4b90da45d2749872ef56bd88 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jul 2018 11:47:06 +0200 Subject: Fix wrong view layer rendered from command line The issue was caused by Render Single Layer option enabled, which is very handy for artists work, so they can hit F12 and see view layer they are currently working in a final rendered state. This saves a lot of time since all the "non-interesting" objects are ignored for such iterations. However, for the render farm we need to render view layers which are explicitly set for render, and ignore active view layer. Reasonable solution seems to be to ignore the Render Single Layer option when rendering from the command line. It is really something more like UI behavior option. --- source/blender/makesrna/intern/rna_scene.c | 2 +- source/blender/render/intern/include/render_result.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index dd08be4c943..b44a53fa90b 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5412,7 +5412,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_single_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_SINGLE_LAYER); - RNA_def_property_ui_text(prop, "Render Single Layer", "Only render the active layer"); + RNA_def_property_ui_text(prop, "Render Single Layer", "Only render the active layer. Only affects rendering from the interface, ignored for rendering from command line"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h index 3096949b49f..ab7eee128f0 100644 --- a/source/blender/render/intern/include/render_result.h +++ b/source/blender/render/intern/include/render_result.h @@ -123,7 +123,7 @@ bool render_result_has_views(struct RenderResult *rr); iter_ != NULL; \ iter_ = iter_->next, nr_++) \ { \ - if ((re_)->r.scemode & R_SINGLE_LAYER) { \ + if (!G.background && (re_)->r.scemode & R_SINGLE_LAYER) { \ if (nr_ != re->active_view_layer) { \ continue; \ } \ -- cgit v1.2.3 From 66fde2d0b57f2597d38545937640bad8b6f7ed30 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jul 2018 12:53:46 +0200 Subject: Fix T55634: Particle Viewport Display affects render visibilty Changed code to follow master behavior closer: ignore draw-as checks when particles are evaluating for rendering. --- source/blender/blenkernel/intern/particle_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 35c8761f671..cee1c9147b5 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2941,7 +2941,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons skip = 1; /* only hair, keyed and baked stuff can have paths */ else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR))) skip = 1; /* particle visualization must be set as path */ - else { + else if (DEG_get_mode(sim->depsgraph) != DAG_EVAL_RENDER) { if (part->draw_as != PART_DRAW_REND) skip = 1; /* draw visualization */ else if (psys->pointcache->flag & PTCACHE_BAKING) -- cgit v1.2.3 From 59286ddcf80c391094d64dcbbb94640bf73bd0d9 Mon Sep 17 00:00:00 2001 From: Germano Date: Mon, 23 Jul 2018 11:04:58 -0300 Subject: transform_snap_object: Better bvhtree creation management for editing multiple objects. - Use the object referenced in `BMEditMesh` as the `ghash` key to save the bvhtrees in cache; - Create a boundbox around edit_mesh to test the snap before creating bvhtree; - Save the `edit_mesh`s bvhtree in the mesh bvh_cache; This is a part of the D3504. --- source/blender/blenkernel/BKE_bvhutils.h | 8 +- source/blender/blenkernel/intern/bvhutils.c | 79 +++++++++-- .../editors/transform/transform_snap_object.c | 149 ++++++++++++++++++--- 3 files changed, 203 insertions(+), 33 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index d79a7eae53e..a0780a5be54 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -102,7 +102,7 @@ typedef struct BVHTreeFromMesh { */ BVHTree *bvhtree_from_editmesh_verts( BVHTreeFromEditMesh *data, struct BMEditMesh *em, - float epsilon, int tree_type, int axis); + float epsilon, int tree_type, int axis, BVHCache **bvh_cache); BVHTree *bvhtree_from_editmesh_verts_ex( BVHTreeFromEditMesh *data, struct BMEditMesh *em, const BLI_bitmap *mask, int verts_num_active, @@ -115,7 +115,7 @@ BVHTree *bvhtree_from_mesh_verts_ex( BVHTree *bvhtree_from_editmesh_edges( BVHTreeFromEditMesh *data, struct BMEditMesh *em, - float epsilon, int tree_type, int axis); + float epsilon, int tree_type, int axis, BVHCache **bvh_cache); BVHTree *bvhtree_from_editmesh_edges_ex( BVHTreeFromEditMesh *data, struct BMEditMesh *em, const BLI_bitmap *edges_mask, int edges_num_active, @@ -190,7 +190,9 @@ enum { BVHTREE_FROM_LOOSEVERTS = 4, BVHTREE_FROM_LOOSEEDGES = 5, - BVHTREE_FROM_EM_LOOPTRI = 6, + BVHTREE_FROM_EM_VERTS = 6, + BVHTREE_FROM_EM_EDGES = 7, + BVHTREE_FROM_EM_LOOPTRI = 8, }; diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 1a7c4e2a4a0..19ac81b4bb7 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -495,12 +495,39 @@ BVHTree *bvhtree_from_editmesh_verts_ex( BVHTree *bvhtree_from_editmesh_verts( BVHTreeFromEditMesh *data, BMEditMesh *em, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvh_cache) { - return bvhtree_from_editmesh_verts_ex( - data, em, - NULL, -1, - epsilon, tree_type, axis); + if (bvh_cache) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); + data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree); + BLI_rw_mutex_unlock(&cache_rwlock); + + if (data->cached == false) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + data->cached = bvhcache_find( + *bvh_cache, BVHTREE_FROM_EM_VERTS, &data->tree); + if (data->cached == false) { + data->tree = bvhtree_from_editmesh_verts_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert( + bvh_cache, data->tree, BVHTREE_FROM_EM_VERTS); + } + BLI_rw_mutex_unlock(&cache_rwlock); + } + } + else { + data->tree = bvhtree_from_editmesh_verts_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + } + + return data->tree; } /** @@ -649,12 +676,39 @@ BVHTree *bvhtree_from_editmesh_edges_ex( BVHTree *bvhtree_from_editmesh_edges( BVHTreeFromEditMesh *data, BMEditMesh *em, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvh_cache) { - return bvhtree_from_editmesh_edges_ex( - data, em, - NULL, -1, - epsilon, tree_type, axis); + if (bvh_cache) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); + data->cached = bvhcache_find(*bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree); + BLI_rw_mutex_unlock(&cache_rwlock); + + if (data->cached == false) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + data->cached = bvhcache_find( + *bvh_cache, BVHTREE_FROM_EM_EDGES, &data->tree); + if (data->cached == false) { + data->tree = bvhtree_from_editmesh_edges_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert( + bvh_cache, data->tree, BVHTREE_FROM_EM_EDGES); + } + BLI_rw_mutex_unlock(&cache_rwlock); + } + } + else { + data->tree = bvhtree_from_editmesh_edges_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); + } + + return data->tree; } /** @@ -1407,6 +1461,11 @@ BVHTree *BKE_bvhtree_from_mesh_get( BLI_rw_mutex_unlock(&cache_rwlock); } break; + case BVHTREE_FROM_EM_VERTS: + case BVHTREE_FROM_EM_EDGES: + case BVHTREE_FROM_EM_LOOPTRI: + BLI_assert(false); + break; } if (data_cp.tree != NULL) { diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index e19320fa220..b826e72acaf 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -111,6 +111,10 @@ typedef struct SnapObjectData_EditMesh { SnapObjectData sd; BVHTreeFromEditMesh *bvh_trees[3]; + /* It's like a boundbox. It is tested first to avoid + * to create a bvhtree for all the edited objects. */ + float min[3], max[3]; + } SnapObjectData_EditMesh; struct SnapObjectContext { @@ -156,6 +160,19 @@ struct SnapObjectContext { typedef void(*IterSnapObjsCallback)(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data); +static void min_max_from_bmesh( + BMesh *bm, float r_min[3], float r_max[3]) +{ + BMIter iter; + BMVert *eve; + + INIT_MINMAX(r_min, r_max); + BM_ITER_MESH(eve, &iter, bm, BM_VERTS_OF_MESH) { + minmax_v3v3_v3(r_min, r_max, eve->co); + } +} + + /** * Walks through all objects in the scene to create the list of objets to snap. * @@ -170,8 +187,8 @@ static void iter_snap_objects( void *data) { ViewLayer *view_layer = DEG_get_evaluated_view_layer(sctx->depsgraph); - Object *obedit = params->use_object_edit_cage ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL; const eSnapSelect snap_select = params->snap_select; + const bool use_object_edit_cage = params->use_object_edit_cage; Base *base_act = view_layer->basact; for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { @@ -179,20 +196,17 @@ static void iter_snap_objects( !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) || (snap_select == SNAP_NOT_ACTIVE && base == base_act))) { - bool use_obedit; Object *obj = base->object; if (obj->transflag & OB_DUPLI) { DupliObject *dupli_ob; ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { - use_obedit = obedit && dupli_ob->ob->data == obedit->data; - sob_callback(sctx, use_obedit, use_obedit ? obedit : dupli_ob->ob, dupli_ob->mat, data); + sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data); } free_object_duplilist(lb); } - use_obedit = obedit && obj->data == obedit->data; - sob_callback(sctx, use_obedit, use_obedit ? obedit : obj, obj->obmat, data); + sob_callback(sctx, use_object_edit_cage, obj, obj->obmat, data); } } } @@ -378,7 +392,7 @@ static bool raycastMesh( BVHTreeFromMesh *treedata = &sod->treedata; - /* The tree is owned by the DM and may have been freed since we last used. */ + /* The tree is owned by the Mesh and may have been freed since we last used. */ if (treedata->tree) { BLI_assert(treedata->cached); if (!bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) { @@ -502,14 +516,30 @@ static bool raycastEditMesh( SnapObjectData_EditMesh *sod = NULL; BVHTreeFromEditMesh *treedata = NULL; + Object *em_ob = em->ob; void **sod_p; - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + /* Use `em->ob` as the key in ghash since the editmesh is used + * to create bvhtree and is the same for each linked object. */ + if (BLI_ghash_ensure_p(sctx->cache.object_map, em_ob, &sod_p)) { sod = *sod_p; } else { sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); sod->sd.type = SNAP_EDIT_MESH; + min_max_from_bmesh(em->bm, sod->min, sod->max); + } + + { + float min[3], max[3]; + mul_v3_m4v3(min, obmat, sod->min); + mul_v3_m4v3(max, obmat, sod->max); + + if (!isect_ray_aabb_v3_simple( + ray_start, ray_dir, min, max, NULL, NULL)) + { + return retval; + } } if (sod->bvh_trees[2] == NULL) { @@ -517,7 +547,17 @@ static bool raycastEditMesh( } treedata = sod->bvh_trees[2]; + BVHCache *em_bvh_cache = ((Mesh *)em_ob->data)->runtime.bvh_cache; + + if (sctx->callbacks.edit_mesh.test_face_fn == NULL) { + /* The tree is owned by the Mesh and may have been freed since we last used! */ + if (!bvhcache_has_tree(em_bvh_cache, treedata->tree)) { + free_bvhtree_from_editmesh(treedata); + } + } + if (treedata->tree == NULL) { + BVHCache **bvh_cache = NULL; BLI_bitmap *elem_mask = NULL; int looptri_num_active = -1; @@ -527,7 +567,15 @@ static bool raycastEditMesh( em->bm, elem_mask, sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); } - bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, NULL); + else { + /* Only cache if bvhtree is created without a mask. + * This helps keep a standardized bvhtree in cache. */ + bvh_cache = &em_bvh_cache; + } + + bvhtree_from_editmesh_looptri_ex( + treedata, em, elem_mask, looptri_num_active, + 0.0f, 4, 6, bvh_cache); if (elem_mask) { MEM_freeN(elem_mask); @@ -669,7 +717,7 @@ static bool raycastObj( switch (ob->type) { case OB_MESH: - if (use_obedit) { + if (use_obedit && BKE_object_is_in_editmode(ob)) { BMEditMesh *em = BKE_editmesh_from_object(ob); retval = raycastEditMesh( sctx, @@ -718,7 +766,7 @@ struct RaycastObjUserData { bool ret; }; -static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data) +static void raycast_obj_cb(SnapObjectContext *sctx, bool use_obedit, Object *ob, float obmat[4][4], void *data) { struct RaycastObjUserData *dt = data; @@ -726,7 +774,7 @@ static void raycast_obj_cb(SnapObjectContext *sctx, bool is_obedit, Object *ob, sctx, dt->ray_start, dt->ray_dir, ob, obmat, dt->ob_index++, - is_obedit, dt->use_occlusion_test, + use_obedit, dt->use_occlusion_test, dt->ray_depth, dt->r_loc, dt->r_no, dt->r_index, dt->r_ob, dt->r_obmat, @@ -1118,6 +1166,13 @@ static short snap_mesh_polygon( }; SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob); + if (sod == NULL) { + /* The object is in edit mode, and the key used + * was the object referenced in BMEditMesh */ + BMEditMesh *em = BKE_editmesh_from_object(ob); + sod = BLI_ghash_lookup(sctx->cache.object_map, em->ob); + } + BLI_assert(sod != NULL); if (sod->type == SNAP_MESH) { @@ -1335,6 +1390,8 @@ static short snapArmature( dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); + use_obedit = use_obedit && BKE_object_is_in_editmode(ob); + if (use_obedit == false) { /* Test BoundBox */ BoundBox *bb = BKE_armature_boundbox_get(ob); @@ -1469,6 +1526,8 @@ static short snapCurve( dist_squared_to_projected_aabb_precalc( &neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval); + use_obedit = use_obedit && BKE_object_is_in_editmode(ob); + if (use_obedit == false) { /* Test BoundBox */ BoundBox *bb = BKE_curve_boundbox_get(ob); @@ -1792,7 +1851,7 @@ static short snapMesh( treedata = &sod->treedata; bvhtree = sod->bvhtree; - /* the tree is owned by the DM and may have been freed since we last used! */ + /* The tree is owned by the Mesh and may have been freed since we last used! */ if ((sod->has_looptris && treedata->tree && !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) || (sod->has_loose_edge && bvhtree[0] && !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[0])) || (sod->has_loose_vert && bvhtree[1] && !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[1]))) @@ -1982,21 +2041,56 @@ static short snapEditMesh( SnapObjectData_EditMesh *sod = NULL; BVHTreeFromEditMesh *treedata_vert = NULL, *treedata_edge = NULL; + Object *em_ob = em->ob; void **sod_p; - if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) { + /* Use `em->ob` as the key in ghash since the editmesh is used + * to create bvhtree and is the same for each linked object. */ + if (BLI_ghash_ensure_p(sctx->cache.object_map, em_ob, &sod_p)) { sod = *sod_p; } else { sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); sod->sd.type = SNAP_EDIT_MESH; + min_max_from_bmesh(em->bm, sod->min, sod->max); } + float dist_px_sq = SQUARE(*dist_px); + + { + float min[3], max[3]; + mul_v3_m4v3(min, obmat, sod->min); + mul_v3_m4v3(max, obmat, sod->max); + + /* In vertex and edges you need to get the pixel distance from ray to BoundBox, see: T46099, T46816 */ + struct DistProjectedAABBPrecalc data_precalc; + dist_squared_to_projected_aabb_precalc( + &data_precalc, snapdata->pmat, snapdata->win_size, snapdata->mval); + + bool dummy[3]; + float bb_dist_px_sq = dist_squared_to_projected_aabb( + &data_precalc, min, max, dummy); + + if (bb_dist_px_sq > dist_px_sq) { + return 0; + } + } + + BVHCache *em_bvh_cache = ((Mesh *)em_ob->data)->runtime.bvh_cache; + if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) { if (sod->bvh_trees[0] == NULL) { sod->bvh_trees[0] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees)); } treedata_vert = sod->bvh_trees[0]; + + if (sctx->callbacks.edit_mesh.test_vert_fn == NULL) { + /* The tree is owned by the Mesh and may have been freed since we last used! */ + if (!bvhcache_has_tree(em_bvh_cache, treedata_vert->tree)) { + free_bvhtree_from_editmesh(treedata_vert); + } + } + if (treedata_vert->tree == NULL) { BLI_bitmap *verts_mask = NULL; int verts_num_active = -1; @@ -2006,9 +2100,13 @@ static short snapEditMesh( BM_VERTS_OF_MESH, em->bm, verts_mask, (bool(*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_vert_fn, sctx->callbacks.edit_mesh.user_data); + + bvhtree_from_editmesh_verts_ex(treedata_vert, em, verts_mask, verts_num_active, 0.0f, 2, 6); + MEM_freeN(verts_mask); + } + else { + bvhtree_from_editmesh_verts(treedata_vert, em, 0.0f, 2, 6, &em_bvh_cache); } - bvhtree_from_editmesh_verts_ex(treedata_vert, em, verts_mask, verts_num_active, 0.0f, 2, 6); - MEM_SAFE_FREE(verts_mask); } } @@ -2017,6 +2115,14 @@ static short snapEditMesh( sod->bvh_trees[1] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees)); } treedata_edge = sod->bvh_trees[1]; + + if (sctx->callbacks.edit_mesh.test_edge_fn == NULL) { + /* The tree is owned by the Mesh and may have been freed since we last used! */ + if (!bvhcache_has_tree(em_bvh_cache, treedata_edge->tree)) { + free_bvhtree_from_editmesh(treedata_edge); + } + } + if (treedata_edge->tree == NULL) { BLI_bitmap *edges_mask = NULL; int edges_num_active = -1; @@ -2027,9 +2133,12 @@ static short snapEditMesh( (bool(*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn, sctx->callbacks.edit_mesh.user_data); + bvhtree_from_editmesh_edges_ex(treedata_edge, em, edges_mask, edges_num_active, 0.0f, 2, 6); + MEM_freeN(edges_mask); + } + else { + bvhtree_from_editmesh_edges(treedata_edge, em, 0.0f, 2, 6, &em_bvh_cache); } - bvhtree_from_editmesh_edges_ex(treedata_edge, em, edges_mask, edges_num_active, 0.0f, 2, 6); - MEM_SAFE_FREE(edges_mask); } } @@ -2043,7 +2152,7 @@ static short snapEditMesh( BVHTreeNearest nearest = { .index = -1, - .dist_sq = SQUARE(*dist_px), + .dist_sq = dist_px_sq, }; int last_index = nearest.index; short elem = SCE_SNAP_MODE_VERTEX; @@ -2119,7 +2228,7 @@ static short snapObject( switch (ob->type) { case OB_MESH: - if (use_obedit) { + if (use_obedit && BKE_object_is_in_editmode(ob)) { BMEditMesh *em = BKE_editmesh_from_object(ob); retval = snapEditMesh( sctx, snapdata, ob, em, obmat, -- cgit v1.2.3 From 17c3110ae5776bb4bfb11e240d4623ea9a80e073 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 23 Jul 2018 16:10:46 +0200 Subject: Fix large font drawing blurriness in a better way. GPU_LINEAR is there for shadow font blurring, the real issue was lack of rounding for the batch offset. --- source/blender/blenfont/intern/blf_font.c | 3 ++- source/blender/blenfont/intern/blf_glyph.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index ea81106e60f..f7a926275a9 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -133,7 +133,8 @@ void blf_batch_draw_begin(FontBLF *font) if (simple_shader) { /* Offset is applied to each glyph. */ - copy_v2_v2(g_batch.ofs, font->pos); + g_batch.ofs[0] = floorf(font->pos[0]); + g_batch.ofs[1] = floorf(font->pos[1]); } else { /* Offset is baked in modelview mat. */ diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 99be8539d24..f7f1e10a480 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -244,7 +244,7 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) gc->textures[gc->texture_current] = tex; GPU_texture_bind(tex, 0); GPU_texture_wrap_mode(tex, false); - GPU_texture_filters(tex, GPU_NEAREST, GPU_NEAREST); + GPU_texture_filters(tex, GPU_NEAREST, GPU_LINEAR); GPU_texture_unbind(tex); } @@ -427,8 +427,8 @@ static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) { rect->xmin = floorf(x + g->pos_x); rect->xmax = rect->xmin + (float)g->width; - rect->ymin = y + g->pos_y; - rect->ymax = y + g->pos_y - (float)g->height; + rect->ymin = floorf(y + g->pos_y); + rect->ymax = rect->ymin - (float)g->height; } void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) -- cgit v1.2.3 From bb98e83b99e63348e0396a5ffe5bb2a20ff1607a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 23 Jul 2018 17:38:41 +0200 Subject: Fix T55668: Volume Keyframe on Cut-ted Metastrip. We actually still had cases of Meta strip duplication resulting in non-unique strip names. Quiet surprising this went unoticed for so long. :( Fixed that bug, and think it was last one (at least, no other case of SEQ_DUPE_UNIQUE_NAME usage should be broken, I think...), and raised subversion and updated doversion to run uniquename check on strips on all previous fileversions. Note: will have to do that again when merging in 2.8... --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/BKE_sequencer.h | 2 +- source/blender/blenkernel/intern/sequencer.c | 1 + source/blender/blenloader/intern/versioning_250.c | 18 ------------------ source/blender/blenloader/intern/versioning_270.c | 20 ++++++++++++++++++++ .../blender/editors/space_sequencer/sequencer_edit.c | 5 +++-- 6 files changed, 26 insertions(+), 22 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index a3da6d5016e..16115203294 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 279 -#define BLENDER_SUBVERSION 5 +#define BLENDER_SUBVERSION 6 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h index 8574e81c4e6..c408597de32 100644 --- a/source/blender/blenkernel/BKE_sequencer.h +++ b/source/blender/blenkernel/BKE_sequencer.h @@ -392,7 +392,7 @@ typedef struct SeqLoadInfo { /* seq_dupli' flags */ -#define SEQ_DUPE_UNIQUE_NAME (1 << 0) +#define SEQ_DUPE_UNIQUE_NAME (1 << 0) /* WARNING: does NOT work when duplicating Meta strips! */ #define SEQ_DUPE_CONTEXT (1 << 1) #define SEQ_DUPE_ANIM (1 << 2) #define SEQ_DUPE_ALL (1 << 3) /* otherwise only selected are copied */ diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 14119998519..7e4069305f6 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -5517,6 +5517,7 @@ static Sequence *seq_dupli(const Scene *scene_src, Scene *scene_dst, Sequence *s if (scene_src == scene_dst) { if (dupe_flag & SEQ_DUPE_UNIQUE_NAME) { + /* TODO this is broken in case of Meta strips recursive duplication... Not trivial to fix. */ BKE_sequence_base_unique_name_recursive(&scene_dst->ed->seqbase, seqn); } diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index e15d0f50948..28720ef5145 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -633,20 +633,6 @@ static void do_version_constraints_radians_degrees_250(ListBase *lb) } } -/* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already */ -static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbasep) -{ - Sequence * seq = seqbasep->first; - - while (seq) { - BKE_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq); - if (seq->seqbase.first) { - do_versions_seq_unique_name_all_strips(sce, &seq->seqbase); - } - seq = seq->next; - } -} - static void do_version_bone_roll_256(Bone *bone) { Bone *child; @@ -1326,10 +1312,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) if (sce->r.mblur_samples == 0) sce->r.mblur_samples = sce->r.osa; - if (sce->ed && sce->ed->seqbase.first) { - do_versions_seq_unique_name_all_strips(sce, &sce->ed->seqbase); - } - sce = sce->id.next; } } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 20f2a747fb2..7b787725084 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -308,6 +308,18 @@ static char *replace_bbone_easing_rnapath(char *old_path) } } +/* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already. + * But in 2.79 another case generating non-unique names was discovered (see T55668, involving Meta strips)... */ +static void do_versions_seq_unique_name_all_strips(Scene *sce, ListBase *seqbasep) +{ + for (Sequence *seq = seqbasep->first; seq != NULL; seq = seq->next) { + BKE_sequence_base_unique_name_recursive(&sce->ed->seqbase, seq); + if (seq->seqbase.first != NULL) { + do_versions_seq_unique_name_all_strips(sce, &seq->seqbase); + } + } +} + static void do_version_bbone_easing_fcurve_fix(ID *UNUSED(id), FCurve *fcu, void *UNUSED(user_data)) { /* F-Curve's path (for bbone_in/out) */ @@ -1826,6 +1838,14 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + if (!MAIN_VERSION_ATLEAST(bmain, 279, 6)) { + for (Scene *sce = bmain->scene.first; sce != NULL; sce = sce->id.next) { + if (sce->ed != NULL && sce->ed->seqbase.first != NULL) { + do_versions_seq_unique_name_all_strips(sce, &sce->ed->seqbase); + } + } + } } void do_versions_after_linking_270(Main *bmain) diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 679fb71f76b..5b8f2ae7067 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -737,7 +737,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_ANIM); } if (seqn) { @@ -846,7 +846,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) if (!skip_dup) { /* Duplicate AFTER the first change */ - seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM); + seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_ANIM); } if (seqn) { @@ -2112,6 +2112,7 @@ static int sequencer_cut_exec(bContext *C, wmOperator *op) SEQP_BEGIN (ed, seq) { + BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq); if (seq->seq1 || seq->seq2 || seq->seq3) { BKE_sequence_calc(scene, seq); } -- cgit v1.2.3 From 87090abb95263eb2eb830face64777a0eb3e7957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 23 Jul 2018 17:40:34 +0200 Subject: Eevee: Remove Colored volumetric option. This option is not necessary as it uses as much memory as the mono-chromatic transmistance. --- source/blender/blenkernel/intern/scene.c | 1 - source/blender/blenloader/intern/versioning_280.c | 2 -- source/blender/makesdna/DNA_scene_types.h | 2 +- source/blender/makesrna/intern/rna_scene.c | 6 ------ 4 files changed, 1 insertion(+), 10 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 3650fa21c1c..0574eef1a0f 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -878,7 +878,6 @@ void BKE_scene_init(Scene *sce) sce->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | - SCE_EEVEE_VOLUMETRIC_COLORED | SCE_EEVEE_GTAO_BENT_NORMALS | SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION | diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 09a940436ef..6ac7c719952 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1200,7 +1200,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) scene->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | - SCE_EEVEE_VOLUMETRIC_COLORED | SCE_EEVEE_GTAO_BENT_NORMALS | SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION | @@ -1258,7 +1257,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) EEVEE_GET_BOOL(props, volumetric_enable, SCE_EEVEE_VOLUMETRIC_ENABLED); EEVEE_GET_BOOL(props, volumetric_lights, SCE_EEVEE_VOLUMETRIC_LIGHTS); EEVEE_GET_BOOL(props, volumetric_shadows, SCE_EEVEE_VOLUMETRIC_SHADOWS); - EEVEE_GET_BOOL(props, volumetric_colored_transmittance, SCE_EEVEE_VOLUMETRIC_COLORED); EEVEE_GET_BOOL(props, gtao_enable, SCE_EEVEE_GTAO_ENABLED); EEVEE_GET_BOOL(props, gtao_use_bent_normals, SCE_EEVEE_GTAO_BENT_NORMALS); EEVEE_GET_BOOL(props, gtao_bounce, SCE_EEVEE_GTAO_BOUNCE); diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 16c8d8875c7..a4235a07ed5 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2096,7 +2096,7 @@ enum { SCE_EEVEE_VOLUMETRIC_ENABLED = (1 << 0), SCE_EEVEE_VOLUMETRIC_LIGHTS = (1 << 1), SCE_EEVEE_VOLUMETRIC_SHADOWS = (1 << 2), - SCE_EEVEE_VOLUMETRIC_COLORED = (1 << 3), +// SCE_EEVEE_VOLUMETRIC_COLORED = (1 << 3), /* Unused */ SCE_EEVEE_GTAO_ENABLED = (1 << 4), SCE_EEVEE_GTAO_BENT_NORMALS = (1 << 5), SCE_EEVEE_GTAO_BOUNCE = (1 << 6), diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index b44a53fa90b..096a2d7b8dc 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -6017,12 +6017,6 @@ static void rna_def_scene_eevee(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Volumetric Shadow Samples", "Number of samples to compute volumetric shadowing"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - prop = RNA_def_property(srna, "use_volumetric_colored_transmittance", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_VOLUMETRIC_COLORED); - RNA_def_property_boolean_default(prop, 1); - RNA_def_property_ui_text(prop, "Colored Transmittance", "Enable wavelength dependent volumetric transmittance"); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - /* Ambient Occlusion */ prop = RNA_def_property(srna, "use_gtao", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SCE_EEVEE_GTAO_ENABLED); -- cgit v1.2.3 From 8876e3aae25ad0e74baf362413b0fd113aa5b638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 23 Jul 2018 17:44:16 +0200 Subject: Fix assert when loading file with multiple windows opened ... or when loading a file when having more windows opened than the file itself. --- source/blender/windowmanager/intern/wm_files.c | 4 ++++ source/blender/windowmanager/intern/wm_window.c | 4 +--- source/blender/windowmanager/wm_window.h | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index c191255cd21..02c24aac60e 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -279,6 +279,10 @@ static void wm_window_match_replace_by_file_wm( wm->initialized = 0; wm->winactive = NULL; + /* Clearing drawable of before deleting any context + * to avoid clearing the wrong wm. */ + wm_window_clear_drawable(oldwm); + /* only first wm in list has ghostwins */ for (wmWindow *win = wm->windows.first; win; win = win->next) { for (wmWindow *oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) { diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index c1006db34ef..4b26532742b 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -123,7 +123,6 @@ static struct WMInitStruct { /* ******** win open & close ************ */ static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate); -static void wm_window_clear_drawable(wmWindowManager *wm); /* XXX this one should correctly check for apple top header... * done for Cocoa : returns window contents (and not frame) max size*/ @@ -202,7 +201,6 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win) GHOST_DisposeWindow(g_system, win->ghostwin); win->ghostwin = NULL; win->gpuctx = NULL; - } } @@ -1103,7 +1101,7 @@ static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool acti immActivate(); } -static void wm_window_clear_drawable(wmWindowManager *wm) +void wm_window_clear_drawable(wmWindowManager *wm) { if (wm->windrawable) { BLF_batch_reset(); diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 385d61217ad..4fd5d66fb43 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -57,6 +57,7 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm); void wm_window_process_events (const bContext *C); void wm_window_process_events_nosleep(void); +void wm_window_clear_drawable(wmWindowManager *wm); void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win); void wm_window_reset_drawable(void); -- cgit v1.2.3 From 7d6776ba2da7dbac3d80ccef28becf311f93a745 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 23 Jul 2018 18:37:29 +0200 Subject: Fix missing header include in previous master merge. --- source/blender/blenloader/intern/versioning_280.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source') diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 79ae95e96e4..edeefe35567 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -70,6 +70,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_sequencer.h" #include "BKE_studiolight.h" #include "BKE_workspace.h" -- cgit v1.2.3 From a50e23ba791d3a3489c65321d85e567684e89b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 23 Jul 2018 18:56:24 +0200 Subject: Fix compilation issue after merge. --- source/blender/blenloader/intern/versioning_280.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index edeefe35567..3a586e49ab3 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1213,7 +1213,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) scene->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | - SCE_EEVEE_VOLUMETRIC_COLORED | SCE_EEVEE_GTAO_BENT_NORMALS | SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION | @@ -1271,7 +1270,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) EEVEE_GET_BOOL(props, volumetric_enable, SCE_EEVEE_VOLUMETRIC_ENABLED); EEVEE_GET_BOOL(props, volumetric_lights, SCE_EEVEE_VOLUMETRIC_LIGHTS); EEVEE_GET_BOOL(props, volumetric_shadows, SCE_EEVEE_VOLUMETRIC_SHADOWS); - EEVEE_GET_BOOL(props, volumetric_colored_transmittance, SCE_EEVEE_VOLUMETRIC_COLORED); EEVEE_GET_BOOL(props, gtao_enable, SCE_EEVEE_GTAO_ENABLED); EEVEE_GET_BOOL(props, gtao_use_bent_normals, SCE_EEVEE_GTAO_BENT_NORMALS); EEVEE_GET_BOOL(props, gtao_bounce, SCE_EEVEE_GTAO_BOUNCE); -- cgit v1.2.3 From f6eccd367cf7ef504ebeef332b62a86d928f5542 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jul 2018 18:40:04 +0200 Subject: Subsurf: Subdivide polygons to the same resolution Previously it was ptex faces which were subdividing to the same resolution. This was looking like more details for non-quad faces, but was also causing discontinuity in the edge where quad touches non-quad polygon. Now ptex faces which are coming from non-quad faces are subdivided at a half of resolution, matching old behavior and solving discontinuity problem. --- source/blender/blenkernel/BKE_subdiv.h | 20 -- source/blender/blenkernel/intern/subdiv.c | 19 -- source/blender/blenkernel/intern/subdiv_mesh.c | 398 +++++++++++++++++-------- 3 files changed, 268 insertions(+), 169 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h index a1792866255..003dc7a37d3 100644 --- a/source/blender/blenkernel/BKE_subdiv.h +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -94,26 +94,6 @@ typedef struct Subdiv { */ SubdivSettings settings; - /* Total number of ptex faces on subdivision level 0. - * - * Ptex face is what is internally used by OpenSubdiv for evaluator. It is - * a quad face, which corresponds to Blender's legacy Catmull Clark grids. - * - * Basically, here is a correspondence between polygons and ptex faces: - * - Triangle consists of 3 PTex faces. - * - Quad is a single PTex face. - * - N-gon is N PTex faces. - * - * This value is initialized in BKE_subdiv_new_from_FOO() and is read-only - * after this. - */ - int num_ptex_faces; - - /* Indexed by base face index, element indicates total number of ptex faces - * created for preceding base faces. - */ - int *face_ptex_offset; - /* Topology refiner includes all the glue logic to feed Blender side * topology to OpenSubdiv. It can be shared by both evaluator and GL mesh * drawer. diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c index 794da2d3477..0bf969b7de2 100644 --- a/source/blender/blenkernel/intern/subdiv.c +++ b/source/blender/blenkernel/intern/subdiv.c @@ -42,23 +42,6 @@ # include "opensubdiv_topology_refiner_capi.h" #endif -#ifdef WITH_OPENSUBDIV -static void update_subdiv_after_topology_change(Subdiv *subdiv) -{ - /* Count ptex faces. */ - subdiv->num_ptex_faces = subdiv->topology_refiner->getNumPtexFaces( - subdiv->topology_refiner); - /* Initialize offset of base faces in ptex indices. */ - MEM_SAFE_FREE(subdiv->face_ptex_offset); - subdiv->face_ptex_offset = MEM_malloc_arrayN(subdiv->num_ptex_faces, - sizeof(int), - "subdiv ptex offset"); - subdiv->topology_refiner->fillFacePtexIndexOffset( - subdiv->topology_refiner, - subdiv->face_ptex_offset); -} -#endif - Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings, struct OpenSubdiv_Converter *converter) { @@ -79,7 +62,6 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings, subdiv->settings = *settings; subdiv->topology_refiner = osd_topology_refiner; subdiv->evaluator = NULL; - update_subdiv_after_topology_change(subdiv); BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME); subdiv->stats = stats; return subdiv; @@ -113,7 +95,6 @@ void BKE_subdiv_free(Subdiv *subdiv) if (subdiv->topology_refiner != NULL) { openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner); } - MEM_SAFE_FREE(subdiv->face_ptex_offset); MEM_freeN(subdiv); #endif } diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 83f2069ea0f..eb47d9158d3 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -38,27 +38,40 @@ #include "BKE_mesh.h" -/* TODO(sergey): Somehow move this to subdiv code? */ -static int mpoly_ptex_faces_count_get(const MPoly *mp) +#include "MEM_guardedalloc.h" + +/* ============================================================================= + * General helpers. + */ + +/* Number of ptex faces for a given polygon. */ +BLI_INLINE int num_ptex_faces_per_poly_get(const MPoly *poly) { - if (mp->totloop == 4) { - return 1; - } - else { - return mp->totloop; - } + return (poly->totloop == 4) ? 1 : poly->totloop; } -static int num_edges_per_ptex_get(const int resolution) +BLI_INLINE int num_edges_per_ptex_face_get(const int resolution) { return 2 * (resolution - 1) * resolution; } -static int num_polys_per_ptex_get(const int resolution) +/* Number of subdivision polygons per ptex face. */ +BLI_INLINE int num_polys_per_ptex_get(const int resolution) { return (resolution - 1) * (resolution - 1); } +/* Subdivision resolution per given polygon's ptex faces. */ +BLI_INLINE int ptex_face_resolution_get(const MPoly *poly, int resolution) +{ + return (poly->totloop == 4) ? (resolution) + : ((resolution >> 1) + 1); +} + +/* ============================================================================= + * Mesh subdivision context. + */ + typedef struct SubdivMeshContext { const Mesh *coarse_mesh; Subdiv *subdiv; @@ -72,8 +85,127 @@ typedef struct SubdivMeshContext { /* UV layers interpolation. */ int num_uv_layers; MLoopUV *uv_layers[MAX_MTFACE]; + + /* Indexed by coarse polygon index, indicates offset in subdivided mesh + * vertices, edges and polygons arrays, where first element of the poly + * begins. + */ + int *subdiv_vertex_offset; + int *subdiv_edge_offset; + int *subdiv_polygon_offset; + /* Indexed by base face index, element indicates total number of ptex faces + * created for preceding base faces. + */ + int *face_ptex_offset; + + /* Counters of geometry in subdivided mesh, initialized as a part of + * offsets calculation. + */ + int num_subdiv_vertices; + int num_subdiv_edges; + int num_subdiv_loops; + int num_subdiv_polygons; } SubdivMeshContext; +static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx) +{ + Mesh *subdiv_mesh = ctx->subdiv_mesh; + ctx->num_uv_layers = + CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV); + for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) { + ctx->uv_layers[layer_index] = CustomData_get_layer_n( + &subdiv_mesh->ldata, CD_MLOOPUV, layer_index); + } +} + +static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx) +{ + Mesh *subdiv_mesh = ctx->subdiv_mesh; + /* Pointers to original indices layers. */ + ctx->vert_origindex = CustomData_get_layer( + &subdiv_mesh->vdata, CD_ORIGINDEX); + ctx->edge_origindex = CustomData_get_layer( + &subdiv_mesh->edata, CD_ORIGINDEX); + ctx->loop_origindex = CustomData_get_layer( + &subdiv_mesh->ldata, CD_ORIGINDEX); + ctx->poly_origindex = CustomData_get_layer( + &subdiv_mesh->pdata, CD_ORIGINDEX); + /* UV layers interpolation. */ + subdiv_mesh_ctx_cache_uv_layers(ctx); +} + +static void subdiv_mesh_ctx_init_offsets(SubdivMeshContext *ctx) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + /* Allocate memory. */ + ctx->subdiv_vertex_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_vertex_offset), + "vertex_offset"); + ctx->subdiv_edge_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_edge_offset), + "subdiv_edge_offset"); + ctx->subdiv_polygon_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_polygon_offset), + "subdiv_polygon_offset"); + ctx->face_ptex_offset = MEM_malloc_arrayN(coarse_mesh->totpoly, + sizeof(*ctx->face_ptex_offset), + "face_ptex_offset"); + /* Fill in offsets. */ + int vertex_offset = 0; + int edge_offset = 0; + int polygon_offset = 0; + int face_ptex_offset = 0; + for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int ptex_face_resolution = ptex_face_resolution_get( + coarse_poly, ctx->settings->resolution); + const int ptex_face_resolution2 = + ptex_face_resolution * ptex_face_resolution; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + ctx->subdiv_vertex_offset[poly_index] = vertex_offset; + ctx->subdiv_edge_offset[poly_index] = edge_offset; + ctx->subdiv_polygon_offset[poly_index] = polygon_offset; + ctx->face_ptex_offset[poly_index] = face_ptex_offset; + vertex_offset += num_ptex_faces_per_poly * ptex_face_resolution2; + edge_offset += num_ptex_faces_per_poly * + num_edges_per_ptex_face_get(ptex_face_resolution); + polygon_offset += + num_ptex_faces_per_poly * + num_polys_per_ptex_get(ptex_face_resolution); + face_ptex_offset += num_ptex_faces_per_poly; + } + ctx->num_subdiv_vertices = vertex_offset; + ctx->num_subdiv_edges = edge_offset; + ctx->num_subdiv_polygons = polygon_offset; + ctx->num_subdiv_loops = 4 * ctx->num_subdiv_polygons; +} + +static void subdiv_mesh_ctx_init(SubdivMeshContext *ctx) +{ + subdiv_mesh_ctx_init_offsets(ctx); +} + +static void subdiv_mesh_ctx_init_result(SubdivMeshContext *ctx) +{ + subdiv_mesh_ctx_cache_custom_data_layers(ctx); +} + +static void subdiv_mesh_ctx_free(SubdivMeshContext *ctx) +{ + MEM_freeN(ctx->subdiv_vertex_offset); + MEM_freeN(ctx->subdiv_edge_offset); + MEM_freeN(ctx->face_ptex_offset); +} + +/* ============================================================================= + * Loop custom data copy helpers. + */ + typedef struct LoopsOfPtex { /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */ const MLoop *first_loop; @@ -112,6 +244,10 @@ static void loops_of_ptex_get( } } +/* ============================================================================= + * Edge custom data copy helpers. + */ + typedef struct EdgesOfPtex { /* First edge of the ptex, starts at ptex (0, 0) and goes in u direction. */ const MEdge *first_edge; @@ -145,6 +281,10 @@ static void edges_of_ptex_get( } } +/* ============================================================================= + * Vertex custom data interpolation helpers. + */ + /* TODO(sergey): Somehow de-duplicate with loops storage, without too much * exception cases all over the code. */ @@ -285,6 +425,10 @@ static void vertex_interpolation_end( } } +/* ============================================================================= + * Loop custom data interpolation helpers. + */ + typedef struct LoopsForInterpolation { /* This field points to a loop data which is to be used for interpolation. * The idea is to avoid unnecessary allocations for regular faces, where @@ -413,6 +557,10 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) } } +/* ============================================================================= + * Vertex subdivision process. + */ + static void subdiv_copy_vertex_data( const SubdivMeshContext *ctx, MVert *subdiv_vertex, @@ -468,23 +616,26 @@ static void subdiv_evaluate_vertices(SubdivMeshContext *ctx, { Subdiv *subdiv = ctx->subdiv; const int resolution = ctx->settings->resolution; - const int resolution2 = resolution * resolution; - const float inv_resolution_1 = 1.0f / (float)(resolution - 1); + const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; /* Base/coarse mesh information. */ const Mesh *coarse_mesh = ctx->coarse_mesh; - const MPoly *coarse_polyoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_polyoly[poly_index]; - const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly); + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + const int ptex_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1); /* Hi-poly subdivided mesh. */ Mesh *subdiv_mesh = ctx->subdiv_mesh; MVert *subdiv_vertex = subdiv_mesh->mvert; - const int ptex_face_index = subdiv->face_ptex_offset[poly_index]; + MVert *subdiv_vert = &subdiv_vertex[start_vertex_index]; /* Actual evaluation. */ VerticesForInterpolation vertex_interpolation; vertex_interpolation_init(ctx, &vertex_interpolation, coarse_poly); - MVert *subdiv_vert = &subdiv_vertex[ptex_face_index * resolution2]; + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; for (int ptex_of_poly_index = 0; - ptex_of_poly_index < num_poly_ptex_faces; + ptex_of_poly_index < num_ptex_faces_per_poly; ptex_of_poly_index++) { vertex_interpolation_from_ptex(ctx, @@ -496,13 +647,13 @@ static void subdiv_evaluate_vertices(SubdivMeshContext *ctx, BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal( subdiv, current_ptex_face_index, - resolution, + ptex_resolution, subdiv_vert, offsetof(MVert, co), sizeof(MVert), subdiv_vert, offsetof(MVert, no), sizeof(MVert)); - for (int y = 0; y < resolution; y++) { - const float v = y * inv_resolution_1; - for (int x = 0; x < resolution; x++, subdiv_vert++) { - const float u = x * inv_resolution_1; + for (int y = 0; y < ptex_resolution; y++) { + const float v = y * inv_ptex_resolution_1; + for (int x = 0; x < ptex_resolution; x++, subdiv_vert++) { + const float u = x * inv_ptex_resolution_1; subdiv_copy_vertex_data(ctx, subdiv_vert, coarse_mesh, @@ -516,6 +667,10 @@ static void subdiv_evaluate_vertices(SubdivMeshContext *ctx, vertex_interpolation_end(&vertex_interpolation); } +/* ============================================================================= + * Edge subdivision process. + */ + static void subdiv_copy_edge_data( SubdivMeshContext *ctx, MEdge *subdiv_edge, @@ -590,22 +745,22 @@ static MEdge *subdiv_create_edges_column(SubdivMeshContext *ctx, static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index) { - Subdiv *subdiv = ctx->subdiv; - const int resolution = ctx->settings->resolution; - const int resolution2 = resolution * resolution; - const int ptex_face_index = subdiv->face_ptex_offset[poly_index]; - const int num_edges_per_ptex = num_edges_per_ptex_get(resolution); - const int start_edge_index = ptex_face_index * num_edges_per_ptex; + const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; + const int start_edge_index = ctx->subdiv_edge_offset[poly_index]; /* Base/coarse mesh information. */ const Mesh *coarse_mesh = ctx->coarse_mesh; - const MPoly *coarse_polyoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_polyoly[poly_index]; - const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly); + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + const int ptex_face_resolution = ptex_face_resolution_get( + coarse_poly, ctx->settings->resolution); + const int ptex_face_resolution2 = + ptex_face_resolution * ptex_face_resolution; /* Hi-poly subdivided mesh. */ Mesh *subdiv_mesh = ctx->subdiv_mesh; MEdge *subdiv_medge = subdiv_mesh->medge; MEdge *subdiv_edge = &subdiv_medge[start_edge_index]; - const int start_poly_vertex_index = ptex_face_index * resolution2; /* Consider a subdivision of base face at level 1: * * y @@ -619,22 +774,25 @@ static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index) * * This is illustrate which parts of geometry is created by code below. */ - for (int i = 0; i < num_poly_ptex_faces; i++) { + for (int ptex_of_poly_index = 0; + ptex_of_poly_index < num_ptex_faces_per_poly; + ptex_of_poly_index++) + { const int start_ptex_face_vertex_index = - start_poly_vertex_index + i * resolution2; + start_vertex_index + ptex_of_poly_index * ptex_face_resolution2; EdgesOfPtex edges_of_ptex; - edges_of_ptex_get(ctx, &edges_of_ptex, coarse_poly, i); + edges_of_ptex_get(ctx, &edges_of_ptex, coarse_poly, ptex_of_poly_index); /* Create bottom row of edges (0-1, 1-2). */ subdiv_edge = subdiv_create_edges_row( ctx, subdiv_edge, edges_of_ptex.first_edge, start_ptex_face_vertex_index, - resolution); + ptex_face_resolution); /* Create remaining edges. */ - for (int row = 0; row < resolution - 1; row++) { + for (int row = 0; row < ptex_face_resolution - 1; row++) { const int start_row_vertex_index = - start_ptex_face_vertex_index + row * resolution; + start_ptex_face_vertex_index + row * ptex_face_resolution; /* Create vertical columns. * * At first iteration it will be edges (0-3. 1-4, 2-5), then it @@ -646,7 +804,7 @@ static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index) edges_of_ptex.last_edge, edges_of_ptex.second_edge, start_row_vertex_index, - resolution); + ptex_face_resolution); /* Create horizontal edge row. * * At first iteration it will be edges (3-4, 4-5), then it will be @@ -655,14 +813,18 @@ static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index) subdiv_edge = subdiv_create_edges_row( ctx, subdiv_edge, - (row == resolution - 2) ? edges_of_ptex.third_edge - : NULL, - start_row_vertex_index + resolution, - resolution); + (row == ptex_face_resolution - 2) ? edges_of_ptex.third_edge + : NULL, + start_row_vertex_index + ptex_face_resolution, + ptex_face_resolution); } } } +/* ============================================================================= + * Loops creation/interpolation. + */ + static void subdiv_copy_loop_data( const SubdivMeshContext *ctx, MLoop *subdiv_loop, @@ -723,24 +885,25 @@ static void subdiv_eval_uv_layer(SubdivMeshContext *ctx, static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index) { - Subdiv *subdiv = ctx->subdiv; const int resolution = ctx->settings->resolution; - const int resolution2 = resolution * resolution; - const float inv_resolution_1 = 1.0f / (float)(resolution - 1); - const int ptex_face_index = subdiv->face_ptex_offset[poly_index]; - const int num_edges_per_ptex = num_edges_per_ptex_get(resolution); - const int start_edge_index = ptex_face_index * num_edges_per_ptex; - const int num_polys_per_ptex = num_polys_per_ptex_get(resolution); - const int start_poly_index = ptex_face_index * num_polys_per_ptex; - const int start_loop_index = 4 * start_poly_index; - const int start_vert_index = ptex_face_index * resolution2; - const float du = inv_resolution_1; - const float dv = inv_resolution_1; + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; + const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; + const int start_edge_index = ctx->subdiv_edge_offset[poly_index]; + const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; /* Base/coarse mesh information. */ const Mesh *coarse_mesh = ctx->coarse_mesh; - const MPoly *coarse_polyoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_polyoly[poly_index]; - const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly); + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + const int ptex_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int ptex_resolution2 = ptex_resolution * ptex_resolution; + const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1); + const int num_edges_per_ptex = num_edges_per_ptex_face_get(ptex_resolution); + const int start_loop_index = 4 * start_poly_index; + const float du = inv_ptex_resolution_1; + const float dv = inv_ptex_resolution_1; /* Hi-poly subdivided mesh. */ Mesh *subdiv_mesh = ctx->subdiv_mesh; MLoop *subdiv_loopoop = subdiv_mesh->mloop; @@ -748,7 +911,7 @@ static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index) LoopsForInterpolation loop_interpolation; loop_interpolation_init(ctx, &loop_interpolation, coarse_poly); for (int ptex_of_poly_index = 0; - ptex_of_poly_index < num_poly_ptex_faces; + ptex_of_poly_index < num_ptex_faces_per_poly; ptex_of_poly_index++) { loop_interpolation_from_ptex(ctx, @@ -757,24 +920,24 @@ static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index) ptex_of_poly_index); const int current_ptex_face_index = ptex_face_index + ptex_of_poly_index; - for (int y = 0; y < resolution - 1; y++) { - const float v = y * inv_resolution_1; - for (int x = 0; x < resolution - 1; x++, subdiv_loop += 4) { - const float u = x * inv_resolution_1; + for (int y = 0; y < ptex_resolution - 1; y++) { + const float v = y * inv_ptex_resolution_1; + for (int x = 0; x < ptex_resolution - 1; x++, subdiv_loop += 4) { + const float u = x * inv_ptex_resolution_1; /* Vertex indicies ordered counter-clockwise. */ - const int v0 = start_vert_index + - (ptex_of_poly_index * resolution2) + - (y * resolution + x); + const int v0 = start_vertex_index + + (ptex_of_poly_index * ptex_resolution2) + + (y * ptex_resolution + x); const int v1 = v0 + 1; - const int v2 = v0 + resolution + 1; - const int v3 = v0 + resolution; + const int v2 = v0 + ptex_resolution + 1; + const int v3 = v0 + ptex_resolution; /* Edge indicies ordered counter-clockwise. */ const int e0 = start_edge_index + (ptex_of_poly_index * num_edges_per_ptex) + - (y * (2 * resolution - 1) + x); - const int e1 = e0 + resolution; - const int e2 = e0 + (2 * resolution - 1); - const int e3 = e0 + resolution - 1; + (y * (2 * ptex_resolution - 1) + x); + const int e1 = e0 + ptex_resolution; + const int e2 = e0 + (2 * ptex_resolution - 1); + const int e3 = e0 + ptex_resolution - 1; /* Initialize 4 loops of corresponding hi-poly poly. */ /* TODO(sergey): For ptex boundaries we should use loops from * coarse mesh. @@ -808,13 +971,17 @@ static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index) subdiv_loop, current_ptex_face_index, u, v, - inv_resolution_1); + inv_ptex_resolution_1); } } } loop_interpolation_end(&loop_interpolation); } +/* ============================================================================= + * Polygons subdivision process. + */ + static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, MPoly *subdiv_poly, const MPoly *coarse_poly) @@ -833,24 +1000,25 @@ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, static void subdiv_create_polys(SubdivMeshContext *ctx, int poly_index) { - Subdiv *subdiv = ctx->subdiv; const int resolution = ctx->settings->resolution; - const int ptex_face_index = subdiv->face_ptex_offset[poly_index]; - const int num_polys_per_ptex = num_polys_per_ptex_get(resolution); - const int num_loops_per_ptex = 4 * num_polys_per_ptex; - const int start_poly_index = ptex_face_index * num_polys_per_ptex; - const int start_loop_index = 4 * start_poly_index; + const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; /* Base/coarse mesh information. */ const Mesh *coarse_mesh = ctx->coarse_mesh; - const MPoly *coarse_polyoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_polyoly[poly_index]; - const int num_poly_ptex_faces = mpoly_ptex_faces_count_get(coarse_poly); + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + const int ptex_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int num_polys_per_ptex = num_polys_per_ptex_get(ptex_resolution); + const int num_loops_per_ptex = 4 * num_polys_per_ptex; + const int start_loop_index = 4 * start_poly_index; /* Hi-poly subdivided mesh. */ Mesh *subdiv_mesh = ctx->subdiv_mesh; MPoly *subdiv_mpoly = subdiv_mesh->mpoly; MPoly *subdiv_mp = &subdiv_mpoly[start_poly_index]; for (int ptex_of_poly_index = 0; - ptex_of_poly_index < num_poly_ptex_faces; + ptex_of_poly_index < num_ptex_faces_per_poly; ptex_of_poly_index++) { for (int subdiv_poly_index = 0; @@ -866,6 +1034,10 @@ static void subdiv_create_polys(SubdivMeshContext *ctx, int poly_index) } } +/* ============================================================================= + * Subdivision process entry points. + */ + static void subdiv_eval_task( void *__restrict userdata, const int poly_index, @@ -880,33 +1052,6 @@ static void subdiv_eval_task( subdiv_create_polys(data, poly_index); } -static void cache_uv_layers(SubdivMeshContext *ctx) -{ - Mesh *subdiv_mesh = ctx->subdiv_mesh; - ctx->num_uv_layers = - CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV); - for (int layer_index = 0; layer_index < ctx->num_uv_layers; ++layer_index) { - ctx->uv_layers[layer_index] = CustomData_get_layer_n( - &subdiv_mesh->ldata, CD_MLOOPUV, layer_index); - } -} - -static void cache_custom_data_layers(SubdivMeshContext *ctx) -{ - Mesh *subdiv_mesh = ctx->subdiv_mesh; - /* Pointers to original indices layers. */ - ctx->vert_origindex = CustomData_get_layer( - &subdiv_mesh->vdata, CD_ORIGINDEX); - ctx->edge_origindex = CustomData_get_layer( - &subdiv_mesh->edata, CD_ORIGINDEX); - ctx->loop_origindex = CustomData_get_layer( - &subdiv_mesh->ldata, CD_ORIGINDEX); - ctx->poly_origindex = CustomData_get_layer( - &subdiv_mesh->pdata, CD_ORIGINDEX); - /* UV layers interpolation. */ - cache_uv_layers(ctx); -} - Mesh *BKE_subdiv_to_mesh( Subdiv *subdiv, const SubdivToMeshSettings *settings, @@ -917,29 +1062,20 @@ Mesh *BKE_subdiv_to_mesh( * is is refined for the new positions of coarse vertices. */ BKE_subdiv_eval_update_from_mesh(subdiv, coarse_mesh); - const int resolution = settings->resolution; - const int resolution2 = resolution * resolution; - const int num_result_verts = subdiv->num_ptex_faces * resolution2; - const int num_result_edges = - subdiv->num_ptex_faces * num_edges_per_ptex_get(resolution); - const int num_result_polys = - subdiv->num_ptex_faces * num_polys_per_ptex_get(resolution); - const int num_result_loops = 4 * num_result_polys; - /* Create mesh and its arrays. */ + SubdivMeshContext ctx = {0}; + ctx.coarse_mesh = coarse_mesh; + ctx.subdiv = subdiv; + ctx.settings = settings; + subdiv_mesh_ctx_init(&ctx); Mesh *result = BKE_mesh_new_nomain_from_template( coarse_mesh, - num_result_verts, - num_result_edges, + ctx.num_subdiv_vertices, + ctx.num_subdiv_edges, 0, - num_result_loops, - num_result_polys); - /* Evaluate subdivisions of base faces in threads. */ - SubdivMeshContext ctx; - ctx.coarse_mesh = coarse_mesh; - ctx.subdiv = subdiv; + ctx.num_subdiv_loops, + ctx.num_subdiv_polygons); ctx.subdiv_mesh = result; - ctx.settings = settings; - cache_custom_data_layers(&ctx); + subdiv_mesh_ctx_init_result(&ctx); /* Multi-threaded evaluation. */ ParallelRangeSettings parallel_range_settings; BLI_parallel_range_settings_defaults(¶llel_range_settings); @@ -947,6 +1083,8 @@ Mesh *BKE_subdiv_to_mesh( &ctx, subdiv_eval_task, ¶llel_range_settings); + subdiv_mesh_ctx_free(&ctx); + // BKE_mesh_validate(result, true, true); BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); return result; } -- cgit v1.2.3 From b466c09c305dfafbe3d15d6564c34f9f874ac0ad Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jul 2018 19:09:16 +0200 Subject: Subsurf: Fix wrong vertices index in vertex data interpolation --- source/blender/blenkernel/intern/subdiv_mesh.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index eb47d9158d3..ad2e094fa48 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -355,7 +355,7 @@ static void vertex_interpolation_init( int *indices = BLI_array_alloca(indices, coarse_poly->totloop); for (int i = 0; i < coarse_poly->totloop; ++i) { weights[i] = weight; - indices[i] = coarse_poly->loopstart + i; + indices[i] = coarse_mloop[coarse_poly->loopstart + i].v; } CustomData_interp(&coarse_mesh->vdata, &vertex_interpolation->vertex_data_storage, @@ -395,13 +395,15 @@ static void vertex_interpolation_from_ptex( * iteration. */ const float weights[2] = {0.5f, 0.5f}; + const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop; + const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop; const int first_indices[2] = { - coarse_mloop[loops_of_ptex.first_loop - coarse_mloop].v, - coarse_mloop[(loops_of_ptex.first_loop + 1 - coarse_mloop) % - coarse_poly->totloop].v}; - const int last_indices[2] = { - coarse_mloop[loops_of_ptex.last_loop - coarse_mloop].v, - coarse_mloop[loops_of_ptex.first_loop - coarse_mloop].v}; + coarse_mloop[first_loop_index].v, + coarse_mloop[coarse_poly->loopstart + + (first_loop_index - coarse_poly->loopstart + 1) % + coarse_poly->totloop].v}; + const int last_indices[2] = {coarse_mloop[first_loop_index].v, + coarse_mloop[last_loop_index].v}; CustomData_interp(vertex_data, &vertex_interpolation->vertex_data_storage, first_indices, -- cgit v1.2.3 From 4d978cc2e496eb0287b3b828ac105bb767da4bb4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 24 Jul 2018 13:54:25 +1000 Subject: Cleanup: changes from 2.8 --- source/blender/blenlib/intern/hash_mm3.c | 18 +++---- .../compositor/nodes/COM_CryptomatteNode.cpp | 6 +-- .../operations/COM_CryptomatteOperation.cpp | 2 +- .../composite/nodes/node_composite_cryptomatte.c | 58 +++++++++++----------- .../nodes/node_shader_bsdf_hair_principled.c | 2 +- 5 files changed, 43 insertions(+), 43 deletions(-) (limited to 'source') diff --git a/source/blender/blenlib/intern/hash_mm3.c b/source/blender/blenlib/intern/hash_mm3.c index 5ead9ceca63..105c1f46832 100644 --- a/source/blender/blenlib/intern/hash_mm3.c +++ b/source/blender/blenlib/intern/hash_mm3.c @@ -92,7 +92,7 @@ BLI_INLINE uint64_t fmix64(uint64_t k) uint32_t BLI_hash_mm3(const unsigned char *in, size_t len, uint32_t seed) { - const uint8_t *data = (const uint8_t*)in; + const uint8_t *data = (const uint8_t *)in; const int nblocks = len / 4; uint32_t h1 = seed; @@ -102,23 +102,23 @@ uint32_t BLI_hash_mm3(const unsigned char *in, size_t len, uint32_t seed) /* body */ - const uint32_t *blocks = (const uint32_t *)(data + nblocks*4); + const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4); for (int i = -nblocks; i; i++) { - uint32_t k1 = getblock32(blocks,i); + uint32_t k1 = getblock32(blocks, i); k1 *= c1; - k1 = ROTL32(k1,15); + k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; - h1 = ROTL32(h1,13); - h1 = h1*5+0xe6546b64; + h1 = ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; } /* tail */ - const uint8_t *tail = (const uint8_t*)(data + nblocks*4); + const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); uint32_t k1 = 0; @@ -132,10 +132,10 @@ uint32_t BLI_hash_mm3(const unsigned char *in, size_t len, uint32_t seed) case 1: k1 ^= tail[0]; k1 *= c1; - k1 = ROTL32(k1,15); + k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; - }; + } /* finalization */ diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp index bc115e66c20..5ed66fe45e7 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp @@ -62,7 +62,7 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter, const Compos bNode *node = this->getbNode(); NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage; - CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets()-1); + CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1); if (cryptoMatteSettings) { if (cryptoMatteSettings->matte_id) { /* Split the string by commas, ignoring white space. */ @@ -83,7 +83,7 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter, const Compos operation->addObjectIndex(atof(token.substr(1, token.length() - 2).c_str())); } else { - uint32_t hash = BLI_hash_mm3((const unsigned char*)token.c_str(), token.length(), 0); + uint32_t hash = BLI_hash_mm3((const unsigned char *)token.c_str(), token.length(), 0); operation->addObjectIndex(hash_to_float(hash)); } } @@ -93,7 +93,7 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter, const Compos converter.addOperation(operation); - for (int i = 0; i < getNumberOfInputSockets()-1; ++i) { + for (int i = 0; i < getNumberOfInputSockets() - 1; ++i) { converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i)); } diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp b/source/blender/compositor/operations/COM_CryptomatteOperation.cpp index 9dd36863d37..f3fa81075c6 100644 --- a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp +++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cpp @@ -63,7 +63,7 @@ void CryptomatteOperation::executePixel(float output[4], output[1] = ((float) ((m3hash << 8)) / (float) UINT32_MAX); output[2] = ((float) ((m3hash << 16)) / (float) UINT32_MAX); } - for(size_t i = 0; i < m_objectIndex.size(); i++) { + for (size_t i = 0; i < m_objectIndex.size(); i++) { if (m_objectIndex[i] == input[0]) { output[3] += input[1]; } diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c index 0231e4717b2..bf9ab4a5064 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c @@ -39,10 +39,10 @@ static inline float hash_to_float(uint32_t hash) { - uint32_t mantissa = hash & (( 1 << 23) - 1); + uint32_t mantissa = hash & ((1 << 23) - 1); uint32_t exponent = (hash >> 23) & ((1 << 8) - 1); - exponent = MAX2(exponent, (uint32_t) 1); - exponent = MIN2(exponent, (uint32_t) 254); + exponent = MAX2(exponent, (uint32_t)1); + exponent = MIN2(exponent, (uint32_t)254); exponent = exponent << 23; uint32_t sign = (hash >> 31); sign = sign << 31; @@ -54,7 +54,7 @@ static inline float hash_to_float(uint32_t hash) return f; } -static void cryptomatte_add(NodeCryptomatte* n, float f) +static void cryptomatte_add(NodeCryptomatte *n, float f) { /* Turn the number into a string. */ char number[32]; @@ -72,16 +72,16 @@ static void cryptomatte_add(NodeCryptomatte* n, float f) } /* Find the next seprator. */ - char* token_end = strchr(n->matte_id+start, ','); - if (token_end == NULL || token_end == n->matte_id+start) { - token_end = n->matte_id+end; + char *token_end = strchr(n->matte_id + start, ','); + if (token_end == NULL || token_end == n->matte_id + start) { + token_end = n->matte_id + end; } /* Be aware that token_len still contains any trailing white space. */ token_len = token_end - (n->matte_id + start); /* If this has a leading bracket, assume a raw floating point number and look for the closing bracket. */ if (n->matte_id[start] == '<') { - if (strncmp(n->matte_id+start, number, strlen(number)) == 0) { + if (strncmp(n->matte_id + start, number, strlen(number)) == 0) { /* This number is already there, so continue. */ return; } @@ -89,16 +89,16 @@ static void cryptomatte_add(NodeCryptomatte* n, float f) else { /* Remove trailing white space */ size_t name_len = token_len; - while (n->matte_id[start+name_len] == ' ' && name_len > 0) { + while (n->matte_id[start + name_len] == ' ' && name_len > 0) { name_len--; } /* Calculate the hash of the token and compare. */ - uint32_t hash = BLI_hash_mm3((const unsigned char*)(n->matte_id+start), name_len, 0); + uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0); if (f == hash_to_float(hash)) { return; } } - start += token_len+1; + start += token_len + 1; } } @@ -107,12 +107,12 @@ static void cryptomatte_add(NodeCryptomatte* n, float f) return; } - if(n->matte_id) { + if (n->matte_id) { BLI_dynstr_append(new_matte, n->matte_id); MEM_freeN(n->matte_id); } - if(BLI_dynstr_get_len(new_matte) > 0) { + if (BLI_dynstr_get_len(new_matte) > 0) { BLI_dynstr_append(new_matte, ","); } BLI_dynstr_append(new_matte, number); @@ -120,7 +120,7 @@ static void cryptomatte_add(NodeCryptomatte* n, float f) BLI_dynstr_free(new_matte); } -static void cryptomatte_remove(NodeCryptomatte*n, float f) +static void cryptomatte_remove(NodeCryptomatte *n, float f) { if (n->matte_id == NULL || strlen(n->matte_id) == 0) { /* Empty string, nothing to remove. */ @@ -150,9 +150,9 @@ static void cryptomatte_remove(NodeCryptomatte*n, float f) } /* Find the next seprator. */ - char* token_end = strchr(n->matte_id+start+1, ','); - if (token_end == NULL || token_end == n->matte_id+start) { - token_end = n->matte_id+end; + char *token_end = strchr(n->matte_id + start + 1, ','); + if (token_end == NULL || token_end == n->matte_id + start) { + token_end = n->matte_id + end; } /* Be aware that token_len still contains any trailing white space. */ token_len = token_end - (n->matte_id + start); @@ -162,7 +162,7 @@ static void cryptomatte_remove(NodeCryptomatte*n, float f) } /* If this has a leading bracket, assume a raw floating point number and look for the closing bracket. */ else if (n->matte_id[start] == '<') { - if (strncmp(n->matte_id+start, number, strlen(number)) == 0) { + if (strncmp(n->matte_id + start, number, strlen(number)) == 0) { /* This number is already there, so skip it. */ skip = true; } @@ -170,11 +170,11 @@ static void cryptomatte_remove(NodeCryptomatte*n, float f) else { /* Remove trailing white space */ size_t name_len = token_len; - while (n->matte_id[start+name_len] == ' ' && name_len > 0) { + while (n->matte_id[start + name_len] == ' ' && name_len > 0) { name_len--; } /* Calculate the hash of the token and compare. */ - uint32_t hash = BLI_hash_mm3((const unsigned char*)(n->matte_id+start), name_len, 0); + uint32_t hash = BLI_hash_mm3((const unsigned char *)(n->matte_id + start), name_len, 0); if (f == hash_to_float(hash)) { skip = true; } @@ -186,26 +186,26 @@ static void cryptomatte_remove(NodeCryptomatte*n, float f) else { BLI_dynstr_append(new_matte, ", "); } - BLI_dynstr_nappend(new_matte, n->matte_id+start, token_len); + BLI_dynstr_nappend(new_matte, n->matte_id + start, token_len); } - start += token_len+1; + start += token_len + 1; } - if(n->matte_id) { + if (n->matte_id) { MEM_freeN(n->matte_id); n->matte_id = NULL; } - if(BLI_dynstr_get_len(new_matte) > 0) { + if (BLI_dynstr_get_len(new_matte) > 0) { n->matte_id = BLI_dynstr_get_cstring(new_matte); } BLI_dynstr_free(new_matte); } static bNodeSocketTemplate outputs[] = { - { SOCK_RGBA, 0, N_("Image")}, - { SOCK_FLOAT, 0, N_("Matte")}, - { SOCK_RGBA, 0, N_("Pick")}, - { -1, 0, "" } + { SOCK_RGBA, 0, N_("Image")}, + { SOCK_FLOAT, 0, N_("Matte")}, + { SOCK_RGBA, 0, N_("Pick")}, + { -1, 0, "" } }; void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node) @@ -235,7 +235,7 @@ bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node) NodeCryptomatte *n = node->storage; char sockname[32]; n->num_inputs++; - BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs-1); + BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1); bNodeSocket *sock = nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, NULL, sockname); return sock; } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c index c5029852033..aeeb262a5a6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c @@ -40,7 +40,7 @@ static bNodeSocketTemplate sh_node_bsdf_hair_principled_in[] = { { SOCK_FLOAT, 1, N_("Radial Roughness"), 0.3f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("Coat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("IOR"), 1.55f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, - { SOCK_FLOAT, 1, N_("Offset"), 2.f*((float)M_PI)/180.f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE}, + { SOCK_FLOAT, 1, N_("Offset"), 2.0f * ((float)M_PI) / 180.f, 0.0f, 0.0f, 0.0f, -M_PI_2, M_PI_2, PROP_ANGLE}, { SOCK_FLOAT, 1, N_("Random Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("Random Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, { SOCK_FLOAT, 1, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, -- cgit v1.2.3 From ec640510a8c8ef5de8daea907da2351ef1988915 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 14 Jul 2018 17:01:02 +0300 Subject: Fix T55958: allow the user to select between spring and spring2. The old springs with damping 1.0 operate in a special way that is more similar to plastic deformation than a spring. Some users rely on that, so let the user choose which implementation to use. This also restores full backward compatibility with 2.79. Reviewers: sergof Differential Revision: https://developer.blender.org/D3544 --- source/blender/blenkernel/intern/rigidbody.c | 66 ++++++++++------ source/blender/makesdna/DNA_rigidbody_types.h | 11 ++- source/blender/makesrna/intern/rna_rigidbody.c | 102 ++++++++++++++++--------- 3 files changed, 118 insertions(+), 61 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 502b6a81c76..5d6695e6598 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -700,6 +700,35 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool /* --------------------- */ +static void rigidbody_constraint_init_spring( + RigidBodyCon *rbc, void (*set_spring)(rbConstraint*,int,int), + void (*set_stiffness)(rbConstraint*,int,float), void (*set_damping)(rbConstraint*,int,float) +) { + set_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X); + set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x); + set_damping(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x); + + set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y); + set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y); + set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y); + + set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z); + set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z); + set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z); + + set_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X); + set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x); + set_damping(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x); + + set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y); + set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y); + set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y); + + set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z); + set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z); + set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); +} + static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, void (*set_limits)(rbConstraint*,int,float,float)) { if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) @@ -824,35 +853,24 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b RB_constraint_set_limits_piston(rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper); break; case RBC_TYPE_6DOF_SPRING: - rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2); - - RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X); - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x); - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x); - - RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y); - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y); - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y); + if (rbc->spring_type == RBC_SPRING_TYPE2) { + rbc->physics_constraint = RB_constraint_new_6dof_spring2(loc, rot, rb1, rb2); - RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z); - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z); - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z); + rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring2, RB_constraint_set_stiffness_6dof_spring2, RB_constraint_set_damping_6dof_spring2); - RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X); - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x); - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x); + RB_constraint_set_equilibrium_6dof_spring2(rbc->physics_constraint); - RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y); - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y); - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y); + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring2); + } + else { + rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2); - RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z); - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z); - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); + rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring, RB_constraint_set_stiffness_6dof_spring, RB_constraint_set_damping_6dof_spring); - RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); + RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); - rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring); + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof); + } break; case RBC_TYPE_6DOF: rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); @@ -1071,6 +1089,8 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty rbc->flag |= RBC_FLAG_ENABLED; rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS; + rbc->spring_type = RBC_SPRING_TYPE2; + rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */ rbc->num_solver_iterations = 10; /* 10 is Bullet default */ diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h index 1cd3a22fbe0..19e49644816 100644 --- a/source/blender/makesdna/DNA_rigidbody_types.h +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -203,7 +203,8 @@ typedef struct RigidBodyCon { int flag; /* (eRigidBodyCon_Flag) */ float breaking_threshold; /* breaking impulse threshold */ - float pad; + char spring_type; /* spring implementation to use */ + char pad[3]; /* limits */ /* translation limits */ @@ -273,9 +274,15 @@ typedef enum eRigidBodyCon_Type { /* Simplified spring constraint with only once axis that's automatically placed between the connected bodies */ RBC_TYPE_SPRING, /* dirves bodies by applying linear and angular forces */ - RBC_TYPE_MOTOR + RBC_TYPE_MOTOR, } eRigidBodyCon_Type; +/* Spring implementation type for RigidBodyOb */ +typedef enum eRigidBodyCon_SpringType { + RBC_SPRING_TYPE1 = 0, /* btGeneric6DofSpringConstraint */ + RBC_SPRING_TYPE2, /* btGeneric6DofSpring2Constraint */ +} eRigidBodyCon_SpringType; + /* Flags for RigidBodyCon */ typedef enum eRigidBodyCon_Flag { /* constraint influences rigid body motion */ diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index e1e9bb30335..853b1d9978c 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -76,6 +76,12 @@ const EnumPropertyItem rna_enum_rigidbody_constraint_type_items[] = { {RBC_TYPE_MOTOR, "MOTOR", ICON_NONE, "Motor", "Drive rigid body around or along an axis"}, {0, NULL, 0, NULL, NULL}}; +/* bullet spring type */ +const EnumPropertyItem rna_enum_rigidbody_constraint_spring_type_items[] = { + {RBC_SPRING_TYPE1, "SPRING1", ICON_NONE, "Blender 2.7", "Spring implementation used in blender 2.7. Damping is capped at 1.0"}, + {RBC_SPRING_TYPE2, "SPRING2", ICON_NONE, "Blender 2.8", "New implementation available since 2.8"}, + {0, NULL, 0, NULL, NULL}}; + #ifndef RNA_RUNTIME /* mesh source for collision shape creation */ static const EnumPropertyItem rigidbody_mesh_source_items[] = { @@ -376,6 +382,14 @@ static void rna_RigidBodyCon_type_set(PointerRNA *ptr, int value) rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; } +static void rna_RigidBodyCon_spring_type_set(PointerRNA *ptr, int value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_type = value; + rbc->flag |= RBC_FLAG_NEEDS_VALIDATE; +} + static void rna_RigidBodyCon_enabled_set(PointerRNA *ptr, bool value) { RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; @@ -468,6 +482,22 @@ static void rna_RigidBodyCon_num_solver_iterations_set(PointerRNA *ptr, int valu #endif } +#ifdef WITH_BULLET +static void rna_RigidBodyCon_do_set_spring_stiffness(RigidBodyCon *rbc, float value, int flag, int axis) +{ + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & flag)) { + switch (rbc->spring_type) { + case RBC_SPRING_TYPE1: + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, axis, value); + break; + case RBC_SPRING_TYPE2: + RB_constraint_set_stiffness_6dof_spring2(rbc->physics_constraint, axis, value); + break; + } + } +} +#endif + static void rna_RigidBodyCon_spring_stiffness_x_set(PointerRNA *ptr, float value) { RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; @@ -475,9 +505,7 @@ static void rna_RigidBodyCon_spring_stiffness_x_set(PointerRNA *ptr, float value rbc->spring_stiffness_x = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_X)) { - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, value); - } + rna_RigidBodyCon_do_set_spring_stiffness(rbc, value, RBC_FLAG_USE_SPRING_X, RB_LIMIT_LIN_X); #endif } @@ -488,9 +516,7 @@ static void rna_RigidBodyCon_spring_stiffness_y_set(PointerRNA *ptr, float value rbc->spring_stiffness_y = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_Y)) { - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, value); - } + rna_RigidBodyCon_do_set_spring_stiffness(rbc, value, RBC_FLAG_USE_SPRING_Y, RB_LIMIT_LIN_Y); #endif } @@ -501,9 +527,7 @@ static void rna_RigidBodyCon_spring_stiffness_z_set(PointerRNA *ptr, float value rbc->spring_stiffness_z = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_Z)) { - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, value); - } + rna_RigidBodyCon_do_set_spring_stiffness(rbc, value, RBC_FLAG_USE_SPRING_Z, RB_LIMIT_LIN_Z); #endif } @@ -514,9 +538,7 @@ static void rna_RigidBodyCon_spring_stiffness_ang_x_set(PointerRNA *ptr, float v rbc->spring_stiffness_ang_x = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) { - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value); - } + rna_RigidBodyCon_do_set_spring_stiffness(rbc, value, RBC_FLAG_USE_SPRING_ANG_X, RB_LIMIT_ANG_X); #endif } @@ -527,9 +549,7 @@ static void rna_RigidBodyCon_spring_stiffness_ang_y_set(PointerRNA *ptr, float v rbc->spring_stiffness_ang_y = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) { - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value); - } + rna_RigidBodyCon_do_set_spring_stiffness(rbc, value, RBC_FLAG_USE_SPRING_ANG_Y, RB_LIMIT_ANG_Y); #endif } @@ -540,12 +560,26 @@ static void rna_RigidBodyCon_spring_stiffness_ang_z_set(PointerRNA *ptr, float v rbc->spring_stiffness_ang_z = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) { - RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value); - } + rna_RigidBodyCon_do_set_spring_stiffness(rbc, value, RBC_FLAG_USE_SPRING_ANG_Z, RB_LIMIT_ANG_Z); #endif } +#ifdef WITH_BULLET +static void rna_RigidBodyCon_do_set_spring_damping(RigidBodyCon *rbc, float value, int flag, int axis) +{ + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & flag)) { + switch (rbc->spring_type) { + case RBC_SPRING_TYPE1: + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, axis, value); + break; + case RBC_SPRING_TYPE2: + RB_constraint_set_damping_6dof_spring2(rbc->physics_constraint, axis, value); + break; + } + } +} +#endif + static void rna_RigidBodyCon_spring_damping_x_set(PointerRNA *ptr, float value) { RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; @@ -553,9 +587,7 @@ static void rna_RigidBodyCon_spring_damping_x_set(PointerRNA *ptr, float value) rbc->spring_damping_x = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_X)) { - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, value); - } + rna_RigidBodyCon_do_set_spring_damping(rbc, value, RBC_FLAG_USE_SPRING_X, RB_LIMIT_LIN_X); #endif } @@ -565,9 +597,7 @@ static void rna_RigidBodyCon_spring_damping_y_set(PointerRNA *ptr, float value) rbc->spring_damping_y = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_Y)) { - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, value); - } + rna_RigidBodyCon_do_set_spring_damping(rbc, value, RBC_FLAG_USE_SPRING_Y, RB_LIMIT_LIN_Y); #endif } @@ -577,9 +607,7 @@ static void rna_RigidBodyCon_spring_damping_z_set(PointerRNA *ptr, float value) rbc->spring_damping_z = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_Z)) { - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, value); - } + rna_RigidBodyCon_do_set_spring_damping(rbc, value, RBC_FLAG_USE_SPRING_Z, RB_LIMIT_LIN_Z); #endif } @@ -590,9 +618,7 @@ static void rna_RigidBodyCon_spring_damping_ang_x_set(PointerRNA *ptr, float val rbc->spring_damping_ang_x = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) { - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value); - } + rna_RigidBodyCon_do_set_spring_damping(rbc, value, RBC_FLAG_USE_SPRING_ANG_X, RB_LIMIT_ANG_X); #endif } @@ -602,9 +628,7 @@ static void rna_RigidBodyCon_spring_damping_ang_y_set(PointerRNA *ptr, float val rbc->spring_damping_ang_y = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) { - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value); - } + rna_RigidBodyCon_do_set_spring_damping(rbc, value, RBC_FLAG_USE_SPRING_ANG_Y, RB_LIMIT_ANG_Y); #endif } @@ -614,9 +638,7 @@ static void rna_RigidBodyCon_spring_damping_ang_z_set(PointerRNA *ptr, float val rbc->spring_damping_ang_z = value; #ifdef WITH_BULLET - if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) { - RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value); - } + rna_RigidBodyCon_do_set_spring_damping(rbc, value, RBC_FLAG_USE_SPRING_ANG_Z, RB_LIMIT_ANG_Z); #endif } @@ -1025,6 +1047,14 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "spring_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "spring_type"); + RNA_def_property_enum_items(prop, rna_enum_rigidbody_constraint_spring_type_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyCon_spring_type_set", NULL); + RNA_def_property_ui_text(prop, "Spring Type", "Which implementation of spring to use"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_ENABLED); RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_enabled_set"); -- cgit v1.2.3 From 1b415e4456ff4f6666c92efabeb88ead84227648 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 23 Jul 2018 16:38:25 +0200 Subject: Motion paths: default to bone head instead of tail location. This puts the motion path in the same location as the transform gizmo, which is less confusing especially if you have a custom bone shape where the tail is not visible. --- source/blender/blenkernel/intern/anim.c | 2 ++ source/blender/editors/armature/pose_edit.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index eed8943cd5b..a867accfe44 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -99,6 +99,8 @@ void animviz_settings_init(bAnimVizSettings *avs) avs->path_viewflag = (MOTIONPATH_VIEW_KFRAS | MOTIONPATH_VIEW_KFNOS); avs->path_step = 1; + + avs->path_bakeflag |= MOTIONPATH_BAKE_HEADS; } /* ------------------- */ diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index a9ba8c405ba..3ae578279ca 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -287,7 +287,8 @@ void POSE_OT_paths_calculate(wmOperatorType *ot) RNA_def_int(ot->srna, "end_frame", 250, MINAFRAME, MAXFRAME, "End", "Last frame to calculate bone paths on", MINFRAME, MAXFRAME / 2.0); - RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items, 0, + RNA_def_enum(ot->srna, "bake_location", rna_enum_motionpath_bake_location_items, + MOTIONPATH_BAKE_HEADS, "Bake Location", "Which point on the bones is used when calculating paths"); } -- cgit v1.2.3 From 9284c051d62833960ff836f2f48bf5a3b18b369c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 24 Jul 2018 11:08:58 +0200 Subject: Fix incorrect object visibility test in baking. --- source/blender/editors/object/object_bake_api.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 5210182510f..e8fabdabf17 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -49,6 +49,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" #include "BKE_material.h" @@ -357,17 +358,24 @@ static bool is_noncolor_pass(eScenePassType pass_type) } /* if all is good tag image and return true */ -static bool bake_object_check(Scene *scene, Object *ob, ReportList *reports) +static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *reports) { Image *image; + Base *base = BKE_view_layer_base_find(view_layer, ob); void *lock; int i; - if ((ob->lay & scene->lay) == 0) { - BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not on a scene layer", ob->id.name + 2); + if (base == NULL) { + BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not in view layer", ob->id.name + 2); return false; } + if (!(base->flag & BASE_ENABLED_RENDER)) { + BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not enabled for rendering", ob->id.name + 2); + return false; + } + + if (ob->type != OB_MESH) { BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2); return false; @@ -497,7 +505,7 @@ static bool bake_pass_filter_check(eScenePassType pass_type, const int pass_filt } /* before even getting in the bake function we check for some basic errors */ -static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase *selected_objects, +static bool bake_objects_check(Main *bmain, ViewLayer *view_layer, Object *ob, ListBase *selected_objects, ReportList *reports, const bool is_selected_to_active) { CollectionPointerLink *link; @@ -508,7 +516,7 @@ static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase * if (is_selected_to_active) { int tot_objects = 0; - if (!bake_object_check(scene, ob, reports)) + if (!bake_object_check(view_layer, ob, reports)) return false; for (link = selected_objects->first; link; link = link->next) { @@ -536,7 +544,7 @@ static bool bake_objects_check(Main *bmain, Scene *scene, Object *ob, ListBase * } for (link = selected_objects->first; link; link = link->next) { - if (!bake_object_check(scene, link->ptr.data, reports)) + if (!bake_object_check(view_layer, link->ptr.data, reports)) return false; } } @@ -1204,7 +1212,7 @@ static int bake_exec(bContext *C, wmOperator *op) goto finally; } - if (!bake_objects_check(bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) { + if (!bake_objects_check(bkr.main, bkr.view_layer, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active)) { goto finally; } @@ -1263,7 +1271,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa return; } - if (!bake_objects_check(bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) { + if (!bake_objects_check(bkr->main, bkr->view_layer, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) { bkr->result = OPERATOR_CANCELLED; return; } -- cgit v1.2.3 From c4803759a260853ca516dbdc9028bd0077056114 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 24 Jul 2018 11:21:32 +0200 Subject: Fix T55245: undo with multiple windows and view layers not working correct. --- source/blender/blenloader/intern/writefile.c | 14 +++++++------- source/blender/windowmanager/intern/wm_window.c | 7 ++++++- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 552f5420e8d..503f8b44ec3 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1147,7 +1147,7 @@ static void write_nodetree_nolib(WriteData *wd, bNodeTree *ntree) */ static void current_screen_compat( Main *mainvar, bool use_active_win, - bScreen **r_screen, Scene **r_scene, ViewLayer **r_render_layer) + bScreen **r_screen, Scene **r_scene, ViewLayer **r_view_layer) { wmWindowManager *wm; wmWindow *window = NULL; @@ -1177,7 +1177,7 @@ static void current_screen_compat( *r_screen = (window) ? BKE_workspace_active_screen_get(window->workspace_hook) : NULL; *r_scene = (window) ? window->scene : NULL; - *r_render_layer = (window && *r_scene) ? BKE_view_layer_find(*r_scene, window->view_layer_name) : NULL; + *r_view_layer = (window && *r_scene) ? BKE_view_layer_find(*r_scene, window->view_layer_name) : NULL; } typedef struct RenderInfo { @@ -1193,11 +1193,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar) { bScreen *curscreen; Scene *sce, *curscene = NULL; - ViewLayer *render_layer; + ViewLayer *view_layer; RenderInfo data; /* XXX in future, handle multiple windows with multiple screens? */ - current_screen_compat(mainvar, false, &curscreen, &curscene, &render_layer); + current_screen_compat(mainvar, false, &curscreen, &curscene, &view_layer); for (sce = mainvar->scene.first; sce; sce = sce->id.next) { if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) { @@ -3686,7 +3686,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) FileGlobal fg; bScreen *screen; Scene *scene; - ViewLayer *render_layer; + ViewLayer *view_layer; char subvstr[8]; /* prevent mem checkers from complaining */ @@ -3695,12 +3695,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) memset(fg.build_hash, 0, sizeof(fg.build_hash)); fg.pad1 = NULL; - current_screen_compat(mainvar, is_undo, &screen, &scene, &render_layer); + current_screen_compat(mainvar, is_undo, &screen, &scene, &view_layer); /* XXX still remap G */ fg.curscreen = screen; fg.curscene = scene; - fg.cur_view_layer = render_layer; + fg.cur_view_layer = view_layer; /* prevent to save this, is not good convention, and feature with concerns... */ fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 4b26532742b..dd4013efdf2 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -2167,7 +2167,12 @@ ViewLayer *WM_window_get_active_view_layer(const wmWindow *win) return view_layer; } - return BKE_view_layer_default_view(scene); + view_layer = BKE_view_layer_default_view(scene); + if (view_layer) { + WM_window_set_active_view_layer((wmWindow*)win, view_layer); + } + + return view_layer; } void WM_window_set_active_view_layer(wmWindow *win, ViewLayer *view_layer) -- cgit v1.2.3 From 882ccd924ba9febaec2db53831d95bc4a6c45ef3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 24 Jul 2018 11:37:27 +0200 Subject: Fix T55721: crashes with collections panel in object properties. --- source/blender/editors/object/object_group.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'source') diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 53cabe3759e..72c5fde2955 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -411,6 +411,9 @@ static int collection_add_exec(bContext *C, wmOperator *UNUSED(op)) id_fake_user_set(&collection->id); BKE_collection_object_add(bmain, collection, ob); + DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -460,6 +463,9 @@ static int collection_link_exec(bContext *C, wmOperator *op) BKE_collection_object_add(bmain, collection, ob); + DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -500,6 +506,9 @@ static int collection_remove_exec(bContext *C, wmOperator *UNUSED(op)) BKE_collection_object_remove(bmain, collection, ob, false); + DEG_id_tag_update(&collection->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); return OPERATOR_FINISHED; @@ -531,6 +540,8 @@ static int collection_unlink_exec(bContext *C, wmOperator *UNUSED(op)) BKE_libblock_delete(bmain, collection); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); return OPERATOR_FINISHED; -- cgit v1.2.3 From 293c15ec0cc3878bced1b52e274c078810ba2d8a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 24 Jul 2018 12:02:24 +0200 Subject: Fix T56081: crash with make static override and linked collection. --- source/blender/editors/object/object_relations.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source') diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 2c3ff8b6afe..52d9c43ea65 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2329,6 +2329,7 @@ static int make_override_static_exec(bContext *C, wmOperator *op) if (new_ob != NULL && new_ob->id.override_static != NULL) { if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) { BKE_collection_object_add_from(bmain, scene, obcollection, new_ob); + base = BKE_view_layer_base_find(view_layer, new_ob); DEG_id_tag_update_ex(bmain, &new_ob->id, DEG_TAG_TRANSFORM | DEG_TAG_BASE_FLAGS_UPDATE); } /* parent to 'collection' empty */ -- cgit v1.2.3 From 7f7e51161f65c371d0f0c6c39bd32cbea45694cd Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 24 Jul 2018 12:43:21 +0200 Subject: Fix T56079: crash with startup.blend saved in sculpt/paint modes. This reverts commit 81a93df6d22c2f148667b9a6e8308e083a4cec39, it is not safe to handle initialization for startup.blend differently. Instead fix the root issue of the preview icon data structures not being initialized in time. --- source/blender/editors/include/UI_interface_icons.h | 2 +- source/blender/editors/interface/interface_icons.c | 3 +-- source/blender/editors/interface/resources.c | 2 +- source/blender/windowmanager/intern/wm_files.c | 8 +------- source/blender/windowmanager/intern/wm_init_exit.c | 13 ++++++------- 5 files changed, 10 insertions(+), 18 deletions(-) (limited to 'source') diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 651081c46bb..a34c4938b86 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -59,7 +59,7 @@ typedef struct IconFile { /* * Resizable Icons for Blender */ -void UI_icons_init(int first_dyn_id); +void UI_icons_init(void); int UI_icon_get_width(int icon_id); int UI_icon_get_height(int icon_id); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 22b82898288..7255640bedc 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -934,9 +934,8 @@ int UI_icon_get_height(int icon_id) return 0; } -void UI_icons_init(int first_dyn_id) +void UI_icons_init() { - BKE_icons_init(first_dyn_id); #ifndef WITH_HEADLESS init_iconfile_list(&iconfilelist); init_internal_icons(); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 47d664eaeb2..3cb8a277e9a 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -83,7 +83,7 @@ static struct bThemeState g_theme_state = { void ui_resources_init(void) { - UI_icons_init(BIFICONID_LAST); + UI_icons_init(); } void ui_resources_free(void) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 02c24aac60e..042bd8823c4 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -492,13 +492,7 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo Main *bmain = CTX_data_main(C); DEG_on_visible_update(bmain, true); - - if (!is_startup_file) { - /* When starting up, the UI hasn't been fully initialised yet, and - * this call can trigger icon updates, causing a segfault due to a - * not-yet-initialised ghash for the icons. */ - wm_event_do_depsgraph(C); - } + wm_event_do_depsgraph(C); ED_editors_init(C); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index c51d4c5534a..4b0d751a7ce 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -115,6 +115,7 @@ #include "ED_undo.h" #include "UI_interface.h" +#include "UI_resources.h" #include "BLF_api.h" #include "BLT_lang.h" @@ -237,6 +238,11 @@ void WM_init(bContext *C, int argc, const char **argv) BLF_init(); BLT_lang_init(); + /* Init icons before reading .blend files for preview icons, which can + * get triggered by the depsgraph. This is also done in background mode + * for scripts that do background processing with preview icons. */ + BKE_icons_init(BIFICONID_LAST); + /* reports cant be initialized before the wm, * but keep before file reading, since that may report errors */ wm_init_reports(C); @@ -259,13 +265,6 @@ void WM_init(bContext *C, int argc, const char **argv) UI_init(); BKE_studiolight_init(); } - else { - /* Note: Currently only inits icons, which we now want in background mode too - * (scripts could use those in background processing...). - * In case we do more later, we may need to pass a 'background' flag. - * Called from 'UI_init' above */ - BKE_icons_init(1); - } ED_spacemacros_init(); -- cgit v1.2.3 From c924f6f53f13fb55f76b878dbf5d69d60f9d64c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 24 Jul 2018 16:50:31 +0200 Subject: Workbench: Fix missing geometry on Iris 640/630 GPUs For some reason 32c5972653041a3423122b5a5ae791ef536b87ed broke display of solid meshes in workbench. After some investigation, it seems that the vertex coordinate output is degenerated even if the input is correct and the matrix too. Removing dead code seems to fix the problem. So maybe the GLSL preprocessor is not doing what it should? --- source/blender/draw/engines/workbench/workbench_deferred.c | 7 +++++-- source/blender/draw/engines/workbench/workbench_forward.c | 13 +++++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) (limited to 'source') diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index 4e90a08a543..23fbbe56c16 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -142,9 +142,12 @@ static char *workbench_build_prepass_frag(void) return str; } -static char *workbench_build_prepass_vert(void) +static char *workbench_build_prepass_vert(bool is_hair) { char *str = NULL; + if (!is_hair) { + return BLI_strdup(datatoc_workbench_prepass_vert_glsl); + } DynStr *ds = BLI_dynstr_new(); @@ -176,7 +179,7 @@ static void ensure_deferred_shaders(WORKBENCH_PrivateData *wpd, int index, bool if (e_data.prepass_sh_cache[index] == NULL) { char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); char *composite_frag = workbench_build_composite_frag(wpd); - char *prepass_vert = workbench_build_prepass_vert(); + char *prepass_vert = workbench_build_prepass_vert(is_hair); char *prepass_frag = workbench_build_prepass_frag(); e_data.prepass_sh_cache[index] = DRW_shader_create( prepass_vert, NULL, diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 825b80ace52..c81ecc492db 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -80,9 +80,12 @@ extern char datatoc_workbench_common_lib_glsl[]; extern char datatoc_workbench_world_light_lib_glsl[]; /* static functions */ -static char *workbench_build_forward_vert(void) +static char *workbench_build_forward_vert(bool is_hair) { char *str = NULL; + if (!is_hair) { + return BLI_strdup(datatoc_workbench_prepass_vert_glsl); + } DynStr *ds = BLI_dynstr_new(); @@ -206,7 +209,7 @@ static void ensure_forward_shaders(WORKBENCH_PrivateData *wpd, int index, bool u if (e_data.transparent_accum_sh_cache[index] == NULL) { char *defines = workbench_material_build_defines(wpd, use_textures, is_hair); - char *transparent_accum_vert = workbench_build_forward_vert(); + char *transparent_accum_vert = workbench_build_forward_vert(is_hair); char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag(); e_data.transparent_accum_sh_cache[index] = DRW_shader_create( transparent_accum_vert, NULL, @@ -267,7 +270,8 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) char *defines = workbench_material_build_defines(wpd, false, false); char *defines_texture = workbench_material_build_defines(wpd, true, false); char *defines_hair = workbench_material_build_defines(wpd, false, true); - char *forward_vert = workbench_build_forward_vert(); + char *forward_vert = workbench_build_forward_vert(false); + char *forward_hair_vert = workbench_build_forward_vert(true); e_data.object_outline_sh = DRW_shader_create( forward_vert, NULL, datatoc_workbench_forward_depth_frag_glsl, defines); @@ -275,12 +279,13 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) forward_vert, NULL, datatoc_workbench_forward_depth_frag_glsl, defines_texture); e_data.object_outline_hair_sh = DRW_shader_create( - forward_vert, NULL, + forward_hair_vert, NULL, datatoc_workbench_forward_depth_frag_glsl, defines_hair); e_data.checker_depth_sh = DRW_shader_create_fullscreen( datatoc_workbench_checkerboard_depth_frag_glsl, NULL); + MEM_freeN(forward_hair_vert); MEM_freeN(forward_vert); MEM_freeN(defines); MEM_freeN(defines_texture); -- cgit v1.2.3 From cfaea24117f2ef3f1e2ce9bc0ebd620c27bfeba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 24 Jul 2018 17:57:24 +0200 Subject: Fix T55754: DOF with new Camera is not working Was due to non initialized gpu_dof.ratio --- source/blender/blenkernel/intern/camera.c | 3 +++ source/blender/makesrna/intern/rna_scene.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'source') diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 4203e0455f8..87b65601534 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -76,6 +76,9 @@ void BKE_camera_init(Camera *cam) cam->flag |= CAM_SHOWPASSEPARTOUT; cam->passepartalpha = 0.5f; + cam->gpu_dof.fstop = 128.0f; + cam->gpu_dof.ratio = 1.0f; + /* stereoscopy 3d */ cam->stereo.interocular_distance = 0.065f; cam->stereo.convergence_distance = 30.f * 0.065f; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 096a2d7b8dc..b666b15015a 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4092,6 +4092,7 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna) prop = RNA_def_property(srna, "fstop", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(prop, "F-stop", "F-stop for dof effect"); + RNA_def_property_float_default(prop, 128.0f); RNA_def_property_range(prop, 0.0f, FLT_MAX); RNA_def_property_ui_range(prop, 0.1f, 128.0f, 10, 1); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update"); @@ -4110,6 +4111,7 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna) prop = RNA_def_property(srna, "ratio", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(prop, "Ratio", "Distortion to simulate anamorphic lens bokeh"); + RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.0000001f, FLT_MAX); RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); -- cgit v1.2.3 From a76198cb238bef5c08e83b7777c977daa7316c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 24 Jul 2018 17:59:46 +0200 Subject: RNA: Remove Unused dof.is_hq_supported and dof.use_high_quality It's not necessary anymore since we assume it's always high quality. --- source/blender/makesrna/intern/rna_scene.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index b666b15015a..764e55e9e30 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2024,11 +2024,6 @@ static void rna_Stereo3dFormat_update(Main *bmain, Scene *UNUSED(scene), Pointer } } -static bool rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr)) -{ - return true; -} - static ViewLayer *rna_ViewLayer_new( ID *id, Scene *UNUSED(sce), Main *bmain, const char *name) { @@ -4115,18 +4110,6 @@ static void rna_def_gpu_dof_fx(BlenderRNA *brna) RNA_def_property_range(prop, 0.0000001f, FLT_MAX); RNA_def_property_ui_range(prop, 1.0f, 2.0f, 0.1, 3); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - - prop = RNA_def_property(srna, "use_high_quality", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "high_quality", 1); - RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPUDOFSettings_update"); - - /* NOTE: high quality is always supported */ - prop = RNA_def_property(srna, "is_hq_supported", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_gpu_is_hq_supported_get", NULL); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "High Quality", "Use high quality depth of field"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); } static void rna_def_gpu_ssao_fx(BlenderRNA *brna) -- cgit v1.2.3 From decb724572c4700d2ed2b9fb9447a17c2b5b1626 Mon Sep 17 00:00:00 2001 From: Germano Date: Tue, 24 Jul 2018 19:13:28 -0300 Subject: Fix T55798: Crash when snapping objects with data recalculated by modifiers. Although the default behavior is for these objects to be ignored during the snap operation, this should not crash. --- .../editors/transform/transform_snap_object.c | 38 ++++++++++++++-------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index b826e72acaf..dd4fc5025d9 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -172,6 +172,26 @@ static void min_max_from_bmesh( } } +static SnapObjectData_Mesh *snap_object_data_mesh_create(SnapObjectContext *sctx) +{ + SnapObjectData_Mesh *sod = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_MESH; + /* start assuming that it has each of these element types */ + sod->has_looptris = true; + sod->has_loose_edge = true; + sod->has_loose_vert = true; + + return sod; +} + +static SnapObjectData_EditMesh *snap_object_data_editmesh_create(SnapObjectContext *sctx, BMesh *bm) +{ + SnapObjectData_EditMesh *sod = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); + sod->sd.type = SNAP_EDIT_MESH; + min_max_from_bmesh(bm, sod->min, sod->max); + + return sod; +} /** * Walks through all objects in the scene to create the list of objets to snap. @@ -386,8 +406,7 @@ static bool raycastMesh( sod = *sod_p; } else { - sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); - sod->sd.type = SNAP_MESH; + sod = *sod_p = snap_object_data_mesh_create(sctx); } BVHTreeFromMesh *treedata = &sod->treedata; @@ -525,9 +544,7 @@ static bool raycastEditMesh( sod = *sod_p; } else { - sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); - sod->sd.type = SNAP_EDIT_MESH; - min_max_from_bmesh(em->bm, sod->min, sod->max); + sod = *sod_p = snap_object_data_editmesh_create(sctx, em->bm); } { @@ -1838,12 +1855,7 @@ static short snapMesh( sod = *sod_p; } else { - sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); - sod->sd.type = SNAP_MESH; - /* start assuming that it has each of these element types */ - sod->has_looptris = true; - sod->has_loose_edge = true; - sod->has_loose_vert = true; + sod = *sod_p = snap_object_data_mesh_create(sctx); } BVHTreeFromMesh *treedata, dummy_treedata; @@ -2050,9 +2062,7 @@ static short snapEditMesh( sod = *sod_p; } else { - sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod)); - sod->sd.type = SNAP_EDIT_MESH; - min_max_from_bmesh(em->bm, sod->min, sod->max); + sod = *sod_p = snap_object_data_mesh_create(sctx, em->bm); } float dist_px_sq = SQUARE(*dist_px); -- cgit v1.2.3 From 4f85982c6f6621c7d64a573e1d4558de4e824a00 Mon Sep 17 00:00:00 2001 From: Germano Date: Tue, 24 Jul 2018 19:34:49 -0300 Subject: Fix base->flag and base->flag_legacy: The flags of the Transform operator are being added to the bases of the not evaluated view_layer. But I'm not sure if the flags `BA_WAS_SEL`,` BASE_SELECTED` and `BA_SNAP_FIX_DEPS_FIASCO`(lol XD) should be added to the bases of the not evaluated `view_layer`. This needs to be discussed. --- source/blender/editors/transform/transform_snap_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index dd4fc5025d9..95ce26beed1 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -206,7 +206,7 @@ static void iter_snap_objects( IterSnapObjsCallback sob_callback, void *data) { - ViewLayer *view_layer = DEG_get_evaluated_view_layer(sctx->depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(sctx->depsgraph); const eSnapSelect snap_select = params->snap_select; const bool use_object_edit_cage = params->use_object_edit_cage; -- cgit v1.2.3 From fdd4b03f33da4f046faa72b77dc0e77289afda0b Mon Sep 17 00:00:00 2001 From: Germano Date: Tue, 24 Jul 2018 19:45:03 -0300 Subject: Correction on the last commit. --- source/blender/editors/transform/transform_snap_object.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 95ce26beed1..7116923e678 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -216,17 +216,17 @@ static void iter_snap_objects( !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) || (snap_select == SNAP_NOT_ACTIVE && base == base_act))) { - Object *obj = base->object; - if (obj->transflag & OB_DUPLI) { + Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object); + if (obj_eval->transflag & OB_DUPLI) { DupliObject *dupli_ob; - ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj); + ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval); for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) { sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data); } free_object_duplilist(lb); } - sob_callback(sctx, use_object_edit_cage, obj, obj->obmat, data); + sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data); } } } -- cgit v1.2.3 From bd608d9aff84804d8912f4e652f7d7bf9dccb5d1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 25 Jul 2018 09:23:07 +1000 Subject: Fix mistake in fix for T55798 --- source/blender/editors/transform/transform_snap_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 7116923e678..4ac4bdfb34d 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -2062,7 +2062,7 @@ static short snapEditMesh( sod = *sod_p; } else { - sod = *sod_p = snap_object_data_mesh_create(sctx, em->bm); + sod = *sod_p = snap_object_data_editmesh_create(sctx, em->bm); } float dist_px_sq = SQUARE(*dist_px); -- cgit v1.2.3 From d8514482fe6b750070270ac886d49d06d28a9a9b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 25 Jul 2018 11:00:03 +1000 Subject: WM: keymap utility to set enum from a key range --- source/blender/windowmanager/WM_keymap.h | 4 ++++ source/blender/windowmanager/intern/wm_keymap.c | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'source') diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 547028c88f9..2e84140707d 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -70,6 +70,10 @@ wmKeyMapItem *WM_keymap_add_panel(struct wmKeyMap *keymap, const char *idname, i wmKeyMapItem *WM_keymap_add_tool(struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); +void WM_keymap_add_context_enum_set_items( + wmKeyMap *keymap, const struct EnumPropertyItem *items, const char *data_path, + int type_start, int val, int modifier, int keymodifier); + bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi); int WM_keymap_item_to_string(wmKeyMapItem *kmi, const bool compact, char *result, const int result_len); diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index a95ccf36fdb..6815ff4413a 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -526,6 +526,25 @@ wmKeyMapItem *WM_keymap_add_tool(wmKeyMap *keymap, const char *idname, int type, return kmi; } +/** Useful for mapping numbers to an enum. */ +void WM_keymap_add_context_enum_set_items( + wmKeyMap *keymap, const EnumPropertyItem *items, const char *data_path, + int type_start, int val, int modifier, int keymodifier) +{ + for (int i = 0, type_offset = 0; items[i].identifier; i++) { + if (items[i].identifier[0] == '\0') { + continue; + } + wmKeyMapItem *kmi = WM_keymap_add_item( + keymap, "WM_OT_context_set_enum", + type_start + type_offset, val, modifier, keymodifier); + RNA_string_set(kmi->ptr, "data_path", data_path); + RNA_string_set(kmi->ptr, "value", items[i].identifier); + type_offset += 1; + } +} + + bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi) { if (BLI_findindex(&keymap->items, kmi) != -1) { -- cgit v1.2.3 From 2e112f591413eb8b49595c209298d61fec612476 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 25 Jul 2018 11:02:12 +1000 Subject: Keymap: Use 1..4 to change UV select modes Support for sync selection switching which keys apply. --- source/blender/editors/include/ED_object.h | 1 + source/blender/editors/mesh/editmesh_select.c | 12 ++++++++++++ source/blender/editors/mesh/mesh_ops.c | 18 ++---------------- source/blender/editors/object/object_ops.c | 24 ++++++++++++++++++++++++ source/blender/editors/uvedit/uvedit_ops.c | 10 ++++++++++ source/blender/makesrna/RNA_enum_types.h | 1 + source/blender/makesrna/intern/rna_scene.c | 18 +++++++++--------- 7 files changed, 59 insertions(+), 25 deletions(-) (limited to 'source') diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 38545137740..9fd5cc99073 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -112,6 +112,7 @@ void ED_keymap_proportional_obmode(struct wmKeyConfig *keyconf, struct wmKeyMap void ED_keymap_proportional_maskmode(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap); void ED_keymap_proportional_editmode(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, const bool do_connected); +void ED_keymap_editmesh_elem_mode(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap); void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode); void ED_object_base_activate(struct bContext *C, struct Base *base); diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 2e7cf1fc76f..cdb8981801a 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -1462,6 +1462,18 @@ static int edbm_select_mode_exec(bContext *C, wmOperator *op) static int edbm_select_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + /* Bypass when in UV non sync-select mode, fall through to keymap that edits. */ + if (CTX_wm_space_image(C)) { + ToolSettings *ts = CTX_data_tool_settings(C); + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0) { + return OPERATOR_PASS_THROUGH; + } + /* Bypass when no action is needed. */ + if (!RNA_struct_property_is_set(op->ptr, "type")) { + return OPERATOR_CANCELLED; + } + } + /* detecting these options based on shift/ctrl here is weak, but it's done * to make this work when clicking buttons or menus */ if (!RNA_struct_property_is_set(op->ptr, "use_extend")) diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 0fcc5ada854..79c8f5c0b09 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -335,22 +335,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "MESH_OT_bevel", BKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "vertex_only", true); - /* selecting */ - for (int i = 0; i < 4; i++) { - const bool is_extend = (i & 1); - const bool is_expand = (i & 2); - const int key_modifier = (is_extend ? KM_SHIFT : 0) | (is_expand ? KM_CTRL : 0); - for (int j = 0; j < 3; j++) { - kmi = WM_keymap_add_item(keymap, "MESH_OT_select_mode", ONEKEY + j, KM_PRESS, key_modifier, 0); - RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX << j); - if (is_extend) { - RNA_boolean_set(kmi->ptr, "use_extend", true); - } - if (is_expand) { - RNA_boolean_set(kmi->ptr, "use_expand", true); - } - } - } + /* Selec Vert/Edge/Face. */ + ED_keymap_editmesh_elem_mode(keyconf, keymap); /* standard mouse selection goes via space_view3d */ kmi = WM_keymap_add_item(keymap, "MESH_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 5a83d085aee..7b6c1156874 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -40,6 +40,7 @@ #include "BKE_context.h" #include "RNA_access.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -490,3 +491,26 @@ void ED_keymap_proportional_editmode(struct wmKeyConfig *UNUSED(keyconf), struct RNA_string_set(kmi->ptr, "value_2", "CONNECTED"); } } + +/** + * Map 1..3 to Vert/Edge/Face. + */ +void ED_keymap_editmesh_elem_mode(struct wmKeyConfig *UNUSED(keyconf), struct wmKeyMap *keymap) +{ + for (int i = 0; i < 4; i++) { + const bool is_extend = (i & 1); + const bool is_expand = (i & 2); + const int key_modifier = (is_extend ? KM_SHIFT : 0) | (is_expand ? KM_CTRL : 0); + for (int j = 0; j < 3; j++) { + wmKeyMapItem *kmi = WM_keymap_add_item( + keymap, "MESH_OT_select_mode", ONEKEY + j, KM_PRESS, key_modifier, 0); + RNA_enum_set(kmi->ptr, "type", SCE_SELECT_VERTEX << j); + if (is_extend) { + RNA_boolean_set(kmi->ptr, "use_extend", true); + } + if (is_expand) { + RNA_boolean_set(kmi->ptr, "use_expand", true); + } + } + } +} diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 51e2c1b6334..32bf32b03ab 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -80,6 +80,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_types.h" @@ -4404,6 +4405,15 @@ void ED_keymap_uvedit(wmKeyConfig *keyconf) RNA_string_set(kmi->ptr, "data_path", "tool_settings.use_uv_sculpt"); #endif + /* Select Element (Sync Select: on) */ + ED_keymap_editmesh_elem_mode(keyconf, keymap); + /* Hack to prevent fall-through, when the button isn't visible. */ + WM_keymap_add_item(keymap, "MESH_OT_select_mode", FOURKEY, KM_PRESS, 0, 0); + /* Select Element (Sync Select: off) */ + WM_keymap_add_context_enum_set_items( + keymap, rna_enum_mesh_select_mode_uv_items, "tool_settings.uv_select_mode", + ONEKEY, KM_PRESS, 0, 0); + /* Mark edge seam */ WM_keymap_add_item(keymap, "UV_OT_mark_seam", EKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index bafb2bf5753..043375a066a 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -54,6 +54,7 @@ extern const EnumPropertyItem rna_enum_snap_element_items[]; extern const EnumPropertyItem rna_enum_snap_node_element_items[]; extern const EnumPropertyItem rna_enum_curve_fit_method_items[]; extern const EnumPropertyItem rna_enum_mesh_select_mode_items[]; +extern const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[]; extern const EnumPropertyItem rna_enum_mesh_delimit_mode_items[]; extern const EnumPropertyItem rna_enum_space_graph_mode_items[]; extern const EnumPropertyItem rna_enum_space_type_items[]; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 764e55e9e30..5637783aa04 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -165,6 +165,14 @@ const EnumPropertyItem rna_enum_mesh_select_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +const EnumPropertyItem rna_enum_mesh_select_mode_uv_items[] = { + {UV_SELECT_VERTEX, "VERTEX", ICON_UV_VERTEXSEL, "Vertex", "Vertex selection mode"}, + {UV_SELECT_EDGE, "EDGE", ICON_UV_EDGESEL, "Edge", "Edge selection mode"}, + {UV_SELECT_FACE, "FACE", ICON_UV_FACESEL, "Face", "Face selection mode"}, + {UV_SELECT_ISLAND, "ISLAND", ICON_UV_ISLANDSEL, "Island", "Island selection mode"}, + {0, NULL, 0, NULL, NULL} +}; + const EnumPropertyItem rna_enum_snap_element_items[] = { {SCE_SNAP_MODE_INCREMENT, "INCREMENT", ICON_SNAP_INCREMENT, "Increment", "Snap to increments of grid"}, {SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"}, @@ -2404,14 +2412,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - static const EnumPropertyItem uv_select_mode_items[] = { - {UV_SELECT_VERTEX, "VERTEX", ICON_UV_VERTEXSEL, "Vertex", "Vertex selection mode"}, - {UV_SELECT_EDGE, "EDGE", ICON_UV_EDGESEL, "Edge", "Edge selection mode"}, - {UV_SELECT_FACE, "FACE", ICON_UV_FACESEL, "Face", "Face selection mode"}, - {UV_SELECT_ISLAND, "ISLAND", ICON_UV_ISLANDSEL, "Island", "Island selection mode"}, - {0, NULL, 0, NULL, NULL} - }; - /* the construction of this enum is quite special - everything is stored as bitflags, * with 1st position only for for on/off (and exposed as boolean), while others are mutually * exclusive options but which will only have any effect when autokey is enabled @@ -2806,7 +2806,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) /* UV */ prop = RNA_def_property(srna, "uv_select_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "uv_selectmode"); - RNA_def_property_enum_items(prop, uv_select_mode_items); + RNA_def_property_enum_items(prop, rna_enum_mesh_select_mode_uv_items); RNA_def_property_ui_text(prop, "UV Selection Mode", "UV selection and display mode"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); -- cgit v1.2.3 From 509d87230a1c744d555b8b25a3a6069f68d21c5b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 25 Jul 2018 11:39:32 +0200 Subject: Fix missing particle use count object names with disabled particles. --- source/blender/makesrna/intern/rna_particle.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 4b8299b9245..979e5d433e7 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1132,6 +1132,9 @@ static void rna_ParticleDupliWeight_active_index_set(struct PointerRNA *ptr, int static void rna_ParticleDupliWeight_name_get(PointerRNA *ptr, char *str) { + ParticleSettings *part = (ParticleSettings *)ptr->id.data; + psys_find_group_weights(part); + ParticleDupliWeight *dw = ptr->data; if (dw->ob) -- cgit v1.2.3 From f3524fe759e8ad42ab305cf2e1636959914cc97e Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Wed, 25 Jul 2018 12:53:15 +0200 Subject: UI: Minor tweaks to nodes Match roundness with widget defaults and collapse triangle size with panel's. Interaction is the same, just an aesthetic tweak. --- source/blender/editors/interface/interface_panel.c | 6 +++--- source/blender/editors/space_node/node_draw.c | 8 ++++---- source/blender/editors/space_node/node_intern.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 59fdf7e672d..aa67d58fd57 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -454,9 +454,9 @@ static void ui_offset_panel_block(uiBlock *block) /* triangle 'icon' for panel header */ void UI_draw_icon_tri(float x, float y, char dir, const float color[4]) { - float f3 = 0.15 * U.widget_unit; - float f5 = 0.25 * U.widget_unit; - float f7 = 0.35 * U.widget_unit; + float f3 = 0.05 * U.widget_unit; + float f5 = 0.15 * U.widget_unit; + float f7 = 0.25 * U.widget_unit; if (dir == 'h') { UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color); diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 4b3a3abc642..bba46771674 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -951,18 +951,18 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN /* open/close entirely? */ { uiBut *but; - int but_size = UI_UNIT_X * 0.6f; + int but_size = UI_UNIT_X * 1.2f; /* XXX button uses a custom triangle draw below, so make it invisible without icon */ UI_block_emboss_set(node->block, UI_EMBOSS_NONE); but = uiDefBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, "", - rct->xmin + 0.5f * U.widget_unit - but_size / 2, rct->ymax - NODE_DY / 2.0f - but_size / 2, + rct->xmin + 0.6f * U.widget_unit - but_size / 2, rct->ymax - NODE_DY / 2.2f - but_size / 2, but_size, but_size, NULL, 0, 0, 0, 0, ""); UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_hide_toggle"); UI_block_emboss_set(node->block, UI_EMBOSS); UI_GetThemeColor4fv(TH_TEXT, color); /* custom draw function for this button */ - UI_draw_icon_tri(rct->xmin + 0.5f * U.widget_unit, rct->ymax - NODE_DY / 2.0f, 'v', color); + UI_draw_icon_tri(rct->xmin + 0.6f * U.widget_unit, rct->ymax - NODE_DY / 2.2f, 'v', color); } nodeLabel(ntree, node, showname, sizeof(showname)); @@ -1071,7 +1071,7 @@ static void node_draw_hidden(const bContext *C, ARegion *ar, SpaceNode *snode, b /* open entirely icon */ { uiBut *but; - int but_size = UI_UNIT_X * 0.6f; + int but_size = UI_UNIT_X * 1.2f; /* XXX button uses a custom triangle draw below, so make it invisible without icon */ UI_block_emboss_set(node->block, UI_EMBOSS_NONE); but = uiDefBut(node->block, UI_BTYPE_BUT_TOGGLE, B_REDR, "", diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index ed7379acca9..3644c8d09e6 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -238,7 +238,7 @@ extern const char *node_context_dir[]; // nodes draw without dpi - the view zoom is flexible #define HIDDEN_RAD (0.75f * U.widget_unit) -#define BASIS_RAD (0.4f * U.widget_unit) +#define BASIS_RAD (0.2f * U.widget_unit) #define NODE_DYS (U.widget_unit / 2) #define NODE_DY U.widget_unit #define NODE_SOCKDY (0.08f * U.widget_unit) -- cgit v1.2.3 From 5f1ead63953527abd9ddca16986990d59f123aff Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 25 Jul 2018 14:52:29 +0200 Subject: Fix T55895: VSE crash while moving a strip Glitch from multi-edit project. ;) --- source/blender/editors/transform/transform_snap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index b67fd22dbff..54253e36351 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1462,7 +1462,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2]) float xmouse, ymouse; int frame; int mframe; - TransSeq *ts = t->custom.type.data; + TransSeq *ts = TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data; /* reuse increment, strictly speaking could be another snap mode, but leave as is */ if (!(t->modifiers & MOD_SNAP_INVERT)) return; -- cgit v1.2.3 From b0077992d2759b29b536187a226e8382b72261b6 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 25 Jul 2018 12:26:09 +0200 Subject: Cycles: add per layer collection mask/holdout support. In the outliner, right click > view layer > set holdout. This is temporary until we have more general dynamic overrides, but helps Spring production for now. --- source/blender/blenkernel/intern/layer.c | 12 ++- source/blender/blenloader/intern/versioning_280.c | 1 + .../editors/space_outliner/outliner_collections.c | 87 ++++++++++++++++------ .../editors/space_outliner/outliner_intern.h | 4 +- .../blender/editors/space_outliner/outliner_ops.c | 6 +- source/blender/makesdna/DNA_layer_types.h | 2 + source/blender/makesrna/intern/rna_layer.c | 6 ++ source/blender/makesrna/intern/rna_object_api.c | 32 ++++++-- 8 files changed, 117 insertions(+), 33 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 2f5c8e7817e..73a217b8865 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -715,6 +715,11 @@ static int layer_collection_sync( lc->runtime_flag |= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS; } + /* Holdout */ + if (lc->flag & LAYER_COLLECTION_HOLDOUT) { + base->flag |= BASE_HOLDOUT; + } + lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS; } @@ -750,7 +755,12 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) /* Clear visible and selectable flags to be reset. */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { - base->flag &= ~(BASE_VISIBLE | BASE_ENABLED | BASE_SELECTABLE | BASE_ENABLED_VIEWPORT | BASE_ENABLED_RENDER); + base->flag &= ~(BASE_VISIBLE | + BASE_ENABLED | + BASE_SELECTABLE | + BASE_ENABLED_VIEWPORT | + BASE_ENABLED_RENDER | + BASE_HOLDOUT); } view_layer->runtime_flag = 0; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 3a586e49ab3..94afc410000 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -492,6 +492,7 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene) { if (srl->lay_zmask & (1 << layer)) { have_override = true; + lc->flag |= LAYER_COLLECTION_HOLDOUT; BKE_override_layer_collection_boolean_add( lc, diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index ad94615a0d2..eec1d654944 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -574,7 +574,7 @@ static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, v return TRAVERSE_CONTINUE; } -static bool collections_view_layer_poll(bContext *C, bool include) +static bool collections_view_layer_poll(bContext *C, bool clear, int flag) { /* Poll function so the right click menu show current state of selected collections. */ SpaceOops *soops = CTX_wm_space_outliner(C); @@ -593,10 +593,10 @@ static bool collections_view_layer_poll(bContext *C, bool include) GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); - if (include && (lc->flag & LAYER_COLLECTION_EXCLUDE)) { + if (clear && (lc->flag & flag)) { result = true; } - else if (!include && !(lc->flag & LAYER_COLLECTION_EXCLUDE)) { + else if (!clear && !(lc->flag & flag)) { result = true; } } @@ -605,27 +605,37 @@ static bool collections_view_layer_poll(bContext *C, bool include) return result; } -static bool collections_exclude_poll(bContext *C) +static bool collections_exclude_set_poll(bContext *C) { - return collections_view_layer_poll(C, false); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_EXCLUDE); } -static bool collections_include_poll(bContext *C) +static bool collections_exclude_clear_poll(bContext *C) { - return collections_view_layer_poll(C, true); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_EXCLUDE); } -static void layer_collection_exclude_recursive_set(LayerCollection *lc) +static bool collections_holdout_set_poll(bContext *C) +{ + return collections_view_layer_poll(C, false, LAYER_COLLECTION_HOLDOUT); +} + +static bool collections_holdout_clear_poll(bContext *C) +{ + return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT); +} + +static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag) { for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - if (lc->flag & LAYER_COLLECTION_EXCLUDE) { - nlc->flag |= LAYER_COLLECTION_EXCLUDE; + if (lc->flag & flag) { + nlc->flag |= flag; } else { - nlc->flag &= ~LAYER_COLLECTION_EXCLUDE; + nlc->flag &= ~flag; } - layer_collection_exclude_recursive_set(nlc); + layer_collection_flag_recursive_set(nlc, flag); } } @@ -636,7 +646,8 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOops *soops = CTX_wm_space_outliner(C); struct CollectionEditData data = {.scene = scene, .soops = soops}; - bool include = STREQ(op->idname, "OUTLINER_OT_collection_include_set"); + bool clear = strstr(op->idname, "clear") != NULL; + int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT : LAYER_COLLECTION_EXCLUDE; data.collections_to_edit = BLI_gset_ptr_new(__func__); @@ -647,14 +658,14 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); if (!(lc->collection->flag & COLLECTION_IS_MASTER)) { - if (include) { - lc->flag &= ~LAYER_COLLECTION_EXCLUDE; + if (clear) { + lc->flag &= ~flag; } else { - lc->flag |= LAYER_COLLECTION_EXCLUDE; + lc->flag |= flag; } - layer_collection_exclude_recursive_set(lc); + layer_collection_flag_recursive_set(lc, flag); } } @@ -671,28 +682,58 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) { /* identifiers */ - ot->name = "Exclude from View Layer"; + ot->name = "Set Exclude"; ot->idname = "OUTLINER_OT_collection_exclude_set"; ot->description = "Exclude collection from the active view layer"; /* api callbacks */ ot->exec = collection_view_layer_exec; - ot->poll = collections_exclude_poll; + ot->poll = collections_exclude_set_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -void OUTLINER_OT_collection_include_set(wmOperatorType *ot) +void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot) { /* identifiers */ - ot->name = "Include in View Layer"; - ot->idname = "OUTLINER_OT_collection_include_set"; + ot->name = "Clear Exclude"; + ot->idname = "OUTLINER_OT_collection_exclude_clear"; ot->description = "Include collection in the active view layer"; /* api callbacks */ ot->exec = collection_view_layer_exec; - ot->poll = collections_include_poll; + ot->poll = collections_exclude_clear_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_holdout_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Holdout"; + ot->idname = "OUTLINER_OT_collection_holdout_set"; + ot->description = "Mask collection in the active view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_holdout_set_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_holdout_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Holdout"; + ot->idname = "OUTLINER_OT_collection_holdout_clear"; + ot->description = "Clear masking of collection in the active view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_holdout_clear_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 093ad9361c2..9262cf8578c 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -358,7 +358,9 @@ void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_instance(struct wmOperatorType *ot); void OUTLINER_OT_collection_exclude_set(struct wmOperatorType *ot); -void OUTLINER_OT_collection_include_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_exclude_clear(struct wmOperatorType *ot); +void OUTLINER_OT_collection_holdout_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_holdout_clear(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 8b4ae029876..4bd5a0c3792 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -457,7 +457,9 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_instance); WM_operatortype_append(OUTLINER_OT_collection_exclude_set); - WM_operatortype_append(OUTLINER_OT_collection_include_set); + WM_operatortype_append(OUTLINER_OT_collection_exclude_clear); + WM_operatortype_append(OUTLINER_OT_collection_holdout_set); + WM_operatortype_append(OUTLINER_OT_collection_holdout_clear); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) @@ -571,7 +573,7 @@ void outliner_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "OBJECT_OT_link_to_collection", MKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "OUTLINER_OT_collection_exclude_set", EKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "OUTLINER_OT_collection_include_set", EKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "OUTLINER_OT_collection_exclude_clear", EKEY, KM_PRESS, KM_ALT, 0); kmi = WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "select", false); diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index bfdd21807b8..2bfe4c4e13b 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -104,6 +104,7 @@ enum { BASE_ENABLED_VIEWPORT = (1 << 6), /* Object is enabled in viewport. */ BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */ BASE_ENABLED = (1 << 9), /* Object is enabled. */ + BASE_HOLDOUT = (1 << 10), /* Object masked out from render */ }; /* LayerCollection->flag */ @@ -113,6 +114,7 @@ enum { /* LAYER_COLLECTION_DEPRECATED2 = (1 << 2), */ /* LAYER_COLLECTION_DEPRECATED3 = (1 << 3), */ LAYER_COLLECTION_EXCLUDE = (1 << 4), + LAYER_COLLECTION_HOLDOUT = (1 << 5), }; /* Layer Collection->runtime_flag */ diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 7d770a99c0c..1ab69d78f03 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -230,6 +230,12 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Exclude", "Exclude collection from view layer"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update"); + + prop = RNA_def_property(srna, "holdout", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_HOLDOUT); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Holdout", "Mask out collection from view layer"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update"); } static void rna_def_layer_collections(BlenderRNA *brna, PropertyRNA *cprop) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 1a2b3854668..dc799928e5a 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -148,6 +148,18 @@ static bool rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports) return ((base->flag & BASE_VISIBLE) != 0) ? 1 : 0; } +static bool rna_Object_holdout_get(Object *ob, ReportList *reports, ViewLayer *view_layer) +{ + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (!base) { + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, view_layer->name); + return -1; + } + + return ((base->flag & BASE_HOLDOUT) != 0) ? 1 : 0; +} + /* Convert a given matrix from a space to another (using the object and/or a bone as reference). */ static void rna_Object_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan, float *mat, float *mat_ret, int from, int to) @@ -470,31 +482,39 @@ void RNA_api_object(StructRNA *srna) #endif static EnumPropertyItem object_select_items[] = { - {0, "SELECT", 0, "Select", "Select object from the active render layer"}, - {1, "DESELECT", 0, "Deselect", "Deselect object from the active render layer"}, - {2, "TOGGLE", 0, "Toggle", "Toggle object selection from the active render layer"}, + {0, "SELECT", 0, "Select", "Select object from the active view layer"}, + {1, "DESELECT", 0, "Deselect", "Deselect object from the active view layer"}, + {2, "TOGGLE", 0, "Toggle", "Toggle object selection from the active view layer"}, {0, NULL, 0, NULL, NULL} }; /* Special wrapper to access the base selection value */ func = RNA_def_function(srna, "select_set", "rna_Object_select_set"); - RNA_def_function_ui_description(func, "Select the object (for the active render layer)"); + RNA_def_function_ui_description(func, "Select the object (for the active view layer)"); RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_enum(func, "action", object_select_items, 0, "Action", "Select mode"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "select_get", "rna_Object_select_get"); - RNA_def_function_ui_description(func, "Get the object selection for the active render layer"); + RNA_def_function_ui_description(func, "Get the object selection for the active view layer"); RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_boolean(func, "result", 0, "", "Object selected"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "visible_get", "rna_Object_visible_get"); - RNA_def_function_ui_description(func, "Get the object visibility for the active render layer"); + RNA_def_function_ui_description(func, "Get the object visibility for the active view layer"); RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_boolean(func, "result", 0, "", "Object visible"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "holdout_get", "rna_Object_holdout_get"); + RNA_def_function_ui_description(func, "Test if object is masked in the view layer"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, "result", 0, "", "Object holdout"); + RNA_def_function_return(func, parm); + /* Matrix space conversion */ func = RNA_def_function(srna, "convert_space", "rna_Object_mat_convert_space"); RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another"); -- cgit v1.2.3 From 885cda65c90b3f85dc4e72e2e9759aa926a8f07c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 25 Jul 2018 12:26:09 +0200 Subject: Cycles: add per layer collection indirectly on setting. In the outliner, right click > view layer > set indirect only. This is like clearing camera ray visibility on objects in the collection, and is temporary until we have more general dynamic overrides. --- source/blender/blenkernel/intern/layer.c | 8 +++- source/blender/blenloader/intern/versioning_280.c | 17 +-------- .../editors/space_outliner/outliner_collections.c | 44 +++++++++++++++++++++- .../editors/space_outliner/outliner_intern.h | 2 + .../blender/editors/space_outliner/outliner_ops.c | 2 + source/blender/makesdna/DNA_layer_types.h | 2 + source/blender/makesrna/intern/rna_layer.c | 8 +++- source/blender/makesrna/intern/rna_object_api.c | 26 +++++++++++-- 8 files changed, 87 insertions(+), 22 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 73a217b8865..1396ad1f97c 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -715,10 +715,13 @@ static int layer_collection_sync( lc->runtime_flag |= LAYER_COLLECTION_HAS_VISIBLE_OBJECTS; } - /* Holdout */ + /* Holdout and indirect only */ if (lc->flag & LAYER_COLLECTION_HOLDOUT) { base->flag |= BASE_HOLDOUT; } + if (lc->flag & LAYER_COLLECTION_INDIRECT_ONLY) { + base->flag |= BASE_INDIRECT_ONLY; + } lc->runtime_flag |= LAYER_COLLECTION_HAS_OBJECTS; } @@ -760,7 +763,8 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) BASE_SELECTABLE | BASE_ENABLED_VIEWPORT | BASE_ENABLED_RENDER | - BASE_HOLDOUT); + BASE_HOLDOUT | + BASE_INDIRECT_ONLY); } view_layer->runtime_flag = 0; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 94afc410000..068c12daa94 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -487,28 +487,15 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene) nlc->flag |= LAYER_COLLECTION_EXCLUDE; } } - else if ((scene->lay & srl->lay & ~(srl->lay_exclude) & (1 << layer)) || - (srl->lay_zmask & (scene->lay | srl->lay_exclude) & (1 << layer))) - { + else { if (srl->lay_zmask & (1 << layer)) { have_override = true; lc->flag |= LAYER_COLLECTION_HOLDOUT; - - BKE_override_layer_collection_boolean_add( - lc, - ID_OB, - "cycles.is_holdout", - true); } if ((srl->lay & (1 << layer)) == 0) { have_override = true; - - BKE_override_layer_collection_boolean_add( - lc, - ID_OB, - "cycles_visibility.camera", - false); + lc->flag |= LAYER_COLLECTION_INDIRECT_ONLY; } } } diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index eec1d654944..e480cac2dcc 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -625,6 +625,16 @@ static bool collections_holdout_clear_poll(bContext *C) return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT); } +static bool collections_indirect_only_set_poll(bContext *C) +{ + return collections_view_layer_poll(C, false, LAYER_COLLECTION_INDIRECT_ONLY); +} + +static bool collections_indirect_only_clear_poll(bContext *C) +{ + return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY); +} + static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag) { for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { @@ -647,7 +657,9 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) SpaceOops *soops = CTX_wm_space_outliner(C); struct CollectionEditData data = {.scene = scene, .soops = soops}; bool clear = strstr(op->idname, "clear") != NULL; - int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT : LAYER_COLLECTION_EXCLUDE; + int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT : + strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY : + LAYER_COLLECTION_EXCLUDE; data.collections_to_edit = BLI_gset_ptr_new(__func__); @@ -739,6 +751,36 @@ void OUTLINER_OT_collection_holdout_clear(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +void OUTLINER_OT_collection_indirect_only_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Indirect Only"; + ot->idname = "OUTLINER_OT_collection_indirect_only_set"; + ot->description = "Set collection to only contribute indirectly (through shadows and reflections) in the view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_indirect_only_set_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Clear Indirect Only"; + ot->idname = "OUTLINER_OT_collection_indirect_only_clear"; + ot->description = "Clear collection contributing only indirectly in the view layer"; + + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_indirect_only_clear_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /** * Populates the \param objects ListBase with all the outliner selected objects * We store it as (Object *)LinkData->data diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 9262cf8578c..461d4bd7c56 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -361,6 +361,8 @@ void OUTLINER_OT_collection_exclude_set(struct wmOperatorType *ot); void OUTLINER_OT_collection_exclude_clear(struct wmOperatorType *ot); void OUTLINER_OT_collection_holdout_set(struct wmOperatorType *ot); void OUTLINER_OT_collection_holdout_clear(struct wmOperatorType *ot); +void OUTLINER_OT_collection_indirect_only_set(struct wmOperatorType *ot); +void OUTLINER_OT_collection_indirect_only_clear(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 4bd5a0c3792..576038979d3 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -460,6 +460,8 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_exclude_clear); WM_operatortype_append(OUTLINER_OT_collection_holdout_set); WM_operatortype_append(OUTLINER_OT_collection_holdout_clear); + WM_operatortype_append(OUTLINER_OT_collection_indirect_only_set); + WM_operatortype_append(OUTLINER_OT_collection_indirect_only_clear); } static wmKeyMap *outliner_item_drag_drop_modal_keymap(wmKeyConfig *keyconf) diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 2bfe4c4e13b..e6b1bda7cf5 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -105,6 +105,7 @@ enum { BASE_ENABLED_RENDER = (1 << 7), /* Object is enabled in final render */ BASE_ENABLED = (1 << 9), /* Object is enabled. */ BASE_HOLDOUT = (1 << 10), /* Object masked out from render */ + BASE_INDIRECT_ONLY = (1 << 11), /* Object only contributes indirectly to render */ }; /* LayerCollection->flag */ @@ -115,6 +116,7 @@ enum { /* LAYER_COLLECTION_DEPRECATED3 = (1 << 3), */ LAYER_COLLECTION_EXCLUDE = (1 << 4), LAYER_COLLECTION_HOLDOUT = (1 << 5), + LAYER_COLLECTION_INDIRECT_ONLY = (1 << 6), }; /* Layer Collection->runtime_flag */ diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c index 1ab69d78f03..d425534fe53 100644 --- a/source/blender/makesrna/intern/rna_layer.c +++ b/source/blender/makesrna/intern/rna_layer.c @@ -234,7 +234,13 @@ static void rna_def_layer_collection(BlenderRNA *brna) prop = RNA_def_property(srna, "holdout", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_HOLDOUT); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Holdout", "Mask out collection from view layer"); + RNA_def_property_ui_text(prop, "Holdout", "Mask out objects in collection from view layer"); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update"); + + prop = RNA_def_property(srna, "indirect_only", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", LAYER_COLLECTION_INDIRECT_ONLY); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Indirect Only", "Objects in collection only contribute indirectly (through shadows and reflections) in the view layer"); RNA_def_property_update(prop, NC_SCENE | ND_LAYER, "rna_LayerCollection_use_update"); } diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index dc799928e5a..44709db9d94 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -128,7 +128,7 @@ static bool rna_Object_select_get(Object *ob, bContext *C, ReportList *reports) Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, view_layer->name); + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); return -1; } @@ -141,7 +141,7 @@ static bool rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports) Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, view_layer->name); + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); return -1; } @@ -153,13 +153,25 @@ static bool rna_Object_holdout_get(Object *ob, ReportList *reports, ViewLayer *v Base *base = BKE_view_layer_base_find(view_layer, ob); if (!base) { - BKE_reportf(reports, RPT_ERROR, "Object '%s' not in Render Layer '%s'!", ob->id.name + 2, view_layer->name); + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); return -1; } return ((base->flag & BASE_HOLDOUT) != 0) ? 1 : 0; } +static bool rna_Object_indirect_only_get(Object *ob, ReportList *reports, ViewLayer *view_layer) +{ + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (!base) { + BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); + return -1; + } + + return ((base->flag & BASE_INDIRECT_ONLY) != 0) ? 1 : 0; +} + /* Convert a given matrix from a space to another (using the object and/or a bone as reference). */ static void rna_Object_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan, float *mat, float *mat_ret, int from, int to) @@ -515,6 +527,14 @@ void RNA_api_object(StructRNA *srna) parm = RNA_def_boolean(func, "result", 0, "", "Object holdout"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "indirect_only_get", "rna_Object_indirect_only_get"); + RNA_def_function_ui_description(func, "Test if object is set to contribute only indirectly (through shadows and reflections) in the view layer"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "view_layer", "ViewLayer", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, "result", 0, "", "Object indirect only"); + RNA_def_function_return(func, parm); + /* Matrix space conversion */ func = RNA_def_function(srna, "convert_space", "rna_Object_mat_convert_space"); RNA_def_function_ui_description(func, "Convert (transform) the given matrix from one space to another"); -- cgit v1.2.3 From 9a40690242dff4153a48c1da0f0f87a71a020e64 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 25 Jul 2018 18:30:26 +0200 Subject: Fix for holdout / indirect only with collection instances. --- source/blender/makesrna/intern/rna_object_api.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 44709db9d94..8f8f3176096 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -129,10 +129,10 @@ static bool rna_Object_select_get(Object *ob, bContext *C, ReportList *reports) if (!base) { BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); - return -1; + return false; } - return ((base->flag & BASE_SELECTED) != 0) ? 1 : 0; + return ((base->flag & BASE_SELECTED) != 0); } static bool rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports) @@ -142,10 +142,10 @@ static bool rna_Object_visible_get(Object *ob, bContext *C, ReportList *reports) if (!base) { BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); - return -1; + return false; } - return ((base->flag & BASE_VISIBLE) != 0) ? 1 : 0; + return ((base->flag & BASE_VISIBLE) != 0); } static bool rna_Object_holdout_get(Object *ob, ReportList *reports, ViewLayer *view_layer) @@ -154,10 +154,10 @@ static bool rna_Object_holdout_get(Object *ob, ReportList *reports, ViewLayer *v if (!base) { BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); - return -1; + return false; } - return ((base->flag & BASE_HOLDOUT) != 0) ? 1 : 0; + return ((base->flag & BASE_HOLDOUT) != 0); } static bool rna_Object_indirect_only_get(Object *ob, ReportList *reports, ViewLayer *view_layer) @@ -166,10 +166,10 @@ static bool rna_Object_indirect_only_get(Object *ob, ReportList *reports, ViewLa if (!base) { BKE_reportf(reports, RPT_ERROR, "Object '%s' not in View Layer '%s'!", ob->id.name + 2, view_layer->name); - return -1; + return false; } - return ((base->flag & BASE_INDIRECT_ONLY) != 0) ? 1 : 0; + return ((base->flag & BASE_INDIRECT_ONLY) != 0); } /* Convert a given matrix from a space to another (using the object and/or a bone as reference). */ -- cgit v1.2.3 From 5ba4d059c014a038202b6981a040ba247ff42758 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 25 Jul 2018 21:04:28 +0200 Subject: Fix (unreported) potential div-by-zero in ray/bbox intersection BLI code. Also added note that direction parameter should be normalized vector in case one intend to use returned distance values. --- source/blender/blenlib/intern/math_geom.c | 32 +++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'source') diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index a48d985faed..61b8f6819cc 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2475,9 +2475,11 @@ bool isect_ray_aabb_v3( return true; } -/* - * Test a bounding box (AABB) for ray intersection - * assumes the ray is already local to the boundbox space +/** + * Test a bounding box (AABB) for ray intersection. + * Assumes the ray is already local to the boundbox space. + * + * \note: \a direction should be normalized if you intend to use the \a tmin or \a tmax distance results! */ bool isect_ray_aabb_v3_simple( const float orig[3], const float dir[3], @@ -2486,19 +2488,25 @@ bool isect_ray_aabb_v3_simple( { double t[7]; float hit_dist[2]; - t[1] = (double)(bb_min[0] - orig[0]) / dir[0]; - t[2] = (double)(bb_max[0] - orig[0]) / dir[0]; - t[3] = (double)(bb_min[1] - orig[1]) / dir[1]; - t[4] = (double)(bb_max[1] - orig[1]) / dir[1]; - t[5] = (double)(bb_min[2] - orig[2]) / dir[2]; - t[6] = (double)(bb_max[2] - orig[2]) / dir[2]; + const double invdirx = (dir[0] > 1e-35f || dir[0] < -1e-35f) ? 1.0 / (double)dir[0] : DBL_MAX; + const double invdiry = (dir[1] > 1e-35f || dir[1] < -1e-35f) ? 1.0 / (double)dir[1] : DBL_MAX; + const double invdirz = (dir[2] > 1e-35f || dir[2] < -1e-35f) ? 1.0 / (double)dir[2] : DBL_MAX; + t[1] = (double)(bb_min[0] - orig[0]) * invdirx; + t[2] = (double)(bb_max[0] - orig[0]) * invdirx; + t[3] = (double)(bb_min[1] - orig[1]) * invdiry; + t[4] = (double)(bb_max[1] - orig[1]) * invdiry; + t[5] = (double)(bb_min[2] - orig[2]) * invdirz; + t[6] = (double)(bb_max[2] - orig[2]) * invdirz; hit_dist[0] = (float)fmax(fmax(fmin(t[1], t[2]), fmin(t[3], t[4])), fmin(t[5], t[6])); hit_dist[1] = (float)fmin(fmin(fmax(t[1], t[2]), fmax(t[3], t[4])), fmax(t[5], t[6])); - if ((hit_dist[1] < 0 || hit_dist[0] > hit_dist[1])) + if ((hit_dist[1] < 0.0f || hit_dist[0] > hit_dist[1])) { return false; + } else { - if (tmin) *tmin = hit_dist[0]; - if (tmax) *tmax = hit_dist[1]; + if (tmin) + *tmin = hit_dist[0]; + if (tmax) + *tmax = hit_dist[1]; return true; } } -- cgit v1.2.3 From 29d1db9ed6253f68c5452be1f0125ed364d4a954 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 25 Jul 2018 21:05:44 +0200 Subject: Fix T55964: Direction not normalized in isect_ray_aabb_v3_simple()? RNA API Object.ray_cast would not normalize direction vector before doing first quick bbox intersection test, while using its returned distance value. This could lead to wrong exclusion of object. Thanks to @codemanx for finding that issue. --- source/blender/makesrna/intern/rna_object_api.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 2acda5985e1..376a89c65d1 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -332,8 +332,10 @@ static void rna_Object_ray_cast( /* Test BoundBox first (efficiency) */ BoundBox *bb = BKE_object_boundbox_get(ob); float distmin; - if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) { - + normalize_v3(direction); /* Needed for valid distance check from isect_ray_aabb_v3_simple() call. */ + if (!bb || + (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) + { BVHTreeFromMesh treeData = {NULL}; /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ @@ -346,9 +348,6 @@ static void rna_Object_ray_cast( hit.index = -1; hit.dist = distance; - normalize_v3(direction); - - if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1) { -- cgit v1.2.3 From 1882dfc47c18c9b715c36eb7a76d01a306a10580 Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Thu, 26 Jul 2018 02:42:20 +0200 Subject: UI: More opaque type icons in the Outliner Also always draw the counter of elements-per-type with a dark background regardless of the active status. It being white when active affects readability since the icon background itself is already highlighted. Thanks devtalk forum for feedback. --- source/blender/editors/space_outliner/outliner_draw.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'source') diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 783a03f3993..e1049d02e37 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1341,16 +1341,9 @@ static void tselem_draw_icon( static void outliner_draw_iconrow_number( const uiFontStyle *fstyle, int offsx, int ys, - const eOLDrawState active, const int num_elements) { - float color[4] = {0.4f, 0.4f, 0.4f, 0.9f}; - copy_v3_fl(color, 0.2f); - if (active != OL_DRAWSEL_NONE) { - copy_v3_fl(color, 0.65f); - color[3] = 1.0f; - } - + float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float ufac = 0.25f * UI_UNIT_X; float offset_x = (float) offsx + UI_UNIT_X * 0.35f; @@ -1414,13 +1407,13 @@ static void outliner_draw_iconrow_doit( } /* No inlined icon should be clickable. */ - tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.5f * alpha_fac, false); + tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.8f * alpha_fac, false); te->xs = *offsx; te->ys = ys; te->xend = (short)*offsx + UI_UNIT_X; if (num_elements > 1) { - outliner_draw_iconrow_number(fstyle, *offsx, ys, active, num_elements); + outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements); } (*offsx) += UI_UNIT_X; } -- cgit v1.2.3 From 2df27fa6cf85a6b4534302a41d9588b550029b01 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 11:07:56 +1000 Subject: Cleanup: Use const argument --- source/blender/makesrna/RNA_access.h | 2 +- source/blender/makesrna/intern/rna_access.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index ffada6efd02..a026d8e875e 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -800,7 +800,7 @@ bool RNA_struct_bl_idname_ok_or_report(struct ReportList *reports, const char *i /* Property Information */ -const char *RNA_property_identifier(PropertyRNA *prop); +const char *RNA_property_identifier(const PropertyRNA *prop); const char *RNA_property_description(PropertyRNA *prop); PropertyType RNA_property_type(PropertyRNA *prop); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 2a74aedd60a..d805d6138a7 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -952,7 +952,7 @@ bool RNA_struct_bl_idname_ok_or_report(ReportList *reports, const char *identifi /* Property Information */ -const char *RNA_property_identifier(PropertyRNA *prop) +const char *RNA_property_identifier(const PropertyRNA *prop) { return rna_ensure_property_identifier(prop); } -- cgit v1.2.3 From dbd79c097c14d486fe79b91b916a9f854587b27e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 09:59:56 +1000 Subject: WM: Add operator property poll callback This allows operators to filter out properties from the auto-generated draw functions. Some custom draw functions can move to using this. --- source/blender/editors/gpencil/gpencil_convert.c | 4 ++-- source/blender/editors/include/UI_interface.h | 7 ++++-- .../editors/interface/interface_templates.c | 20 +++++++++++++++-- source/blender/editors/interface/interface_utils.c | 5 +++-- source/blender/editors/mesh/editmesh_tools.c | 4 ++-- .../blender/editors/object/object_data_transfer.c | 4 ++-- source/blender/editors/object/object_relations.c | 4 ++-- source/blender/editors/screen/screendump.c | 4 ++-- source/blender/editors/space_clip/clip_toolbar.c | 2 +- source/blender/editors/space_file/file_panels.c | 25 ++++++++++++---------- source/blender/editors/space_image/image_ops.c | 8 +++---- .../editors/space_sequencer/sequencer_add.c | 4 ++-- .../blender/editors/space_view3d/view3d_toolbar.c | 2 +- source/blender/windowmanager/WM_types.h | 6 ++++++ source/blender/windowmanager/intern/wm_operators.c | 8 +++---- 15 files changed, 68 insertions(+), 39 deletions(-) (limited to 'source') diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 0c148710e3e..d6cb36d7fcd 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1371,7 +1371,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes"); @@ -1444,7 +1444,7 @@ static void gp_convert_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, NULL, '\0'); } void GPENCIL_OT_convert(wmOperatorType *ot) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index eefbeee6336..f2aad249df3 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -703,7 +703,11 @@ uiBut *uiDefSearchButO_ptr( short width, short height, float a1, float a2, const char *tip); uiBut *uiDefAutoButR(uiBlock *block, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, const char *name, int icon, int x1, int y1, int x2, int y2); -int uiDefAutoButsRNA(uiLayout *layout, struct PointerRNA *ptr, bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), const char label_align); + +int uiDefAutoButsRNA( + uiLayout *layout, struct PointerRNA *ptr, + bool (*check_prop)(struct PointerRNA *ptr, struct PropertyRNA *prop, void *user_data), void *user_data, + const char label_align); /* Links * @@ -988,7 +992,6 @@ void UI_but_func_operator_search(uiBut *but); void uiTemplateOperatorSearch(uiLayout *layout); void uiTemplateOperatorPropertyButs( const struct bContext *C, uiLayout *layout, struct wmOperator *op, - bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), const char label_align, const short flag); void uiTemplateHeader3D(uiLayout *layout, struct bContext *C); void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index daee0d3af3f..9d05819dd6a 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3549,13 +3549,24 @@ static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), void *op_pt, } #endif +struct uiTemplateOperatorPropertyPollParam { + const bContext *C; + wmOperator *op; +}; + +static bool ui_layout_operator_buts_poll_property( + struct PointerRNA *UNUSED(ptr), struct PropertyRNA *prop, void *user_data) +{ + struct uiTemplateOperatorPropertyPollParam *params = user_data; + return params->op->type->poll_property(params->C, params->op, prop); +} + /** * Draw Operator property buttons for redoing execution with different settings. * This function does not initialize the layout, functions can be called on the layout before and after. */ void uiTemplateOperatorPropertyButs( const bContext *C, uiLayout *layout, wmOperator *op, - bool (*check_prop)(struct PointerRNA *, struct PropertyRNA *), const char label_align, const short flag) { if (!op->properties) { @@ -3611,11 +3622,16 @@ void uiTemplateOperatorPropertyButs( wmWindowManager *wm = CTX_wm_manager(C); PointerRNA ptr; int empty; + struct uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op}; RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* main draw call */ - empty = uiDefAutoButsRNA(layout, &ptr, check_prop, label_align) == 0; + empty = uiDefAutoButsRNA( + layout, &ptr, + op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL, + op->type->poll_property ? &user_data : NULL, + label_align) == 0; if (empty && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) { uiItemL(layout, IFACE_("No Properties"), ICON_NONE); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 1aa6f045266..2059fc1c849 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -159,7 +159,7 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind */ int uiDefAutoButsRNA( uiLayout *layout, PointerRNA *ptr, - bool (*check_prop)(PointerRNA *, PropertyRNA *), + bool (*check_prop)(PointerRNA *ptr, PropertyRNA *prop, void *user_data), void *user_data, const char label_align) { uiLayout *split, *col; @@ -172,8 +172,9 @@ int uiDefAutoButsRNA( RNA_STRUCT_BEGIN (ptr, prop) { flag = RNA_property_flag(prop); - if (flag & PROP_HIDDEN || (check_prop && check_prop(ptr, prop) == 0)) + if (flag & PROP_HIDDEN || (check_prop && check_prop(ptr, prop, user_data) == 0)) { continue; + } if (label_align != '\0') { PropertyType type = RNA_property_type(prop); diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index a478fee1f82..c5c670b77ea 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -5373,7 +5373,7 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); const int action = RNA_enum_get(ptr, "type"); @@ -5406,7 +5406,7 @@ static void edbm_sort_elements_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call. */ - uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, NULL, '\0'); } void MESH_OT_sort_elements(wmOperatorType *ot) diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 384bea3701f..44cca58fc5c 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -453,7 +453,7 @@ static bool data_transfer_poll(bContext *C) } /* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ -static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { PropertyRNA *prop_other; @@ -525,7 +525,7 @@ static void data_transfer_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, data_transfer_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, data_transfer_draw_check_prop, NULL, '\0'); } /* transfers weight from active to selected */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 286a7e09581..77b5d35db03 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -938,7 +938,7 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent return OPERATOR_INTERFACE; } -static bool parent_set_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool parent_set_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); const int type = RNA_enum_get(ptr, "type"); @@ -963,7 +963,7 @@ static void parent_set_ui(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* Main auto-draw call. */ - uiDefAutoButsRNA(layout, &ptr, parent_set_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, parent_set_draw_check_prop, NULL, '\0'); } void OBJECT_OT_parent_set(wmOperatorType *ot) diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index dda75877f50..3ec2078a4d1 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -247,7 +247,7 @@ static void screenshot_cancel(bContext *UNUSED(C), wmOperator *op) screenshot_data_free(op); } -static bool screenshot_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) +static bool screenshot_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); @@ -266,7 +266,7 @@ static void screenshot_draw(bContext *UNUSED(C), wmOperator *op) /* main draw call */ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); - uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, NULL, '\0'); } static bool screenshot_poll(bContext *C) diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c index fbd73ee4315..7d4aa0083f1 100644 --- a/source/blender/editors/space_clip/clip_toolbar.c +++ b/source/blender/editors/space_clip/clip_toolbar.c @@ -193,7 +193,7 @@ void CLIP_OT_tools(wmOperatorType *ot) static void clip_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op) { - uiTemplateOperatorPropertyButs(C, pa->layout, op, NULL, 'V', 0); + uiTemplateOperatorPropertyButs(C, pa->layout, op, 'V', 0); } static void clip_panel_operator_redo_header(const bContext *C, Panel *pa) diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index c02320de89e..c5350750af4 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -43,6 +43,7 @@ #include "MEM_guardedalloc.h" #include "RNA_access.h" +#include "RNA_define.h" #include "ED_fileselect.h" @@ -71,24 +72,26 @@ static void file_panel_operator_header(const bContext *C, Panel *pa) BLI_strncpy(pa->drawname, RNA_struct_ui_name(op->type->srna), sizeof(pa->drawname)); } -static bool file_panel_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) -{ - const char *prop_id = RNA_property_identifier(prop); - return !(STREQ(prop_id, "filepath") || - STREQ(prop_id, "directory") || - STREQ(prop_id, "filename") - ); -} - static void file_panel_operator(const bContext *C, Panel *pa) { SpaceFile *sfile = CTX_wm_space_file(C); wmOperator *op = sfile->op; - // int empty = 1, flag; UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL); - uiTemplateOperatorPropertyButs(C, pa->layout, op, file_panel_check_prop, '\0', UI_TEMPLATE_OP_PROPS_SHOW_EMPTY); + /* Hack: temporary hide.*/ + const char *hide[3] = {"filepath", "directory", "filename"}; + for (int i = 0; i < ARRAY_SIZE(hide); i++) { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath"); + RNA_def_property_flag(prop, PROP_HIDDEN); + } + + uiTemplateOperatorPropertyButs(C, pa->layout, op, '\0', UI_TEMPLATE_OP_PROPS_SHOW_EMPTY); + + for (int i = 0; i < ARRAY_SIZE(hide); i++) { + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath"); + RNA_def_property_clear_flag(prop, PROP_HIDDEN); + } UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index d9f66ef175a..2a015177dac 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1406,7 +1406,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( return OPERATOR_RUNNING_MODAL; } -static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) +static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); @@ -1425,7 +1425,7 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op) /* main draw call */ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); - uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, image_open_draw_check_prop, NULL, '\0'); /* image template */ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr); @@ -2120,7 +2120,7 @@ static void image_save_as_cancel(bContext *UNUSED(C), wmOperator *op) image_save_as_free(op); } -static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) +static bool image_save_as_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); @@ -2145,7 +2145,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op) /* main draw call */ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); - uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, image_save_as_draw_check_prop, NULL, '\0'); /* multiview template */ if (is_multiview) diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 5c332925011..b3e1d3be42a 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -627,7 +627,7 @@ static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op) op->customdata = NULL; } -static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) +static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); @@ -693,7 +693,7 @@ static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op) /* main draw call */ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); - uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, sequencer_add_draw_check_prop, NULL, '\0'); /* image template */ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr); diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 02634d1b0d1..02136af958b 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -67,7 +67,7 @@ static void view3d_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op) { - uiTemplateOperatorPropertyButs(C, pa->layout, op, NULL, 'V', 0); + uiTemplateOperatorPropertyButs(C, pa->layout, op, 'V', 0); } static void view3d_panel_operator_redo_header(const bContext *C, Panel *pa) diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 3d4080eb600..918188117eb 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -571,6 +571,12 @@ typedef struct wmOperatorType { * that the operator might still fail to execute even if this return true */ bool (*poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT; + /* Use to check of properties should be displayed in auto-generated UI. + * Use 'check' callback to enforce refreshing. */ + bool (*poll_property)( + const struct bContext *C, struct wmOperator *op, + const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT; + /* optional panel for redo and repeat, autogenerated if not set */ void (*ui)(struct bContext *, struct wmOperator *); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index ffa6b0fc371..454d7dc57f0 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -996,13 +996,13 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) if (op->type->flag & OPTYPE_MACRO) { for (op = op->macro.first; op; op = op->next) { - uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); + uiTemplateOperatorPropertyButs(C, layout, op, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); if (op->next) uiItemS(layout); } } else { - uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); + uiTemplateOperatorPropertyButs(C, layout, op, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); } UI_block_bounds_set_popup(block, 4, 0, 0); @@ -1071,7 +1071,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); - uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); + uiTemplateOperatorPropertyButs(C, layout, op, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE); /* clear so the OK button is left alone */ UI_block_func_set(block, NULL, NULL, NULL); @@ -1110,7 +1110,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); /* since ui is defined the auto-layout args are not used */ - uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'V', 0); + uiTemplateOperatorPropertyButs(C, layout, op, 'V', 0); UI_block_func_set(block, NULL, NULL, NULL); -- cgit v1.2.3 From e6c5490323068aad1ab9823f8974dea9ed567df9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 11:13:38 +1000 Subject: UI: hide proportional transform options Adds property poll function to transform. --- source/blender/editors/transform/transform_ops.c | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'source') diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7505a0ba7fe..f8e23c9744d 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -495,6 +495,25 @@ static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event) } } +static bool transform_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + + /* Proportional Editing. */ + { + PropertyRNA *prop_pet = RNA_struct_find_property(op->ptr, "proportional"); + if (prop_pet && (prop_pet != prop) && + (RNA_property_enum_get(op->ptr, prop_pet) == PROP_EDIT_OFF)) + { + if (STRPREFIX(prop_id, "proportional")) { + return false; + } + } + } + + return true; +} + void Transform_Properties(struct wmOperatorType *ot, int flags) { PropertyRNA *prop; @@ -596,6 +615,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; RNA_def_float_vector_xyz(ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); @@ -616,6 +636,7 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); @@ -647,6 +668,7 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = skin_resize_poll; + ot->poll_property = transform_poll_property; RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); @@ -667,6 +689,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; /* Maybe we could use float_vector_xyz here too? */ RNA_def_float_rotation(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX); @@ -688,6 +711,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); @@ -712,6 +736,7 @@ static void TRANSFORM_OT_tilt(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_editcurve_3d; + ot->poll_property = transform_poll_property; RNA_def_float_rotation(ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); @@ -732,6 +757,7 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_region_view3d_active; + ot->poll_property = transform_poll_property; RNA_def_float_rotation(ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2); @@ -752,6 +778,7 @@ static void TRANSFORM_OT_shear(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX); @@ -773,6 +800,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX); @@ -793,6 +821,7 @@ static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_editmesh; + ot->poll_property = transform_poll_property; RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX); @@ -816,6 +845,7 @@ static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1); @@ -836,6 +866,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER); } @@ -856,6 +887,7 @@ static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_editmesh_region_view3d; + ot->poll_property = transform_poll_property; RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); @@ -885,6 +917,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_editmesh_region_view3d; + ot->poll_property = transform_poll_property; RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f); RNA_def_boolean(ot->srna, "use_even", false, "Even", @@ -911,6 +944,7 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_editmesh; + ot->poll_property = transform_poll_property; RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f); @@ -994,6 +1028,7 @@ static void TRANSFORM_OT_transform(struct wmOperatorType *ot) ot->modal = transform_modal; ot->cancel = transform_cancel; ot->poll = ED_operator_screenactive; + ot->poll_property = transform_poll_property; prop = RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", ""); RNA_def_property_flag(prop, PROP_HIDDEN); -- cgit v1.2.3 From 629403fb511089e4545eb6d2248418bf71e0d669 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 14:46:33 +1000 Subject: WM: remove duplicate ui-list functions Missed when moving into own file. Caused issues on MSVC, not GCC. --- source/blender/windowmanager/intern/wm.c | 59 -------------------------------- 1 file changed, 59 deletions(-) (limited to 'source') diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index f92cc511449..7247529d02d 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -223,65 +223,6 @@ void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot) } } -/* ************ uiListType handling ************** */ - -static GHash *uilisttypes_hash = NULL; - -uiListType *WM_uilisttype_find(const char *idname, bool quiet) -{ - uiListType *ult; - - if (idname[0]) { - ult = BLI_ghash_lookup(uilisttypes_hash, idname); - if (ult) { - return ult; - } - } - - if (!quiet) { - printf("search for unknown uilisttype %s\n", idname); - } - - return NULL; -} - -bool WM_uilisttype_add(uiListType *ult) -{ - BLI_ghash_insert(uilisttypes_hash, ult->idname, ult); - return 1; -} - -void WM_uilisttype_freelink(uiListType *ult) -{ - bool ok; - - ok = BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, MEM_freeN); - - BLI_assert(ok); - (void)ok; -} - -/* called on initialize WM_init() */ -void WM_uilisttype_init(void) -{ - uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16); -} - -void WM_uilisttype_free(void) -{ - GHashIterator gh_iter; - - GHASH_ITER (gh_iter, uilisttypes_hash) { - uiListType *ult = BLI_ghashIterator_getValue(&gh_iter); - if (ult->ext.free) { - ult->ext.free(ult->ext.data); - } - } - - BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN); - uilisttypes_hash = NULL; -} - /* ****************************************** */ void WM_keymap_init(bContext *C) -- cgit v1.2.3 From 0dd3b200b06883796ad18bddd53cb97f12c94ee9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 14:58:36 +1000 Subject: Cleanup: remove redundant flag Caller can pass this flag if necessary. --- source/blender/editors/interface/interface_templates.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index e60c64a971f..131ffbca377 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1557,7 +1557,7 @@ static void template_operator_redo_property_buts_draw( eAutoPropButsReturn return_info = uiTemplateOperatorPropertyButs( C, layout, op, UI_BUT_LABEL_ALIGN_NONE, - layout_flags | (r_has_advanced ? UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED : 0)); + layout_flags); if (return_info & UI_PROP_BUTS_ANY_FAILED_CHECK) { if (r_has_advanced) { *r_has_advanced = true; -- cgit v1.2.3 From 44370a307cc77435880793a6420be143004b34f7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 15:44:27 +1000 Subject: UI: hide transform constraints when not used --- source/blender/editors/transform/transform.c | 6 +++++- source/blender/editors/transform/transform_ops.c | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d9e36d0963a..79d06de8b41 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -1999,7 +1999,11 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + /* Only set if needed, so we can hide in the UI when nothing is set. + * See 'transform_poll_property'. */ + if (ELEM(true, UNPACK3(constraint_axis))) { + RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + } } { diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index f8e23c9744d..df118d7a272 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -499,6 +499,17 @@ static bool transform_poll_property(const bContext *UNUSED(C), wmOperator *op, c { const char *prop_id = RNA_property_identifier(prop); + /* Orientation/Constraints. */ + { + /* Hide orientation axis if no constraints are set, since it wont be used. */ + PropertyRNA *prop_con = RNA_struct_find_property(op->ptr, "constraint_axis"); + if (prop_con && !RNA_property_is_set(op->ptr, prop_con)) { + if (STRPREFIX(prop_id, "constraint")) { + return false; + } + } + } + /* Proportional Editing. */ { PropertyRNA *prop_pet = RNA_struct_find_property(op->ptr, "proportional"); -- cgit v1.2.3 From ab67c6e46b689a703c22c6e04f6d098603e3b49c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 17:35:33 +1000 Subject: WM: replace UI draw callbacks w/ property poll Custom drawing functions were used just to control property display. Move to poll function. --- source/blender/editors/gpencil/gpencil_convert.c | 17 +++-------------- source/blender/editors/mesh/editmesh_tools.c | 18 +++--------------- source/blender/editors/object/object_data_transfer.c | 20 ++++---------------- source/blender/editors/object/object_relations.c | 18 +++--------------- 4 files changed, 13 insertions(+), 60 deletions(-) (limited to 'source') diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index d6cb36d7fcd..e0c2e116b8a 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1371,8 +1371,9 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +static bool gp_convert_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) { + PointerRNA *ptr = op->ptr; const char *prop_id = RNA_property_identifier(prop); const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes"); int timing_mode = RNA_enum_get(ptr, "timing_mode"); @@ -1435,18 +1436,6 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void return false; } -static void gp_convert_ui(bContext *C, wmOperator *op) -{ - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - - /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, gp_convert_draw_check_prop, NULL, '\0'); -} - void GPENCIL_OT_convert(wmOperatorType *ot) { PropertyRNA *prop; @@ -1460,7 +1449,7 @@ void GPENCIL_OT_convert(wmOperatorType *ot) ot->invoke = WM_menu_invoke; ot->exec = gp_convert_layer_exec; ot->poll = gp_convert_poll; - ot->ui = gp_convert_ui; + ot->poll_property = gp_convert_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index c5c670b77ea..3e4f8232e62 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -5373,10 +5373,10 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static bool edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +static bool edbm_sort_elements_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); - const int action = RNA_enum_get(ptr, "type"); + const int action = RNA_enum_get(op->ptr, "type"); /* Only show seed for randomize action! */ if (STREQ(prop_id, "seed")) { @@ -5397,18 +5397,6 @@ static bool edbm_sort_elements_draw_check_prop(PointerRNA *ptr, PropertyRNA *pro return true; } -static void edbm_sort_elements_ui(bContext *C, wmOperator *op) -{ - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - - /* Main auto-draw call. */ - uiDefAutoButsRNA(layout, &ptr, edbm_sort_elements_draw_check_prop, NULL, '\0'); -} - void MESH_OT_sort_elements(wmOperatorType *ot) { static const EnumPropertyItem type_items[] = { @@ -5444,7 +5432,7 @@ void MESH_OT_sort_elements(wmOperatorType *ot) ot->invoke = WM_menu_invoke; ot->exec = edbm_sort_elements_exec; ot->poll = ED_operator_editmesh; - ot->ui = edbm_sort_elements_ui; + ot->poll_property = edbm_sort_elements_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 44cca58fc5c..91081345069 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -453,8 +453,9 @@ static bool data_transfer_poll(bContext *C) } /* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ -static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +static bool data_transfer_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) { + PointerRNA *ptr = op->ptr; PropertyRNA *prop_other; const char *prop_id = RNA_property_identifier(prop); @@ -515,19 +516,6 @@ static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, vo return true; } -/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ -static void data_transfer_ui(bContext *C, wmOperator *op) -{ - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - - /* Main auto-draw call */ - uiDefAutoButsRNA(layout, &ptr, data_transfer_draw_check_prop, NULL, '\0'); -} - /* transfers weight from active to selected */ void OBJECT_OT_data_transfer(wmOperatorType *ot) { @@ -540,10 +528,10 @@ void OBJECT_OT_data_transfer(wmOperatorType *ot) /* API callbacks.*/ ot->poll = data_transfer_poll; + ot->poll_property = data_transfer_poll_property; ot->invoke = WM_menu_invoke; ot->exec = data_transfer_exec; ot->check = data_transfer_check; - ot->ui = data_transfer_ui; /* Flags.*/ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -702,10 +690,10 @@ void OBJECT_OT_datalayout_transfer(wmOperatorType *ot) ot->idname = "OBJECT_OT_datalayout_transfer"; ot->poll = datalayout_transfer_poll; + ot->poll_property = data_transfer_poll_property; ot->invoke = datalayout_transfer_invoke; ot->exec = datalayout_transfer_exec; ot->check = data_transfer_check; - ot->ui = data_transfer_ui; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 77b5d35db03..34f64023441 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -938,13 +938,13 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent return OPERATOR_INTERFACE; } -static bool parent_set_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void *UNUSED(user_data)) +static bool parent_set_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); - const int type = RNA_enum_get(ptr, "type"); /* Only show XMirror for PAR_ARMATURE_ENVELOPE and PAR_ARMATURE_AUTO! */ if (STREQ(prop_id, "xmirror")) { + const int type = RNA_enum_get(op->ptr, "type"); if (ELEM(type, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO)) return true; else @@ -954,18 +954,6 @@ static bool parent_set_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop, void return true; } -static void parent_set_ui(bContext *C, wmOperator *op) -{ - uiLayout *layout = op->layout; - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - - /* Main auto-draw call. */ - uiDefAutoButsRNA(layout, &ptr, parent_set_draw_check_prop, NULL, '\0'); -} - void OBJECT_OT_parent_set(wmOperatorType *ot) { /* identifiers */ @@ -977,7 +965,7 @@ void OBJECT_OT_parent_set(wmOperatorType *ot) ot->invoke = parent_set_invoke; ot->exec = parent_set_exec; ot->poll = ED_operator_object_active; - ot->ui = parent_set_ui; + ot->poll_property = parent_set_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -- cgit v1.2.3 From 4d83759f6aad69ccc579bbf302ed2a76d43a3ed1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 26 Jul 2018 19:51:56 +1000 Subject: Cleanup: unused args --- source/blender/blenkernel/intern/subdiv.c | 2 ++ source/blender/editors/transform/transform_snap_object.c | 3 +++ 2 files changed, 5 insertions(+) (limited to 'source') diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c index 0bf969b7de2..d8e0c517d91 100644 --- a/source/blender/blenkernel/intern/subdiv.c +++ b/source/blender/blenkernel/intern/subdiv.c @@ -96,5 +96,7 @@ void BKE_subdiv_free(Subdiv *subdiv) openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner); } MEM_freeN(subdiv); +#else + UNUSED_VARS(subdiv); #endif } diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 4ac4bdfb34d..8b2b80a4239 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -2055,6 +2055,9 @@ static short snapEditMesh( BVHTreeFromEditMesh *treedata_vert = NULL, *treedata_edge = NULL; Object *em_ob = em->ob; + BLI_assert(em_ob->data == ob->data); + UNUSED_VARS_NDEBUG(ob); + void **sod_p; /* Use `em->ob` as the key in ghash since the editmesh is used * to create bvhtree and is the same for each linked object. */ -- cgit v1.2.3 From 1c41dbb079e391a1d684a7dedf40728025ef8839 Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Thu, 26 Jul 2018 14:21:15 +0200 Subject: Fix compiling after ui cleanups --- source/blender/editors/sound/sound_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 356a5f8074b..c3ed2a7b9c2 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -634,7 +634,7 @@ static void sound_mixdown_draw(bContext *C, wmOperator *op) RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); /* main draw call */ - uiDefAutoButsRNA(layout, &ptr, sound_mixdown_draw_check_prop, '\0'); + uiDefAutoButsRNA(layout, &ptr, sound_mixdown_draw_check_prop, NULL, '\0'); } #endif // WITH_AUDASPACE -- cgit v1.2.3 From cb42850ef25ab023a7d4a346a438148c42cb89c9 Mon Sep 17 00:00:00 2001 From: mano-wii Date: Thu, 26 Jul 2018 13:48:26 -0300 Subject: Fix assert in snapEditMesh. --- source/blender/editors/transform/transform_snap_object.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 8b2b80a4239..a6e857c4a60 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -537,6 +537,8 @@ static bool raycastEditMesh( BVHTreeFromEditMesh *treedata = NULL; Object *em_ob = em->ob; + BLI_assert(em_ob->data == BKE_object_get_pre_modified_mesh(ob)); + void **sod_p; /* Use `em->ob` as the key in ghash since the editmesh is used * to create bvhtree and is the same for each linked object. */ @@ -2055,7 +2057,7 @@ static short snapEditMesh( BVHTreeFromEditMesh *treedata_vert = NULL, *treedata_edge = NULL; Object *em_ob = em->ob; - BLI_assert(em_ob->data == ob->data); + BLI_assert(em_ob->data == BKE_object_get_pre_modified_mesh(ob)); UNUSED_VARS_NDEBUG(ob); void **sod_p; -- cgit v1.2.3 From cf080657a1a5ad62121079f93e130ac10fcce18f Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Fri, 27 Jul 2018 02:13:52 +0200 Subject: UI: Tooltip tweaks for Display Mode Keep UI -> Keep User Interface, and don't use the word UI again in the tooltip. --- source/blender/makesrna/intern/rna_scene.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 5637783aa04..915018612a1 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4779,10 +4779,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna) }; static const EnumPropertyItem display_mode_items[] = { - {R_OUTPUT_SCREEN, "SCREEN", 0, "Full Screen", "Images are rendered in full Screen"}, - {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in Image Editor"}, - {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in new Window"}, - {R_OUTPUT_NONE, "NONE", 0, "Keep UI", "Images are rendered without forcing UI changes"}, + {R_OUTPUT_SCREEN, "SCREEN", 0, "Full Screen", "Images are rendered in a maximized Image Editor"}, + {R_OUTPUT_AREA, "AREA", 0, "Image Editor", "Images are rendered in an Image Editor"}, + {R_OUTPUT_WINDOW, "WINDOW", 0, "New Window", "Images are rendered in a new window"}, + {R_OUTPUT_NONE, "NONE", 0, "Keep User Interface", "Images are rendered without changing the user interface"}, {0, NULL, 0, NULL, NULL} }; @@ -4795,7 +4795,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) }; static const EnumPropertyItem pixel_size_items[] = { - {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the UI scale"}, + {0, "AUTO", 0, "Automatic", "Automatic pixel size, depends on the user interface scale"}, {1, "1", 0, "1x", "Render at full resolution"}, {2, "2", 0, "2x", "Render at 50% resolution"}, {4, "4", 0, "4x", "Render at 25% resolution"}, -- cgit v1.2.3 From 71564debf919d9ac99387359e9a07195bf0d94ff Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 27 Jul 2018 10:51:42 +1000 Subject: Fix T56074: Remove doubles creates holes Own regression when moving remove-doubles to kd-tree (seems to happen only in rare cases). --- source/blender/blenlib/intern/BLI_kdtree.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source') diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c index 700000b7717..80a2957d907 100644 --- a/source/blender/blenlib/intern/BLI_kdtree.c +++ b/source/blender/blenlib/intern/BLI_kdtree.c @@ -774,7 +774,12 @@ int BLI_kdtree_calc_duplicates_fast( if (ELEM(duplicates[index], -1, index)) { p.search = index; copy_v3_v3(p.search_co, tree->nodes[node_index].co); + int found_prev = found; deduplicate_recursive(&p, tree->root); + if (found != found_prev) { + /* Prevent chains of doubles. */ + duplicates[index] = index; + } } } MEM_freeN(order); @@ -786,7 +791,12 @@ int BLI_kdtree_calc_duplicates_fast( if (ELEM(duplicates[index], -1, index)) { p.search = index; copy_v3_v3(p.search_co, tree->nodes[node_index].co); + int found_prev = found; deduplicate_recursive(&p, tree->root); + if (found != found_prev) { + /* Prevent chains of doubles. */ + duplicates[index] = index; + } } } } -- cgit v1.2.3 From 98c8094e3a52edaec87bb9f61809e9ae573df430 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 27 Jul 2018 16:41:18 +1000 Subject: Correct arguments for callback --- source/blender/editors/sound/sound_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index c3ed2a7b9c2..b605bd6e1a7 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -481,7 +481,7 @@ static int sound_mixdown_invoke(bContext *C, wmOperator *op, const wmEvent *even #ifdef WITH_AUDASPACE -static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) +static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); return !(STREQ(prop_id, "filepath") || -- cgit v1.2.3 From 3e2dfc6db8e01ffa5e12a8e9b300ef6509a06552 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 27 Jul 2018 16:49:41 +1000 Subject: Fix T55991: Python ignores scene switch argument --- source/creator/creator_args.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'source') diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index b78e76f6ba3..22301bd62f5 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -60,6 +60,8 @@ #include "BKE_sound.h" #include "BKE_image.h" +#include "DNA_screen_types.h" + #include "DEG_depsgraph.h" #ifdef WITH_FFMPEG @@ -1588,6 +1590,16 @@ static int arg_handle_scene_set(int argc, const char **argv, void *data) Scene *scene = BKE_scene_set_name(CTX_data_main(C), argv[1]); if (scene) { CTX_data_scene_set(C, scene); + + /* Set the scene of the first window, see: T55991, + * otherwise scrips that run later won't get this scene back from the context. */ + wmWindow *win = CTX_wm_window(C); + if (win == NULL) { + win = CTX_wm_manager(C)->windows.first; + } + if (win != NULL) { + win->screen->scene = scene; + } } return 1; } -- cgit v1.2.3 From fe8d8aa27e26f1f8e4d5e1e3fcb6fc6288ebf226 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 27 Jul 2018 17:40:01 +1000 Subject: Fix Vector.project crash w/ >4 length vectors --- source/blender/python/mathutils/mathutils_Vector.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'source') diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index a06a63c8067..6a40f22d9df 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -1127,23 +1127,17 @@ PyDoc_STRVAR(Vector_project_doc, static PyObject *Vector_project(VectorObject *self, PyObject *value) { const int size = self->size; - float tvec[MAX_DIMENSIONS]; - float vec[MAX_DIMENSIONS]; + float *tvec; double dot = 0.0f, dot2 = 0.0f; int x; - if (mathutils_array_parse(tvec, size, size, value, "Vector.project(other), invalid 'other' arg") == -1) + if (BaseMath_ReadCallback(self) == -1) return NULL; - if (self->size > 4) { - PyErr_SetString(PyExc_ValueError, - "Vector must be 2D, 3D or 4D"); + if (mathutils_array_parse_alloc(&tvec, size, value, "Vector.project(other), invalid 'other' arg") == -1) { return NULL; } - if (BaseMath_ReadCallback(self) == -1) - return NULL; - /* get dot products */ for (x = 0; x < size; x++) { dot += (double)(self->vec[x] * tvec[x]); @@ -1152,9 +1146,9 @@ static PyObject *Vector_project(VectorObject *self, PyObject *value) /* projection */ dot /= dot2; for (x = 0; x < size; x++) { - vec[x] = (float)dot * tvec[x]; + tvec[x] *= (float)dot; } - return Vector_CreatePyObject(vec, size, Py_TYPE(self)); + return Vector_CreatePyObject_alloc(tvec, size, Py_TYPE(self)); } PyDoc_STRVAR(Vector_lerp_doc, -- cgit v1.2.3 From c6a4b469e3ac8844dfd66ad03cee38a746e0e01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 26 Jul 2018 12:29:16 +0200 Subject: RNA: Set default for Camera properties Change the default clipend value to match the viewport (1000.0f) --- source/blender/blenkernel/intern/camera.c | 2 +- source/blender/makesrna/intern/rna_camera.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 87b65601534..1b5995de4f0 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -70,7 +70,7 @@ void BKE_camera_init(Camera *cam) cam->sensor_x = DEFAULT_SENSOR_WIDTH; cam->sensor_y = DEFAULT_SENSOR_HEIGHT; cam->clipsta = 0.1f; - cam->clipend = 100.0f; + cam->clipend = 1000.0f; cam->drawsize = 0.5f; cam->ortho_scale = 6.0; cam->flag |= CAM_SHOWPASSEPARTOUT; diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 146a8e2738d..8ca45e6dd2d 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -428,6 +428,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "passepartalpha"); + RNA_def_property_float_default(prop, 0.5f); RNA_def_property_ui_text(prop, "Passepartout Alpha", "Opacity (alpha) of the darkened overlay in Camera view"); RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL); @@ -454,6 +455,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipsta"); + RNA_def_property_float_default(prop, 0.1f); RNA_def_property_range(prop, 1e-6f, FLT_MAX); RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance"); @@ -461,6 +463,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipend"); + RNA_def_property_float_default(prop, 1000.0f); RNA_def_property_range(prop, 1e-6f, FLT_MAX); RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance"); @@ -468,6 +471,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "lens", PROP_FLOAT, PROP_DISTANCE_CAMERA); RNA_def_property_float_sdna(prop, NULL, "lens"); + RNA_def_property_float_default(prop, 50.0f); RNA_def_property_range(prop, 1.0f, FLT_MAX); RNA_def_property_ui_range(prop, 1.0f, 5000.0f, 1, 2); RNA_def_property_ui_text(prop, "Focal Length", "Perspective Camera lens value in millimeters"); @@ -475,6 +479,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "sensor_width", PROP_FLOAT, PROP_DISTANCE_CAMERA); RNA_def_property_float_sdna(prop, NULL, "sensor_x"); + RNA_def_property_float_default(prop, 36.0f); RNA_def_property_range(prop, 1.0f, FLT_MAX); RNA_def_property_ui_range(prop, 1.0f, 100.f, 1, 2); RNA_def_property_ui_text(prop, "Sensor Width", "Horizontal size of the image sensor area in millimeters"); @@ -482,6 +487,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "sensor_height", PROP_FLOAT, PROP_DISTANCE_CAMERA); RNA_def_property_float_sdna(prop, NULL, "sensor_y"); + RNA_def_property_float_default(prop, 34.0f); RNA_def_property_range(prop, 1.0f, FLT_MAX); RNA_def_property_ui_range(prop, 1.0f, 100.f, 1, 2); RNA_def_property_ui_text(prop, "Sensor Height", "Vertical size of the image sensor area in millimeters"); @@ -489,6 +495,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "ortho_scale", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "ortho_scale"); + RNA_def_property_float_default(prop, 6.0f); RNA_def_property_range(prop, FLT_MIN, FLT_MAX); RNA_def_property_ui_range(prop, 0.001f, 10000.0f, 10, 3); RNA_def_property_ui_text(prop, "Orthographic Scale", "Orthographic Camera scale (similar to zoom)"); @@ -496,6 +503,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "draw_size", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "drawsize"); + RNA_def_property_float_default(prop, 1.0f); RNA_def_property_range(prop, 0.01f, 1000.0f); RNA_def_property_ui_range(prop, 0.01, 100, 1, 2); RNA_def_property_ui_text(prop, "Draw Size", "Apparent size of the Camera object in the 3D View"); @@ -542,6 +550,7 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "show_passepartout", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWPASSEPARTOUT); + RNA_def_property_boolean_default(prop, true); RNA_def_property_ui_text(prop, "Show Passepartout", "Show a darkened overlay outside the image area in Camera view"); RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL); -- cgit v1.2.3 From bd6d0b94bc17bd0e1a2a89210732a207a0e2b7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 27 Jul 2018 12:15:39 +0200 Subject: Fix T55744: Assertion failure using the Knife angle constraint option --- source/blender/editors/mesh/editmesh_knife.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 99756269c1f..61f55451b17 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1048,14 +1048,15 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void GPU_matrix_push(); GPU_matrix_mul(kcd->ob->obmat); + if (kcd->mode == MODE_DRAGGING && kcd->is_angle_snapping) { + knifetool_draw_angle_snapping(kcd); + } + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); if (kcd->mode == MODE_DRAGGING) { - if (kcd->is_angle_snapping) - knifetool_draw_angle_snapping(kcd); - immUniformColor3ubv(kcd->colors.line); GPU_line_width(2.0); -- cgit v1.2.3 From 141e94f87ff29452ed8df82b4c25d8d134a34dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 27 Jul 2018 13:56:07 +0200 Subject: Fix T55888: Eevee: crash when shadow cube size is > 512px Note that this was only reported to happen on AMD GPU + windows. --- source/blender/gpu/intern/gpu_extensions.c | 7 +++++++ source/blender/gpu/intern/gpu_texture.c | 5 +++++ 2 files changed, 12 insertions(+) (limited to 'source') diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index dff6cfb74a8..43081154e89 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -66,6 +66,7 @@ static struct GPUGlobal { GLint maxtexsize; + GLint maxtexlayers; GLint maxcubemapsize; GLint maxtextures; GLint maxubosize; @@ -96,6 +97,11 @@ int GPU_max_texture_size(void) return GG.maxtexsize; } +int GPU_max_texture_layers(void) +{ + return GG.maxtexlayers; +} + int GPU_max_textures(void) { return GG.maxtextures; @@ -142,6 +148,7 @@ void gpu_extensions_init(void) glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GG.maxtextures); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GG.maxtexsize); + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GG.maxtexlayers); glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GG.maxcubemapsize); if (GLEW_EXT_texture_filter_anisotropic) diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 5ac746ec9c1..f5b52db1c85 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -432,6 +432,11 @@ static bool gpu_texture_try_alloc( glTexImage2D(proxy, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, NULL); break; case GL_PROXY_TEXTURE_2D_ARRAY: + /* HACK: Some driver wrongly check GL_PROXY_TEXTURE_2D_ARRAY as a GL_PROXY_TEXTURE_3D + * checking all dimensions against GPU_max_texture_layers (see T55888). */ + return (tex->w < GPU_max_texture_size()) && + (tex->h < GPU_max_texture_size()) && + (tex->d < GPU_max_texture_layers()); case GL_PROXY_TEXTURE_3D: glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, NULL); break; -- cgit v1.2.3 From 6a05c14a8a24219e43ea82012762e63bd3b2a93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 27 Jul 2018 13:57:46 +0200 Subject: DRW: Fix Race condition in defered compilation --- source/blender/draw/intern/draw_manager_shader.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index b0aec4a7600..b85e6267687 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -72,6 +72,7 @@ typedef struct DRWShaderCompiler { ThreadMutex compilation_lock; void *gl_context; + bool own_context; int shaders_done; /* To compute progress. */ } DRWShaderCompiler; @@ -146,7 +147,7 @@ static void drw_deferred_shader_compilation_free(void *custom_data) BLI_spin_end(&comp->list_lock); BLI_mutex_end(&comp->compilation_lock); - if (comp->gl_context) { + if (comp->own_context) { /* Only destroy if the job owns the context. */ WM_opengl_context_dispose(comp->gl_context); } @@ -189,8 +190,11 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) BLI_movelisttolist(&comp->queue, &old_comp->queue); BLI_spin_unlock(&old_comp->list_lock); /* Do not recreate context, just pass ownership. */ - comp->gl_context = old_comp->gl_context; - old_comp->gl_context = NULL; + if (old_comp->gl_context) { + comp->gl_context = old_comp->gl_context; + old_comp->own_context = false; + comp->own_context = true; + } } BLI_addtail(&comp->queue, dsh); @@ -199,6 +203,7 @@ static void drw_deferred_shader_add(GPUMaterial *mat, bool deferred) if (comp->gl_context == NULL) { comp->gl_context = WM_opengl_context_create(); WM_opengl_context_activate(DST.gl_context); + comp->own_context = true; } WM_jobs_customdata_set(wm_job, comp, drw_deferred_shader_compilation_free); -- cgit v1.2.3 From 0d20207771e76649fcce3766bcfa1634c087caae Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 27 Jul 2018 14:15:45 +0200 Subject: Fix GPU build error after recent commit. --- source/blender/gpu/GPU_extensions.h | 1 + source/blender/gpu/intern/gpu_texture.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'source') diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index d36b0ea15be..f435be7fb34 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -42,6 +42,7 @@ bool GPU_full_non_power_of_two_support(void); bool GPU_bicubic_bump_support(void); int GPU_max_texture_size(void); +int GPU_max_texture_layers(void); int GPU_max_textures(void); float GPU_max_texture_anisotropy(void); int GPU_max_color_texture_samples(void); diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index f5b52db1c85..e5073196a52 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -160,6 +160,8 @@ static int gpu_get_component_count(GPUTextureFormat format) /* Definitely not complete, edit according to the gl specification. */ static void gpu_validate_data_format(GPUTextureFormat tex_format, GPUDataFormat data_format) { + (void)data_format; + if (ELEM(tex_format, GPU_DEPTH_COMPONENT24, GPU_DEPTH_COMPONENT16, -- cgit v1.2.3 From d6ff77878039a5c3848482c6a82ff626d4b3872c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 27 Jul 2018 14:13:47 +0200 Subject: Fix crash enabling disabled collection containing curves. Fixes T55948, T56016, T55926, T55947. Differential Revision: https://developer.blender.org/D3564 --- source/blender/depsgraph/intern/builder/deg_builder.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source') diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 4cbc7700947..8f5925a5ce3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -67,6 +67,12 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) } if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { flag |= DEG_TAG_COPY_ON_WRITE; + /* This means ID is being added to the dependency graph first + * time, which is similar to "ob-visible-change" + */ + if (GS(id->name) == ID_OB) { + flag |= OB_RECALC_OB | OB_RECALC_DATA; + } } if (flag != 0) { DEG_graph_id_tag_update(bmain, -- cgit v1.2.3 From 70966af5134b0cf53273e3c6da19ad7d5857b0f2 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 27 Jul 2018 15:05:46 +0200 Subject: Workbench: option to change background Replaced the draw world option with a shading.background_type enum. Where the user can select Theme, World or a Custom color. World and theme colors do not always work in workbench. We needed to have an option what the user could control locally (per viewport). Especially when using linked data. I removed the world background drawing from the draw_manager. It was never used as EEVEE and Workbench both override the logic. Not 100% sure about the naming of Theme, World, Viewport. In other parts of blender's codebase World is sometimes called Scene. Will stick to the names that describes its location best. {F3990139} Reviewers: fclem, campbellbarton Reviewed By: fclem Subscribers: venomgfx Tags: #bf_blender_2.8 Differential Revision: https://developer.blender.org/D3551 --- source/blender/blenkernel/intern/screen.c | 1 + source/blender/blenloader/intern/versioning_280.c | 14 ++++++++++++ .../draw/engines/workbench/workbench_data.c | 8 ++++++- source/blender/draw/intern/draw_view.c | 11 +-------- source/blender/editors/space_view3d/space_view3d.c | 2 +- source/blender/editors/space_view3d/view3d_draw.c | 2 +- source/blender/makesdna/DNA_view3d_types.h | 17 ++++++++++++-- source/blender/makesrna/intern/rna_space.c | 26 +++++++++++++++++----- source/blender/makesrna/intern/rna_world.c | 3 +++ 9 files changed, 64 insertions(+), 20 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index f8d926a13ed..c107bb04e6e 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -869,6 +869,7 @@ void BKE_screen_view3d_shading_init(View3DShading *shading) shading->cavity_valley_factor = 1.0f; shading->cavity_ridge_factor = 1.0f; copy_v3_fl(shading->single_color, 0.8f); + copy_v3_fl(shading->background_color, 0.05f); } /* magic zoom calculation, no idea what diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 068c12daa94..39ceb527209 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1546,6 +1546,20 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!DNA_struct_elem_find(fd->filesdna, "View3DShadeing", "short", "background_type")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->shading.background_type = (v3d->flag3 & V3D_SHOW_WORLD)? V3D_SHADING_BACKGROUND_WORLD: V3D_SHADING_BACKGROUND_THEME; + copy_v3_fl(v3d->shading.background_color, 0.05f); + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_cubemap_draw_size")) { for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { scene->eevee.gi_irradiance_draw_size = 0.1f; diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 5c3ab5f6688..24eb0f38a46 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -45,10 +45,16 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0; wd->background_alpha = (v3d || scene->r.alphamode == R_ADDSKY) ? 1.0f : 0.0f; - if (!v3d || ((v3d->flag3 & V3D_SHOW_WORLD) && (scene->world != NULL))) { + if (!v3d || ((v3d->shading.background_type & V3D_SHADING_BACKGROUND_WORLD) && + (scene->world != NULL))) + { copy_v3_v3(wd->background_color_low, &scene->world->horr); copy_v3_v3(wd->background_color_high, &scene->world->horr); } + else if (v3d->shading.background_type & V3D_SHADING_BACKGROUND_VIEWPORT) { + copy_v3_v3(wd->background_color_low, v3d->shading.background_color); + copy_v3_v3(wd->background_color_high, v3d->shading.background_color); + } else if (v3d) { UI_GetThemeColor3fv(UI_GetThemeValue(TH_SHOW_BACK_GRAD) ? TH_LOW_GRAD : TH_HIGH_GRAD, wd->background_color_low); UI_GetThemeColor3fv(TH_HIGH_GRAD, wd->background_color_high); diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 05aecea1d7a..95835a691a3 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -561,21 +561,12 @@ void DRW_draw_grid(void) void DRW_draw_background(void) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - /* Just to make sure */ glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilMask(0xFF); - if ((draw_ctx->v3d->flag3 & V3D_SHOW_WORLD) && - (draw_ctx->scene->world != NULL)) - { - const World *world = draw_ctx->scene->world; - glClearColor(world->horr, world->horg, world->horb, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - else if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { + if (UI_GetThemeValue(TH_SHOW_BACK_GRAD)) { float m[4][4]; unit_m4(m); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 71bdd2e20c2..2577077002e 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1406,7 +1406,7 @@ static void space_view3d_listener( switch (wmn->data) { case ND_WORLD_DRAW: case ND_WORLD: - if (v3d->flag3 & V3D_SHOW_WORLD) + if (v3d->shading.background_type & V3D_SHADING_BACKGROUND_WORLD) ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); break; } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 552d84ebb39..941f9262694 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1599,7 +1599,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( v3d.flag2 |= V3D_SOLID_TEX; } - v3d.flag3 |= V3D_SHOW_WORLD; + v3d.shading.background_type = V3D_SHADING_BACKGROUND_WORLD; if (draw_flags & V3D_OFSDRAW_USE_CAMERA_DOF) { if (camera->type == OB_CAMERA) { diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index fedc604f120..bbbaf8bb957 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -142,7 +142,9 @@ typedef struct View3DShading { short color_type; short light; - short pad[3]; + short background_type; + short pad2[2]; + char studio_light[256]; /* FILE_MAXFILE */ char matcap[256]; /* FILE_MAXFILE */ @@ -157,6 +159,10 @@ typedef struct View3DShading { float cavity_valley_factor; float cavity_ridge_factor; + + float background_color[3]; + int pad; + } View3DShading; /* 3D Viewport Overlay setings */ @@ -349,7 +355,7 @@ typedef struct View3D { /* View3d->flag3 (short) */ -#define V3D_SHOW_WORLD (1 << 0) +#define V3D_SHOW_WORLD (1 << 0) /* LEGACY replaced by V3D_SHADING_BACKGROUND_WORLD */ /* View3DShading->light */ enum { @@ -378,6 +384,13 @@ enum { V3D_SHADING_TEXTURE_COLOR = 3, }; +/* View3DShading->background_type */ +enum { + V3D_SHADING_BACKGROUND_THEME = 0, + V3D_SHADING_BACKGROUND_WORLD = 1, + V3D_SHADING_BACKGROUND_VIEWPORT = 2, +}; + /* View3DOverlay->flag */ enum { V3D_OVERLAY_FACE_ORIENTATION = (1 << 0), diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index e670d3c31a5..2f009238851 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2427,6 +2427,15 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + static const EnumPropertyItem background_type_items[] = { + {V3D_SHADING_BACKGROUND_THEME, "THEME", 0, "Theme", "Use the theme for background color"}, + {V3D_SHADING_BACKGROUND_WORLD, "WORLD", 0, "World", "Use the world for background color"}, + {V3D_SHADING_BACKGROUND_VIEWPORT, "VIEWPORT", 0, "Viewport", "Use a custom color limited to this viewport only"}, + {0, NULL, 0, NULL, NULL} + }; + static const float default_background_color[] = {0.05f, 0.05f, 0.05f}; + + /* Note these settings are used for both 3D viewport and the OpenGL render * engine in the scene, so can't assume to always be part of a screen. */ srna = RNA_def_struct(brna, "View3DShading", NULL); @@ -2514,6 +2523,18 @@ static void rna_def_space_view3d_shading(BlenderRNA *brna) RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "background_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, background_type_items); + RNA_def_property_ui_text(prop, "Background", "Way to draw the background"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "background_color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(prop, 3); + RNA_def_property_float_array_default(prop, default_background_color); + RNA_def_property_ui_text(prop, "Background Color", "Color for custom background color"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_shadows", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_SHADING_SHADOW); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); @@ -2957,11 +2978,6 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Lock Camera to View", "Enable view navigation within the camera view"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "show_world", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_SHOW_WORLD); - RNA_def_property_ui_text(prop, "World Background", "Display world colors in the background"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "use_occlude_geometry", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ZBUF_SELECT); RNA_def_property_ui_text(prop, "Occlude Geometry", "Limit selection to visible (clipped with depth buffer)"); diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index f4dc07cf6c3..fe561cdef1c 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -199,6 +199,8 @@ void RNA_def_world(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + static float default_world_color[] = {0.05f, 0.05f, 0.05f}; + srna = RNA_def_struct(brna, "World", "ID"); RNA_def_struct_ui_text(srna, "World", "World data-block describing the environment and ambient lighting of a scene"); @@ -210,6 +212,7 @@ void RNA_def_world(BlenderRNA *brna) prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "horr"); RNA_def_property_array(prop, 3); + RNA_def_property_float_array_default(prop, default_world_color); RNA_def_property_ui_text(prop, "Color", "Color of the background"); /* RNA_def_property_update(prop, 0, "rna_World_update"); */ /* render-only uses this */ -- cgit v1.2.3 From af2a801731441d132b81bd109c999bde3db58a88 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 25 Jul 2018 10:30:11 +0200 Subject: Subsurf: Correction to origindex Only enforce origindex to NONE for a generated geometry. For the rest of geometry rely on CustomData_copy() to set it to the proper value. This will ensure origindex is set correct for cases when there is an array modifier prior to subsurf. --- source/blender/blenkernel/intern/subdiv_mesh.c | 36 +++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index ad2e094fa48..76f41d512bc 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -566,10 +566,10 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) static void subdiv_copy_vertex_data( const SubdivMeshContext *ctx, MVert *subdiv_vertex, - const Mesh *coarse_mesh, + const Mesh *UNUSED(coarse_mesh), const MPoly *coarse_poly, const VerticesForInterpolation *vertex_interpolation, - const int ptex_of_poly_index, + const int UNUSED(ptex_of_poly_index), const float u, const float v) { const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert; @@ -587,27 +587,33 @@ static void subdiv_copy_vertex_data( ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; if (coarse_poly->totloop == 4) { if (u == 0.0f && v == 0.0f) { - ctx->vert_origindex[subdiv_vertex_index] = - vertex_interpolation->vertex_indices[0]; + // ctx->vert_origindex[subdiv_vertex_index] = + // vertex_interpolation->vertex_indices[0]; } else if (u == 1.0f && v == 0.0f) { - ctx->vert_origindex[subdiv_vertex_index] = - vertex_interpolation->vertex_indices[1]; + // ctx->vert_origindex[subdiv_vertex_index] = + // vertex_interpolation->vertex_indices[1]; } else if (u == 1.0f && v == 1.0f) { - ctx->vert_origindex[subdiv_vertex_index] = - vertex_interpolation->vertex_indices[2]; + // ctx->vert_origindex[subdiv_vertex_index] = + // vertex_interpolation->vertex_indices[2]; } else if (u == 0.0f && v == 1.0f) { - ctx->vert_origindex[subdiv_vertex_index] = - vertex_interpolation->vertex_indices[3]; + // ctx->vert_origindex[subdiv_vertex_index] = + // vertex_interpolation->vertex_indices[3]; + } + else { + ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; } } else { if (u == 0.0f && v == 0.0f) { - const MLoop *coarse_mloop = coarse_mesh->mloop; - ctx->vert_origindex[subdiv_vertex_index] = - coarse_mloop[coarse_poly->loopstart + - ptex_of_poly_index].v; + // const MLoop *coarse_mloop = coarse_mesh->mloop; + // ctx->vert_origindex[subdiv_vertex_index] = + // coarse_mloop[coarse_poly->loopstart + + // ptex_of_poly_index].v; + } + else { + ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; } } } @@ -996,7 +1002,7 @@ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, subdiv_poly_index, 1); if (ctx->poly_origindex != NULL) { - ctx->poly_origindex[subdiv_poly_index] = coarse_poly_index; + // ctx->poly_origindex[subdiv_poly_index] = coarse_poly_index; } } -- cgit v1.2.3 From 5c9754c3aa3f2cb9922d76cb73611cd01192895f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 27 Jul 2018 17:33:53 +0200 Subject: Eevee: Fix assert when baking lightprobes. The GPU context was freed before all framebuffer attached to it were deleted. Fix T56117 --- source/blender/draw/engines/eevee/eevee_data.c | 6 +++--- source/blender/draw/engines/eevee/eevee_lightcache.c | 9 +++++++++ source/blender/draw/engines/eevee/eevee_private.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 96e784b524c..636e532555f 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -30,7 +30,7 @@ #include "eevee_private.h" #include "eevee_lightcache.h" -static void eevee_view_layer_data_free(void *storage) +void EEVEE_view_layer_data_free(void *storage) { EEVEE_ViewLayerData *sldata = (EEVEE_ViewLayerData *)storage; @@ -77,7 +77,7 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void) EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer) { EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure_ex( - view_layer, &draw_engine_eevee_type, &eevee_view_layer_data_free); + view_layer, &draw_engine_eevee_type, &EEVEE_view_layer_data_free); if (*sldata == NULL) { *sldata = MEM_callocN(sizeof(**sldata), "EEVEE_ViewLayerData"); @@ -89,7 +89,7 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_laye EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void) { EEVEE_ViewLayerData **sldata = (EEVEE_ViewLayerData **)DRW_view_layer_engine_data_ensure( - &draw_engine_eevee_type, &eevee_view_layer_data_free); + &draw_engine_eevee_type, &EEVEE_view_layer_data_free); if (*sldata == NULL) { *sldata = MEM_callocN(sizeof(**sldata), "EEVEE_ViewLayerData"); diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 4f5ad5159cf..b0b66ee50dc 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -93,6 +93,7 @@ typedef struct EEVEE_LightBake { LightCache *lcache; Scene *scene; struct Main *bmain; + EEVEE_ViewLayerData *sldata; LightProbe **probe; /* Current probe being rendered. */ GPUTexture *rt_color; /* Target cube color texture. */ @@ -597,6 +598,12 @@ static void eevee_lightbake_delete_resources(EEVEE_LightBake *lbake) lbake->lcache = NULL; } + /* XXX Free the resources contained in the viewlayer data + * to be able to free the context before deleting the depsgraph. */ + if (lbake->sldata) { + EEVEE_view_layer_data_free(lbake->sldata); + } + DRW_TEXTURE_FREE_SAFE(lbake->rt_depth); DRW_TEXTURE_FREE_SAFE(lbake->rt_color); DRW_TEXTURE_FREE_SAFE(lbake->grid_prev); @@ -633,6 +640,8 @@ static void eevee_lightbake_cache_create(EEVEE_Data *vedata, EEVEE_LightBake *lb EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); + lbake->sldata = sldata; + /* Disable all effects BUT high bitdepth shadows. */ scene_eval->eevee.flag &= SCE_EEVEE_SHADOW_HIGH_BITDEPTH; scene_eval->eevee.taa_samples = 1; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 5aa331a9b99..349a27a1765 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -777,6 +777,7 @@ typedef struct EEVEE_PrivateData { } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ +void EEVEE_view_layer_data_free(void *sldata); EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure_ex(struct ViewLayer *view_layer); EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void); -- cgit v1.2.3 From bdbc6fafc038afdffdb4d040ea692f15f31a0048 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 27 Jul 2018 17:50:14 +0200 Subject: GPUTexture: Fix wrong texture size check --- source/blender/gpu/intern/gpu_texture.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index e5073196a52..a5dfb6a6b73 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -436,9 +436,9 @@ static bool gpu_texture_try_alloc( case GL_PROXY_TEXTURE_2D_ARRAY: /* HACK: Some driver wrongly check GL_PROXY_TEXTURE_2D_ARRAY as a GL_PROXY_TEXTURE_3D * checking all dimensions against GPU_max_texture_layers (see T55888). */ - return (tex->w < GPU_max_texture_size()) && - (tex->h < GPU_max_texture_size()) && - (tex->d < GPU_max_texture_layers()); + return (tex->w > 0) && (tex->w <= GPU_max_texture_size()) && + (tex->h > 0) && (tex->h <= GPU_max_texture_size()) && + (tex->d > 0) && (tex->d <= GPU_max_texture_layers()); case GL_PROXY_TEXTURE_3D: glTexImage3D(proxy, 0, internalformat, tex->w, tex->h, tex->d, 0, data_format, data_type, NULL); break; -- cgit v1.2.3 From 48759580839aa4e2ad2541ff4c19baaaf751721d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 27 Jul 2018 18:12:02 +0200 Subject: Cleanup: Remove occurances of GPULamp --- source/blender/blenkernel/intern/object.c | 1 - source/blender/blenloader/intern/readfile.c | 1 - source/blender/gpu/GPU_material.h | 1 - source/blender/makesdna/DNA_object_types.h | 1 - 4 files changed, 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 33ea13c9a38..1d6b23ce7f7 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1204,7 +1204,6 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con ob_dst->derivedDeform = NULL; ob_dst->derivedFinal = NULL; - BLI_listbase_clear(&ob_dst->gpulamp); BLI_listbase_clear((ListBase *)&ob_dst->drawdata); BLI_listbase_clear(&ob_dst->pc_ids); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index d76a2fc2cd0..f226693b989 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5545,7 +5545,6 @@ static void direct_link_object(FileData *fd, Object *ob) ob->derivedDeform = NULL; ob->derivedFinal = NULL; BKE_object_runtime_reset(ob); - BLI_listbase_clear(&ob->gpulamp); link_list(fd, &ob->pc_ids); /* Runtime curve data */ diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index f2c029f643e..9fea9eaf4e1 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -55,7 +55,6 @@ struct GPUNodeStack; struct GPUMaterial; struct GPUTexture; struct GPUUniformBuffer; -struct GPULamp; struct PreviewImage; struct World; struct bNode; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 999ebe0ccc3..edc87c492a6 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -283,7 +283,6 @@ typedef struct Object { /* Runtime valuated curve-specific data, not stored in the file */ struct CurveCache *curve_cache; - ListBase gpulamp; /* runtime, for glsl lamp display only */ ListBase pc_ids; struct RigidBodyOb *rigidbody_object; /* settings for Bullet rigid body */ -- cgit v1.2.3 From decd924116d778a524aae49f271f3020e8696ca4 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 26 Jul 2018 17:35:14 +0200 Subject: Fix outliner icon row with counters not correct for nested collections. --- .../blender/editors/space_outliner/outliner_draw.c | 67 +++++++++++----------- 1 file changed, 33 insertions(+), 34 deletions(-) (limited to 'source') diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index e1049d02e37..435e0018ac0 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1441,23 +1441,19 @@ static int tree_element_id_type_to_index(TreeElement *te) } } +typedef struct MergedIconRow { + eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX]; + int num_elements[INDEX_ID_MAX + OB_TYPE_MAX]; + TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX]; +} MergedIconRow; + static void outliner_draw_iconrow( bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, SpaceOops *soops, - ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac) + ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac, MergedIconRow *merged) { eOLDrawState active; const Object *obact = OBACT(view_layer); - struct { - eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX]; - int num_elements[INDEX_ID_MAX + OB_TYPE_MAX]; - TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX]; - } data = { - .active = {0}, - .num_elements = {0}, - .tree_element = {NULL}, - }; - for (TreeElement *te = lb->first; te; te = te->next) { /* exit drawing early */ if ((*offsx) - UI_UNIT_X > xmax) @@ -1488,13 +1484,13 @@ static void outliner_draw_iconrow( } else { const int index = tree_element_id_type_to_index(te); - data.num_elements[index]++; - if ((data.tree_element[index] == NULL) || - (active > data.active[index])) + merged->num_elements[index]++; + if ((merged->tree_element[index] == NULL) || + (active > merged->active[index])) { - data.tree_element[index] = te; + merged->tree_element[index] = te; } - data.active[index] = MAX2(active, data.active[index]); + merged->active[index] = MAX2(active, merged->active[index]); } } @@ -1502,26 +1498,28 @@ static void outliner_draw_iconrow( if (tselem->type != TSE_R_LAYER) { outliner_draw_iconrow( C, block, fstyle, scene, view_layer, soops, - &te->subtree, level + 1, xmax, offsx, ys, alpha_fac); + &te->subtree, level + 1, xmax, offsx, ys, alpha_fac, merged); } } - for (int i = 0; i < INDEX_ID_MAX; i++) { - const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1; - /* See tree_element_id_type_to_index for the index logic. */ - int index_base = i; - if (i > INDEX_ID_OB) { - index_base += OB_TYPE_MAX; - } - for (int j = 0; j < num_subtypes; j++) { - const int index = index_base + j; - if (data.num_elements[index] != 0) { - outliner_draw_iconrow_doit(block, - data.tree_element[index], - fstyle, - xmax, offsx, ys, alpha_fac, - data.active[index], - data.num_elements[index]); + if (level == 0) { + for (int i = 0; i < INDEX_ID_MAX; i++) { + const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1; + /* See tree_element_id_type_to_index for the index logic. */ + int index_base = i; + if (i > INDEX_ID_OB) { + index_base += OB_TYPE_MAX; + } + for (int j = 0; j < num_subtypes; j++) { + const int index = index_base + j; + if (merged->num_elements[index] != 0) { + outliner_draw_iconrow_doit(block, + merged->tree_element[index], + fstyle, + xmax, offsx, ys, alpha_fac, + merged->active[index], + merged->num_elements[index]); + } } } } @@ -1748,9 +1746,10 @@ static void outliner_draw_tree_element( immUnbindProgram(); } + MergedIconRow merged = {{0}}; outliner_draw_iconrow( C, block, fstyle, scene, view_layer, soops, &te->subtree, 0, xmax, &tempx, - *starty, alpha_fac); + *starty, alpha_fac, &merged); GPU_blend(false); } -- cgit v1.2.3 From f50fa4c5d69a50fca880d1abb0b49d06d4745be8 Mon Sep 17 00:00:00 2001 From: Ines Almeida Date: Sat, 28 Jul 2018 22:58:33 +0200 Subject: Fix T56120: Crash on "Install Matcap, World or Camera HDRI" Code was trying to hide properties by name that may not exist. Check if it was actually found and add 'files' to the filter, since it is what WM_OT_studio_lights_install uses. --- source/blender/editors/space_file/file_panels.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index abe9f173b09..cf8a5b9e1f2 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -80,19 +80,24 @@ static void file_panel_operator(const bContext *C, Panel *pa) UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL); /* Hack: temporary hide.*/ - const char *hide[3] = {"filepath", "directory", "filename"}; + const char *hide[4] = {"filepath", "files", "directory", "filename"}; for (int i = 0; i < ARRAY_SIZE(hide); i++) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); + if (prop) { + RNA_def_property_flag(prop, PROP_HIDDEN); + } } uiTemplateOperatorPropertyButs( C, pa->layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_EMPTY); + /* Hack: temporary hide.*/ for (int i = 0; i < ARRAY_SIZE(hide); i++) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath"); - RNA_def_property_clear_flag(prop, PROP_HIDDEN); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); + if (prop) { + RNA_def_property_clear_flag(prop, PROP_HIDDEN); + } } UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL); -- cgit v1.2.3 From 018c9af446de10f038a6e641ca3a61ce451a7c92 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 29 Jul 2018 12:09:00 +1000 Subject: Fix T56120: bad property access (from 2.8) Thanks to @brita_ for the fix. --- source/blender/editors/space_file/file_panels.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index c5350750af4..a40334098d7 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -80,17 +80,21 @@ static void file_panel_operator(const bContext *C, Panel *pa) UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL); /* Hack: temporary hide.*/ - const char *hide[3] = {"filepath", "directory", "filename"}; + const char *hide[] = {"filepath", "directory", "filename", "files"}; for (int i = 0; i < ARRAY_SIZE(hide); i++) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath"); - RNA_def_property_flag(prop, PROP_HIDDEN); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); + if (prop) { + RNA_def_property_flag(prop, PROP_HIDDEN); + } } uiTemplateOperatorPropertyButs(C, pa->layout, op, '\0', UI_TEMPLATE_OP_PROPS_SHOW_EMPTY); for (int i = 0; i < ARRAY_SIZE(hide); i++) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath"); - RNA_def_property_clear_flag(prop, PROP_HIDDEN); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, hide[i]); + if (prop) { + RNA_def_property_clear_flag(prop, PROP_HIDDEN); + } } UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL); -- cgit v1.2.3 From 9c960557a7d2734b3be8cf5f512ef0d8bba54e98 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 30 Jul 2018 15:38:39 +1000 Subject: Cleanup: trailing space --- source/blender/compositor/nodes/COM_CryptomatteNode.cpp | 4 ++-- source/blender/compositor/nodes/COM_CryptomatteNode.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp index 5ed66fe45e7..648ea4556ad 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cpp @@ -100,7 +100,7 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter, const Compos SeparateChannelOperation *separateOperation = new SeparateChannelOperation; separateOperation->setChannel(3); converter.addOperation(separateOperation); - + SetAlphaOperation *operationAlpha = new SetAlphaOperation(); converter.addOperation(operationAlpha); @@ -117,5 +117,5 @@ void CryptomatteNode::convertToOperations(NodeConverter &converter, const Compos converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0)); converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0)); converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0)); - + } diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h index 5251b57d8af..0ee3c1740b3 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.h +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h @@ -35,4 +35,3 @@ public: }; #endif - -- cgit v1.2.3 From f8f4feefb8083e7f5875ae81b678a4c7c3c81660 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 30 Jul 2018 15:40:09 +1000 Subject: Cleanup: trailing space --- source/blender/blenkernel/intern/world.c | 1 - source/blender/draw/engines/eevee/eevee_lightcache.h | 2 +- .../blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl | 2 +- source/blender/editors/space_view3d/view3d_snap.c | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 3e1a9a4f57b..a5a38a6dc12 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -168,4 +168,3 @@ void BKE_world_make_local(Main *bmain, World *wrld, const bool lib_local) { BKE_id_make_local_generic(bmain, &wrld->id, true, lib_local); } - diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h index b58a0544c59..3c6fc73a849 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.h +++ b/source/blender/draw/engines/eevee/eevee_lightcache.h @@ -56,4 +56,4 @@ void EEVEE_lightcache_free(struct LightCache *lcache); void EEVEE_lightcache_load(struct LightCache *lcache); void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee); -#endif /* __EEVEE_LIGHTCACHE_H__ */ \ No newline at end of file +#endif /* __EEVEE_LIGHTCACHE_H__ */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index ba5b78f4ecf..1f14e506dcf 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -178,4 +178,4 @@ void main() length(ls_vol_isect) / length(ls_ray_dir), length(vs_ray_dir) * stepLength); #endif -} \ No newline at end of file +} diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 6a8589f5468..6cb0db94099 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -229,7 +229,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) /** Snaps the selection as a whole (use_offset=true) or each selected object to the given location. * * \param snap_target_global: a location in global space to snap to (eg. 3D cursor or active object). - * \param use_offset: if the selected objects should maintain their relative offsets and be snapped by the selection + * \param use_offset: if the selected objects should maintain their relative offsets and be snapped by the selection * pivot point (median, active), or if every object origin should be snapped to the given location. **/ static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset) -- cgit v1.2.3 From f4379f8b914eaf7aa1f17323f927836a3d9288fc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 30 Jul 2018 16:16:44 +1000 Subject: Use Ctrl Snap to seconds w/ play-head drag D3056 by @alourenco --- source/blender/blenkernel/BKE_scene.h | 2 ++ source/blender/blenkernel/intern/scene.c | 10 ++++++++++ source/blender/editors/animation/anim_ops.c | 10 ++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index ae809641480..e85867fcbe7 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -114,6 +114,8 @@ int BKE_scene_camera_switch_update(struct Scene *scene); char *BKE_scene_find_marker_name(struct Scene *scene, int frame); char *BKE_scene_find_last_marker_name(struct Scene *scene, int frame); +int BKE_scene_frame_snap_by_seconds(struct Scene *scene, double interval_in_seconds, int cfra); + /* checks for cycle, returns 1 if it's all OK */ bool BKE_scene_validate_setscene(struct Main *bmain, struct Scene *sce); diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a1003910ca3..1eb65519596 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1204,6 +1204,16 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame) return best_marker ? best_marker->name : NULL; } +int BKE_scene_frame_snap_by_seconds(Scene *scene, double interval_in_seconds, int cfra) +{ + const int fps = round_db_to_int(FPS * interval_in_seconds); + const int second_prev = cfra - mod_i(cfra, fps); + const int second_next = second_prev + fps; + const int delta_prev = cfra - second_prev; + const int delta_next = second_next - cfra; + return (delta_prev < delta_next) ? second_prev : second_next; +} + Base *BKE_scene_base_add(Scene *sce, Object *ob) { diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 8612f5944bb..939d547dc94 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -45,6 +45,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_sound.h" +#include "BKE_scene.h" #include "UI_view2d.h" @@ -98,8 +99,13 @@ static void change_frame_apply(bContext *C, wmOperator *op) float frame = RNA_float_get(op->ptr, "frame"); bool do_snap = RNA_boolean_get(op->ptr, "snap"); - if (do_snap && CTX_wm_space_seq(C)) { - frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); + if (do_snap) { + if (CTX_wm_space_seq(C)) { + frame = BKE_sequencer_find_next_prev_edit(scene, frame, SEQ_SIDE_BOTH, true, false, false); + } + else { + frame = BKE_scene_frame_snap_by_seconds(scene, 1.0, frame); + } } /* set the new frame number */ -- cgit v1.2.3 From ff6c6f18c1591a213d6dffb266b9f2136ef09c3b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 30 Jul 2018 16:36:07 +1000 Subject: Cleanup: id-property creation D3473 by @JacquesLucke --- source/blender/python/generic/idprop_py_api.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 4b56d4412e6..4d4d5232800 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -596,15 +596,15 @@ static IDProperty *idp_from_PyMapping(const char *name, PyObject *ob) return prop; } -static IDProperty *idp_from_DatablockPointer(const char *name, PyObject *ob, IDPropertyTemplate *val) +static IDProperty *idp_from_DatablockPointer(const char *name, PyObject *ob) { - pyrna_id_FromPyObject(ob, &val->id); - return IDP_New(IDP_ID, val, name); + IDPropertyTemplate val = {0}; + pyrna_id_FromPyObject(ob, &val.id); + return IDP_New(IDP_ID, &val, name); } static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob) { - IDPropertyTemplate val = {0}; const char *name = idp_try_read_name(name_obj); if (name == NULL) { return NULL; @@ -626,7 +626,7 @@ static IDProperty *idp_from_PyObject(PyObject *name_obj, PyObject *ob) return idp_from_PySequence(name, ob); } else if (ob == Py_None || pyrna_id_CheckPyObject(ob)) { - return idp_from_DatablockPointer(name, ob, &val); + return idp_from_DatablockPointer(name, ob); } else if (PyMapping_Check(ob)) { return idp_from_PyMapping(name, ob); -- cgit v1.2.3 From 914e4d121263ae02dd33f27827417316726778d7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 30 Jul 2018 20:53:34 +1000 Subject: Fix T56152: Rotate crash w/ individual origins --- source/blender/editors/transform/transform_constraints.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index c8f74cbcd4f..b24ef4e0ba2 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -560,7 +560,9 @@ static void applyObjectConstraintRot( /* on setup call, use first object */ if (td == NULL) { - td = TRANS_DATA_CONTAINER_FIRST_OK(t)->data; + BLI_assert(tc == NULL); + tc = TRANS_DATA_CONTAINER_FIRST_OK(t); + td = tc->data; } if (t->flag & T_EDIT) { -- cgit v1.2.3 From bd49a765689a8abfb6662c0b748268d24b1b3d2a Mon Sep 17 00:00:00 2001 From: mano-wii Date: Mon, 30 Jul 2018 08:49:27 -0300 Subject: Fix T56121 and maybe others: DST.gpu_context was being created in the wrong DST.gl_context. In addition to the crash in the selection of bones, this was responsible for other problems such as wrong hair and disappearing objects. --- source/blender/draw/intern/draw_manager.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source') diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index cc4f8ec7947..0a15fb3a114 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2351,6 +2351,7 @@ void DRW_opengl_context_create(void) } /* This changes the active context. */ DST.gl_context = WM_opengl_context_create(); + WM_opengl_context_activate(DST.gl_context); /* Be sure to create gawain.context too. */ DST.gpu_context = GPU_context_create(); if (!G.background) { -- cgit v1.2.3 From d01319df76496d2ded7643d5b38be394e5e29a0b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 30 Jul 2018 12:22:18 +0200 Subject: Shape keys: change default interpolation for absolute shape keys to linear. --- source/blender/blenkernel/intern/key.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 13f7716cd80..0d8e281fa06 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -1457,7 +1457,7 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name) kb = MEM_callocN(sizeof(KeyBlock), "Keyblock"); BLI_addtail(&key->block, kb); - kb->type = KEY_CARDINAL; + kb->type = KEY_LINEAR; tot = BLI_listbase_count(&key->block); if (name) { -- cgit v1.2.3 From d65df10216b8de09b8a1cfc695030649511337a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 30 Jul 2018 12:23:23 +0200 Subject: DRW: Add DRW_shgroup_is_empty and DRW_pass_is_empty --- source/blender/draw/intern/DRW_render.h | 4 ++++ source/blender/draw/intern/draw_manager_data.c | 27 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'source') diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index adcfe2524c7..cd2db3cfd0a 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -402,6 +402,8 @@ void DRW_shgroup_uniform_int_copy(DRWShadingGroup *shgroup, const char *name, co void DRW_shgroup_uniform_bool_copy(DRWShadingGroup *shgroup, const char *name, const bool value); void DRW_shgroup_uniform_float_copy(DRWShadingGroup *shgroup, const char *name, const float value); +bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup); + /* Passes */ DRWPass *DRW_pass_create(const char *name, DRWState state); void DRW_pass_state_set(DRWPass *pass, DRWState state); @@ -410,6 +412,8 @@ void DRW_pass_state_remove(DRWPass *pass, DRWState state); void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData); void DRW_pass_sort_shgroup_z(DRWPass *pass); +bool DRW_pass_is_empty(DRWPass *pass); + /* Viewport */ typedef enum { /* keep in sync with the union struct DRWMatrixState. */ diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index dccb869c133..407eea16d91 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -998,6 +998,23 @@ void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask) shgroup->stencil_mask = mask; } +bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup) +{ + switch (shgroup->type) { + case DRW_SHG_NORMAL: + case DRW_SHG_FEEDBACK_TRANSFORM: + return shgroup->calls.first == NULL; + case DRW_SHG_POINT_BATCH: + case DRW_SHG_LINE_BATCH: + case DRW_SHG_TRIANGLE_BATCH: + case DRW_SHG_INSTANCE: + case DRW_SHG_INSTANCE_EXTERNAL: + return shgroup->instance_count == 0; + } + BLI_assert(!"Shading Group type not supported"); + return true; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1019,6 +1036,16 @@ DRWPass *DRW_pass_create(const char *name, DRWState state) return pass; } +bool DRW_pass_is_empty(DRWPass *pass) +{ + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + if (!DRW_shgroup_is_empty(shgroup)) { + return false; + } + } + return true; +} + void DRW_pass_state_set(DRWPass *pass, DRWState state) { pass->state = state; -- cgit v1.2.3 From 0f97718c10e8c2a441f58a51eb923b1dfa3698d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 30 Jul 2018 13:56:22 +0200 Subject: DRW: Add option to only resolve framebuffer colors without depth test --- source/blender/draw/intern/DRW_render.h | 13 +++++- source/blender/draw/intern/draw_manager.c | 49 ++++++++++++++------ source/blender/gpu/GPU_shader.h | 4 ++ source/blender/gpu/intern/gpu_shader.c | 20 ++++++++ .../gpu_shader_image_multisample_resolve_frag.glsl | 53 ++++++++++++---------- 5 files changed, 98 insertions(+), 41 deletions(-) (limited to 'source') diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index cd2db3cfd0a..d2c44cfef2a 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -120,7 +120,16 @@ typedef char DRWViewportEmptyList; if (dfbl->multisample_fb != NULL) { \ DRW_stats_query_start("Multisample Resolve"); \ GPU_framebuffer_bind(dfbl->default_fb); \ - DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color); \ + DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, true); \ + DRW_stats_query_end(); \ + } \ +} + +#define MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl) { \ + if (dfbl->multisample_fb != NULL) { \ + DRW_stats_query_start("Multisample Resolve"); \ + GPU_framebuffer_bind(dfbl->default_fb); \ + DRW_multisamples_resolve(dtxl->multisample_depth, dtxl->multisample_color, false); \ DRW_stats_query_end(); \ } \ } @@ -228,7 +237,7 @@ void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo); void DRW_transform_to_display(struct GPUTexture *tex); void DRW_transform_none(struct GPUTexture *tex); void DRW_multisamples_resolve( - struct GPUTexture *src_depth, struct GPUTexture *src_color); + struct GPUTexture *src_depth, struct GPUTexture *src_color, bool use_depth); /* Shaders */ struct GPUShader *DRW_shader_create( diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 0a15fb3a114..87239e7d93e 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -317,10 +317,14 @@ void DRW_transform_none(GPUTexture *tex) /* Use manual multisample resolve pass. * Much quicker than blitting back and forth. * Assume destination fb is bound*/ -void DRW_multisamples_resolve(GPUTexture *src_depth, GPUTexture *src_color) +void DRW_multisamples_resolve(GPUTexture *src_depth, GPUTexture *src_color, bool use_depth) { - drw_state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_PREMUL | - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_PREMUL; + + if (use_depth) { + state |= DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + } + drw_state_set(state); int samples = GPU_texture_samples(src_depth); @@ -330,22 +334,39 @@ void DRW_multisamples_resolve(GPUTexture *src_depth, GPUTexture *src_color) GPUBatch *geom = DRW_cache_fullscreen_quad_get(); int builtin; - switch (samples) { - case 2: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2; break; - case 4: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_4; break; - case 8: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_8; break; - case 16: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_16; break; - default: - BLI_assert(0); - builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2; - break; + if (use_depth) { + switch (samples) { + case 2: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST; break; + case 4: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST; break; + case 8: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST; break; + case 16: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST; break; + default: + BLI_assert("Mulisample count unsupported by blit shader."); + builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST; + break; + } + } + else { + switch (samples) { + case 2: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2; break; + case 4: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_4; break; + case 8: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_8; break; + case 16: builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_16; break; + default: + BLI_assert("Mulisample count unsupported by blit shader."); + builtin = GPU_SHADER_2D_IMAGE_MULTISAMPLE_2; + break; + } } GPU_batch_program_set_builtin(geom, builtin); - GPU_texture_bind(src_depth, 0); + if (use_depth) { + GPU_texture_bind(src_depth, 0); + GPU_batch_uniform_1i(geom, "depthMulti", 0); + } + GPU_texture_bind(src_color, 1); - GPU_batch_uniform_1i(geom, "depthMulti", 0); GPU_batch_uniform_1i(geom, "colorMulti", 1); float mat[4][4]; diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index b1a05faf863..7f334cec21f 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -158,6 +158,10 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_IMAGE_MULTISAMPLE_4, GPU_SHADER_2D_IMAGE_MULTISAMPLE_8, GPU_SHADER_2D_IMAGE_MULTISAMPLE_16, + GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST, + GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST, + GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST, + GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST, GPU_SHADER_2D_CHECKER, GPU_SHADER_2D_DIAG_STRIPES, /* for simple 3D drawing */ diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 04b43d03c83..3543c73f71d 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -738,6 +738,10 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, + [GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST] = { datatoc_gpu_shader_2D_vert_glsl, datatoc_gpu_shader_image_multisample_resolve_frag_glsl }, [GPU_SHADER_2D_IMAGE_INTERLACE] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_interlace_frag_glsl }, @@ -873,15 +877,31 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) case GPU_SHADER_2D_IMAGE_MULTISAMPLE_2: defines = "#define SAMPLES 2\n"; break; + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_2_DEPTH_TEST: + defines = "#define SAMPLES 2\n" + "#define USE_DEPTH\n"; + break; case GPU_SHADER_2D_IMAGE_MULTISAMPLE_4: defines = "#define SAMPLES 4\n"; break; + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_4_DEPTH_TEST: + defines = "#define SAMPLES 4\n" + "#define USE_DEPTH\n"; + break; case GPU_SHADER_2D_IMAGE_MULTISAMPLE_8: defines = "#define SAMPLES 8\n"; break; + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_8_DEPTH_TEST: + defines = "#define SAMPLES 8\n" + "#define USE_DEPTH\n"; + break; case GPU_SHADER_2D_IMAGE_MULTISAMPLE_16: defines = "#define SAMPLES 16\n"; break; + case GPU_SHADER_2D_IMAGE_MULTISAMPLE_16_DEPTH_TEST: + defines = "#define SAMPLES 16\n" + "#define USE_DEPTH\n"; + break; case GPU_SHADER_2D_WIDGET_BASE_INST: case GPU_SHADER_2D_NODELINK_INST: defines = "#define USE_INSTANCE\n"; diff --git a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl index 57362c88320..1f59c9dfdbd 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_multisample_resolve_frag.glsl @@ -8,8 +8,6 @@ out vec4 fragColor; #error "Too many samples" #endif -// #define USE_DEPTH_WEIGHTING - void main() { ivec2 texel = ivec2(gl_FragCoord.xy); @@ -19,26 +17,26 @@ void main() vec4 d1, d2, d3, d4; vec4 c1, c2, c3, c4, c5, c6, c7, c8; vec4 c9, c10, c11, c12, c13, c14, c15, c16; - d1 = d2 = d3 = d4 = vec4(1.0); + d1 = d2 = d3 = d4 = vec4(0.5); w1 = w2 = w3 = w4 = vec4(0.0); c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = vec4(0.0); c9 = c10 = c11 = c12 = c13 = c14 = c15 = c16 = vec4(0.0); +#ifdef USE_DEPTH /* Depth */ - d1.x = texelFetch(depthMulti, texel, 0).r; d1.y = texelFetch(depthMulti, texel, 1).r; -#if SAMPLES > 2 +# if SAMPLES > 2 d1.z = texelFetch(depthMulti, texel, 2).r; d1.w = texelFetch(depthMulti, texel, 3).r; -#endif -#if SAMPLES > 4 +# endif +# if SAMPLES > 4 d2.x = texelFetch(depthMulti, texel, 4).r; d2.y = texelFetch(depthMulti, texel, 5).r; d2.z = texelFetch(depthMulti, texel, 6).r; d2.w = texelFetch(depthMulti, texel, 7).r; -#endif -#if SAMPLES > 8 +# endif +# if SAMPLES > 8 d3.x = texelFetch(depthMulti, texel, 8).r; d3.y = texelFetch(depthMulti, texel, 9).r; d3.z = texelFetch(depthMulti, texel, 10).r; @@ -47,6 +45,7 @@ void main() d4.y = texelFetch(depthMulti, texel, 13).r; d4.z = texelFetch(depthMulti, texel, 14).r; d4.w = texelFetch(depthMulti, texel, 15).r; +# endif #endif /* COLOR */ @@ -89,22 +88,26 @@ void main() } #endif -#if SAMPLES > 8 - d1 = min(d1, min(d3, d4)); -#endif -#if SAMPLES > 4 - d1 = min(d1, d2); -#endif -#if SAMPLES > 2 - d1.xy = min(d1.xy, d1.zw); -#endif - gl_FragDepth = min(d1.x, d1.y); - -#ifdef USE_DEPTH_WEIGHTING - c1 *= w1.x; c2 *= w1.y; c3 *= w1.z; c4 *= w1.w; - c5 *= w2.x; c6 *= w2.y; c7 *= w2.z; c8 *= w2.w; - c9 *= w3.x; c10 *= w3.y; c11 *= w3.z; c12 *= w3.w; - c13 *= w4.x; c14 *= w4.y; c15 *= w4.z; c16 *= w4.w; +#ifdef USE_DEPTH + d1 *= 1.0 - step(1.0, d1); /* make far plane depth = 0 */ +# if SAMPLES > 8 + d4 *= 1.0 - step(1.0, d4); + d3 *= 1.0 - step(1.0, d3); + d1 = max(d1, max(d3, d4)); +# endif +# if SAMPLES > 4 + d2 *= 1.0 - step(1.0, d2); + d1 = max(d1, d2); + d1 = max(d1, d2); +# endif +# if SAMPLES > 2 + d1.xy = max(d1.xy, d1.zw); +# endif + gl_FragDepth = max(d1.x, d1.y); + /* Don't let the 0.0 farplane occlude other things */ + if (gl_FragDepth == 0.0) { + gl_FragDepth = 1.0; + } #endif c1 = c1 + c2; -- cgit v1.2.3 From 5a05683da1a9fd43cd611fe62f675ddafc8ba3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 30 Jul 2018 14:15:40 +0200 Subject: Motion Path: Fix motion path when MSAA is enabled --- source/blender/draw/intern/draw_anim_viz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c index 95894783cfe..6bf7bf9ca08 100644 --- a/source/blender/draw/intern/draw_anim_viz.c +++ b/source/blender/draw/intern/draw_anim_viz.c @@ -327,7 +327,7 @@ static void MPATH_draw_scene(void *vedata) DRW_draw_pass(psl->lines); DRW_draw_pass(psl->points); - MULTISAMPLE_SYNC_DISABLE(dfbl, dtxl) + MULTISAMPLE_SYNC_DISABLE_NO_DEPTH(dfbl, dtxl) } /* *************************** Draw Engine Defines ****************************** */ -- cgit v1.2.3 From 6c6ecdd2306b9680ac171b9b80d4a9911fdb8a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 30 Jul 2018 14:17:53 +0200 Subject: Armature: Fix bone always transparent when enabling MSAA --- source/blender/draw/intern/draw_armature.c | 29 +++++++++++++--------- source/blender/draw/intern/draw_common.c | 10 +++++--- source/blender/draw/intern/draw_common.h | 10 ++++---- source/blender/draw/modes/edit_armature_mode.c | 25 +++++++++++-------- source/blender/draw/modes/pose_mode.c | 12 +++++---- .../shaders/armature_envelope_solid_frag.glsl | 4 ++- .../modes/shaders/armature_shape_solid_frag.glsl | 4 ++- .../modes/shaders/armature_sphere_solid_frag.glsl | 4 +-- 8 files changed, 58 insertions(+), 40 deletions(-) (limited to 'source') diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index f0a32dfc8e0..8cd7431cfc0 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -95,6 +95,8 @@ static struct { DRWShadingGroup *lines_ik_spline; DRWArmaturePasses passes; + + bool transparent; } g_data = {NULL}; @@ -139,7 +141,8 @@ static void drw_shgroup_bone_octahedral( } if (g_data.bone_octahedral_solid == NULL) { struct GPUBatch *geom = DRW_cache_bone_octahedral_get(); - g_data.bone_octahedral_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom); + g_data.bone_octahedral_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom, + g_data.transparent); } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); @@ -160,7 +163,7 @@ static void drw_shgroup_bone_box( } if (g_data.bone_box_solid == NULL) { struct GPUBatch *geom = DRW_cache_bone_box_get(); - g_data.bone_box_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom); + g_data.bone_box_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, geom, g_data.transparent); } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); @@ -234,13 +237,13 @@ static void drw_shgroup_bone_envelope( g_data.bone_point_wire = shgroup_instance_bone_sphere_outline(g_data.passes.bone_wire); } if (g_data.bone_point_solid == NULL) { - g_data.bone_point_solid = shgroup_instance_bone_sphere_solid(g_data.passes.bone_solid); + g_data.bone_point_solid = shgroup_instance_bone_sphere_solid(g_data.passes.bone_solid, g_data.transparent); } if (g_data.bone_envelope_wire == NULL) { g_data.bone_envelope_wire = shgroup_instance_bone_envelope_outline(g_data.passes.bone_wire); } if (g_data.bone_envelope_solid == NULL) { - g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.passes.bone_solid); + g_data.bone_envelope_solid = shgroup_instance_bone_envelope_solid(g_data.passes.bone_solid, g_data.transparent); /* We can have a lot of overdraw if we don't do this. Also envelope are not subject to * inverted matrix. */ DRW_shgroup_state_enable(g_data.bone_envelope_solid, DRW_STATE_CULL_BACK); @@ -329,7 +332,8 @@ static void drw_shgroup_bone_custom_solid( } if (surf) { - DRWShadingGroup *shgrp_geom_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, surf); + DRWShadingGroup *shgrp_geom_solid = shgroup_instance_bone_shape_solid(g_data.passes.bone_solid, surf, + g_data.transparent); DRW_shgroup_call_dynamic_add(shgrp_geom_solid, final_bonemat, bone_color, hint_color); } @@ -372,7 +376,7 @@ static void drw_shgroup_bone_point( g_data.bone_point_wire = shgroup_instance_bone_sphere_outline(g_data.passes.bone_wire); } if (g_data.bone_point_solid == NULL) { - g_data.bone_point_solid = shgroup_instance_bone_sphere_solid(g_data.passes.bone_solid); + g_data.bone_point_solid = shgroup_instance_bone_sphere_solid(g_data.passes.bone_solid, g_data.transparent); } float final_bonemat[4][4]; mul_m4_m4m4(final_bonemat, g_data.ob->obmat, bone_mat); @@ -1732,11 +1736,12 @@ static void draw_armature_pose(Object *ob, const float const_color[4]) /** * This function set the object space to use for all subsequent `DRW_shgroup_bone_*` calls. */ -static void drw_shgroup_armature(Object *ob, DRWArmaturePasses passes) +static void drw_shgroup_armature(Object *ob, DRWArmaturePasses passes, bool transp) { memset(&g_data, 0x0, sizeof(g_data)); g_data.ob = ob; g_data.passes = passes; + g_data.transparent = transp; memset(&g_color, 0x0, sizeof(g_color)); } @@ -1745,19 +1750,19 @@ void DRW_shgroup_armature_object(Object *ob, ViewLayer *view_layer, DRWArmatureP float *color; DRW_object_wire_theme_get(ob, view_layer, &color); passes.bone_envelope = NULL; /* Don't do envelope distance in object mode. */ - drw_shgroup_armature(ob, passes); + drw_shgroup_armature(ob, passes, false); draw_armature_pose(ob, color); } -void DRW_shgroup_armature_pose(Object *ob, DRWArmaturePasses passes) +void DRW_shgroup_armature_pose(Object *ob, DRWArmaturePasses passes, bool transp) { - drw_shgroup_armature(ob, passes); + drw_shgroup_armature(ob, passes, transp); draw_armature_pose(ob, NULL); } -void DRW_shgroup_armature_edit(Object *ob, DRWArmaturePasses passes) +void DRW_shgroup_armature_edit(Object *ob, DRWArmaturePasses passes, bool transp) { - drw_shgroup_armature(ob, passes); + drw_shgroup_armature(ob, passes, transp); draw_armature_edit(ob); } diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index c9fc5eba079..77d6e888771 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -552,7 +552,7 @@ DRWShadingGroup *shgroup_instance_bone_envelope_distance(DRWPass *pass) return grp; } -DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass) +DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, bool transp) { if (g_shaders.bone_envelope == NULL) { g_shaders.bone_envelope = DRW_shader_create( @@ -572,6 +572,7 @@ DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass) g_shaders.bone_envelope, pass, DRW_cache_bone_envelope_solid_get(), g_formats.instance_bone_envelope); + DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f); return grp; } @@ -623,7 +624,7 @@ DRWShadingGroup *shgroup_instance_bone_shape_outline(DRWPass *pass, struct GPUBa return grp; } -DRWShadingGroup *shgroup_instance_bone_shape_solid(DRWPass *pass, struct GPUBatch *geom) +DRWShadingGroup *shgroup_instance_bone_shape_solid(DRWPass *pass, struct GPUBatch *geom, bool transp) { if (g_shaders.shape_solid == NULL) { g_shaders.shape_solid = DRW_shader_create( @@ -641,11 +642,12 @@ DRWShadingGroup *shgroup_instance_bone_shape_solid(DRWPass *pass, struct GPUBatc g_shaders.shape_solid, pass, geom, g_formats.instance_bone); DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); + DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.6f : 1.0f); return grp; } -DRWShadingGroup *shgroup_instance_bone_sphere_solid(DRWPass *pass) +DRWShadingGroup *shgroup_instance_bone_sphere_solid(DRWPass *pass, bool transp) { if (g_shaders.bone_sphere == NULL) { g_shaders.bone_sphere = DRW_shader_create( @@ -662,6 +664,8 @@ DRWShadingGroup *shgroup_instance_bone_sphere_solid(DRWPass *pass) DRWShadingGroup *grp = DRW_shgroup_instance_create( g_shaders.bone_sphere, pass, DRW_cache_bone_point_get(), g_formats.instance_bone); + /* More transparent than the shape to be less distractive. */ + DRW_shgroup_uniform_float_copy(grp, "alpha", transp ? 0.4f : 1.0f); return grp; } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 80b2ec8db71..0ad1402f29e 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -128,11 +128,11 @@ struct DRWShadingGroup *shgroup_instance_mball_handles(struct DRWPass *pass); struct DRWShadingGroup *shgroup_instance_bone_axes(struct DRWPass *pass); struct DRWShadingGroup *shgroup_instance_bone_envelope_distance(struct DRWPass *pass); struct DRWShadingGroup *shgroup_instance_bone_envelope_outline(struct DRWPass *pass); -struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass); +struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, bool transp); struct DRWShadingGroup *shgroup_instance_bone_shape_outline(struct DRWPass *pass, struct GPUBatch *geom); -struct DRWShadingGroup *shgroup_instance_bone_shape_solid(struct DRWPass *pass, struct GPUBatch *geom); +struct DRWShadingGroup *shgroup_instance_bone_shape_solid(struct DRWPass *pass, struct GPUBatch *geom, bool transp); struct DRWShadingGroup *shgroup_instance_bone_sphere_outline(struct DRWPass *pass); -struct DRWShadingGroup *shgroup_instance_bone_sphere_solid(struct DRWPass *pass); +struct DRWShadingGroup *shgroup_instance_bone_sphere_solid(struct DRWPass *pass, bool transp); struct DRWShadingGroup *shgroup_instance_bone_stick(struct DRWPass *pass); struct GPUShader *mpath_line_shader_get(void); @@ -155,8 +155,8 @@ typedef struct DRWArmaturePasses { } DRWArmaturePasses; void DRW_shgroup_armature_object(struct Object *ob, struct ViewLayer *view_layer, struct DRWArmaturePasses passes); -void DRW_shgroup_armature_pose(struct Object *ob, struct DRWArmaturePasses passes); -void DRW_shgroup_armature_edit(struct Object *ob, struct DRWArmaturePasses passes); +void DRW_shgroup_armature_pose(struct Object *ob, struct DRWArmaturePasses passes, bool transp); +void DRW_shgroup_armature_edit(struct Object *ob, struct DRWArmaturePasses passes, bool transp); /* draw_hair.c */ diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c index 285e703afbf..1e8293b5dbb 100644 --- a/source/blender/draw/modes/edit_armature_mode.c +++ b/source/blender/draw/modes/edit_armature_mode.c @@ -60,7 +60,7 @@ typedef struct EDIT_ARMATURE_Data { /* *********** STATIC *********** */ typedef struct EDIT_ARMATURE_PrivateData { - char pad; /* UNUSED */ + bool transparent_bones; } EDIT_ARMATURE_PrivateData; /* Transient data */ /* *********** FUNCTIONS *********** */ @@ -69,15 +69,18 @@ static void EDIT_ARMATURE_cache_init(void *vedata) { EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl; EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); if (!stl->g_data) { /* Alloc transient pointers */ - stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); + stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); } + stl->g_data->transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0; { /* Solid bones */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_CULL_BACK; + state |= (stl->g_data->transparent_bones) ? DRW_STATE_BLEND : DRW_STATE_WRITE_DEPTH; psl->bone_solid = DRW_pass_create("Bone Solid Pass", state); } @@ -116,10 +119,12 @@ static void EDIT_ARMATURE_cache_init(void *vedata) static void EDIT_ARMATURE_cache_populate(void *vedata, Object *ob) { bArmature *arm = ob->data; - EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl; if (ob->type == OB_ARMATURE) { if (arm->edbo) { + EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl; + EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl; + DRWArmaturePasses passes = { .bone_solid = psl->bone_solid, .bone_outline = psl->bone_outline, @@ -128,7 +133,7 @@ static void EDIT_ARMATURE_cache_populate(void *vedata, Object *ob) .bone_axes = psl->bone_axes, .relationship_lines = psl->relationship, }; - DRW_shgroup_armature_edit(ob, passes); + DRW_shgroup_armature_edit(ob, passes, stl->g_data->transparent_bones); } } } @@ -136,22 +141,20 @@ static void EDIT_ARMATURE_cache_populate(void *vedata, Object *ob) static void EDIT_ARMATURE_draw_scene(void *vedata) { EDIT_ARMATURE_PassList *psl = ((EDIT_ARMATURE_Data *)vedata)->psl; + EDIT_ARMATURE_StorageList *stl = ((EDIT_ARMATURE_Data *)vedata)->stl; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const bool transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0; DRW_draw_pass(psl->bone_envelope); - if (transparent_bones) { - DRW_pass_state_add(psl->bone_solid, DRW_STATE_BLEND); - DRW_pass_state_remove(psl->bone_solid, DRW_STATE_WRITE_DEPTH); + if (stl->g_data->transparent_bones) { + /* For performance reason, avoid blending on MS target. */ DRW_draw_pass(psl->bone_solid); } MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl) - if (!transparent_bones) { + if (!stl->g_data->transparent_bones) { DRW_draw_pass(psl->bone_solid); } diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c index 040195b889b..7a4abcac179 100644 --- a/source/blender/draw/modes/pose_mode.c +++ b/source/blender/draw/modes/pose_mode.c @@ -75,6 +75,7 @@ typedef struct POSE_PrivateData { DRWShadingGroup *bone_selection_invert_shgrp; float blend_color[4]; float blend_color_invert[4]; + bool transparent_bones; } POSE_PrivateData; /* Transient data */ static struct { @@ -112,9 +113,10 @@ static void POSE_cache_init(void *vedata) if (!stl->g_data) { /* Alloc transient pointers */ - stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); + stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); } POSE_PrivateData *ppd = stl->g_data; + ppd->transparent_bones = (draw_ctx->v3d->overlay.arm_flag & V3D_OVERLAY_ARM_TRANSP_BONES) != 0; { /* Solid bones */ @@ -195,7 +197,7 @@ static bool POSE_is_driven_by_active_armature(Object *ob) static void POSE_cache_populate(void *vedata, Object *ob) { POSE_PassList *psl = ((POSE_Data *)vedata)->psl; - POSE_StorageList *stl = ((POSE_Data *)vedata)->stl; + POSE_PrivateData *ppd = ((POSE_Data *)vedata)->stl->g_data; const DRWContextState *draw_ctx = DRW_context_state_get(); /* In the future this will allow us to implement face gizmos, @@ -214,7 +216,7 @@ static void POSE_cache_populate(void *vedata, Object *ob) .bone_axes = psl->bone_axes, .relationship_lines = psl->relationship, }; - DRW_shgroup_armature_pose(ob, passes); + DRW_shgroup_armature_pose(ob, passes, ppd->transparent_bones); } } else if (ob->type == OB_MESH && @@ -224,10 +226,10 @@ static void POSE_cache_populate(void *vedata, Object *ob) struct GPUBatch *geom = DRW_cache_object_surface_get(ob); if (geom) { if (POSE_is_driven_by_active_armature(ob)) { - DRW_shgroup_call_object_add(stl->g_data->bone_selection_shgrp, geom, ob); + DRW_shgroup_call_object_add(ppd->bone_selection_shgrp, geom, ob); } else { - DRW_shgroup_call_object_add(stl->g_data->bone_selection_invert_shgrp, geom, ob); + DRW_shgroup_call_object_add(ppd->bone_selection_invert_shgrp, geom, ob); } } } diff --git a/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl index b20656ff326..78b29296601 100644 --- a/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl +++ b/source/blender/draw/modes/shaders/armature_envelope_solid_frag.glsl @@ -1,4 +1,6 @@ +uniform float alpha = 0.6; + flat in vec3 finalStateColor; flat in vec3 finalBoneColor; in vec3 normalView; @@ -12,5 +14,5 @@ void main() float n = normalize(normalView).z; float fac = clamp((n * (1.0 - s)) + s, 0.0, 1.0); fragColor.rgb = mix(finalStateColor, finalBoneColor, fac); - fragColor.a = 0.6; /* Hardcoded transparency factor. */ + fragColor.a = alpha; } diff --git a/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl index 89f4d97f29b..45748bf5644 100644 --- a/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl +++ b/source/blender/draw/modes/shaders/armature_shape_solid_frag.glsl @@ -1,9 +1,11 @@ +uniform float alpha = 0.6; + in vec4 finalColor; out vec4 fragColor; void main() { - fragColor = vec4(finalColor.rgb, 0.6); /* Hardcoded transparency factor. */ + fragColor = vec4(finalColor.rgb, alpha); } diff --git a/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl index 3c80f629d79..a0fdd55931f 100644 --- a/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl +++ b/source/blender/draw/modes/shaders/armature_sphere_solid_frag.glsl @@ -3,6 +3,7 @@ uniform mat4 ViewMatrixInverse; uniform mat4 ProjectionMatrix; +uniform float alpha = 0.4; flat in vec3 finalStateColor; flat in vec3 finalBoneColor; @@ -73,8 +74,7 @@ void main() float dither = (0.5 + dot(vec2(ivec2(gl_FragCoord.xy) & ivec2(1)), vec2(1.0, 2.0))) * 0.25; dither *= (1.0 / 255.0); /* Assume 8bit per color buffer. */ - /* Hardcoded transparency factor. Less than shape to be less distractive. */ - fragColor = vec4(fragColor.rgb + dither, 0.4); + fragColor = vec4(fragColor.rgb + dither, alpha); t /= ray_len; gl_FragDepth = get_depth_from_view_z(ray_dir_view.z * t + ray_ori_view.z); -- cgit v1.2.3 From bfaf41663abd929b3756f81f7cbbcb57419d21fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 30 Jul 2018 14:18:38 +0200 Subject: Motion Path: Don't blit MSAA buffer if there is no motion paths --- source/blender/draw/intern/draw_anim_viz.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'source') diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c index 6bf7bf9ca08..f976c7b4d05 100644 --- a/source/blender/draw/intern/draw_anim_viz.c +++ b/source/blender/draw/intern/draw_anim_viz.c @@ -322,6 +322,13 @@ static void MPATH_draw_scene(void *vedata) DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + if (DRW_pass_is_empty(psl->lines) && + DRW_pass_is_empty(psl->points)) + { + /* Nothing to draw. */ + return; + } + MULTISAMPLE_SYNC_ENABLE(dfbl, dtxl) DRW_draw_pass(psl->lines); -- cgit v1.2.3 From 27567a6c760be523b77e4d95e544c60b6f9ddf84 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 30 Jul 2018 15:00:51 +0200 Subject: Fix T56020: Crash while opening .blend file made with older version. We need a NULL workspace check here, in some cases we get a SRTemp screen even though it's not tagged as temp... --- source/blender/blenloader/intern/versioning_280.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source') diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 39ceb527209..5b0a12a0b4c 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -112,6 +112,9 @@ static void do_version_workspaces_create_from_screens(Main *bmain) else { workspace = BKE_workspace_add(bmain, screen->id.name + 2); } + if (workspace == NULL) { + continue; /* Not much we can do.. */ + } BKE_workspace_layout_add(bmain, workspace, screen, screen->id.name + 2); } } -- cgit v1.2.3 From 6d6deeb70086564418368a5213cd9d28cdfa51e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 30 Jul 2018 16:48:44 +0200 Subject: Workbench: Use FXAA instead of TAA when viewport is animated. Fix T55996 "Playback in "Active Editor Only" doesn't work" --- source/blender/draw/engines/workbench/workbench_effect_aa.c | 11 +++++++++++ source/blender/draw/engines/workbench/workbench_private.h | 7 +++++-- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c index 66f1de7f9fc..6269496f568 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_aa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_aa.c @@ -23,6 +23,8 @@ * \ingroup draw_engine */ +#include "ED_screen.h" + #include "workbench_private.h" @@ -32,6 +34,15 @@ void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx) WORKBENCH_PrivateData *wpd = stl->g_data; WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_EffectInfo *effect_info = stl->effects; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + if (draw_ctx->evil_C != NULL) { + struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); + wpd->is_playback = ED_screen_animation_playing(wm) != NULL; + } + else { + wpd->is_playback = false; + } if (TAA_ENABLED(wpd)) { psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx); diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index 99d1b7060fd..dc2894f0207 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -53,8 +53,10 @@ #define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW) #define IS_NAVIGATING(wpd) ((DRW_context_state_get()->rv3d) && (DRW_context_state_get()->rv3d->rflag & RV3D_NAVIGATING)) -#define FXAA_ENABLED(wpd) ((!DRW_state_is_opengl_render()) && (IN_RANGE(wpd->user_preferences->gpu_viewport_quality, GPU_VIEWPORT_QUALITY_FXAA, GPU_VIEWPORT_QUALITY_TAA8) || ((wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8) && IS_NAVIGATING(wpd)))) -#define TAA_ENABLED(wpd) (wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8 && !IS_NAVIGATING(wpd)) +#define FXAA_ENABLED(wpd) ((!DRW_state_is_opengl_render()) && \ + (IN_RANGE(wpd->user_preferences->gpu_viewport_quality, GPU_VIEWPORT_QUALITY_FXAA, GPU_VIEWPORT_QUALITY_TAA8) || \ + ((IS_NAVIGATING(wpd) || wpd->is_playback) && (wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8)))) +#define TAA_ENABLED(wpd) (wpd->user_preferences->gpu_viewport_quality >= GPU_VIEWPORT_QUALITY_TAA8 && !IS_NAVIGATING(wpd) && !wpd->is_playback) #define SPECULAR_HIGHLIGHT_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT) && (!STUDIOLIGHT_ORIENTATION_VIEWNORMAL_ENABLED(wpd))) #define OBJECT_ID_PASS_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) #define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd) || SPECULAR_HIGHLIGHT_ENABLED(wpd)) @@ -174,6 +176,7 @@ typedef struct WORKBENCH_PrivateData { float shadow_near_max[3]; float shadow_near_sides[2][4]; /* This is a parallelogram, so only 2 normal and distance to the edges. */ bool shadow_changed; + bool is_playback; /* Volumes */ bool volumes_do; -- cgit v1.2.3 From a3b6ae9fb9dd76538ec04b9fa6953490d321dd32 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 30 Jul 2018 16:54:40 +0200 Subject: Cleanup/Refactor: Move CurveCache runtime data into Object.runtime struct. Also, fix missing cleanup of Object.runtime when copying Object datablocks! --- source/blender/alembic/intern/abc_mball.cc | 2 +- source/blender/alembic/intern/abc_nurbs.cc | 4 +- source/blender/blenkernel/intern/anim.c | 14 +++---- source/blender/blenkernel/intern/armature_update.c | 2 +- source/blender/blenkernel/intern/cdderivedmesh.c | 4 +- source/blender/blenkernel/intern/constraint.c | 8 ++-- source/blender/blenkernel/intern/curve.c | 10 ++--- source/blender/blenkernel/intern/displist.c | 42 +++++++++---------- source/blender/blenkernel/intern/effect.c | 4 +- source/blender/blenkernel/intern/font.c | 6 +-- source/blender/blenkernel/intern/lattice.c | 30 +++++++------- source/blender/blenkernel/intern/material.c | 4 +- source/blender/blenkernel/intern/mball.c | 2 +- source/blender/blenkernel/intern/mesh_convert.c | 24 +++++------ source/blender/blenkernel/intern/object.c | 48 +++++++++++----------- source/blender/blenloader/intern/readfile.c | 3 -- .../intern/eval/deg_eval_copy_on_write.cc | 8 +--- source/blender/draw/intern/draw_cache.c | 18 ++++---- .../blender/draw/intern/draw_cache_impl_metaball.c | 2 +- source/blender/draw/modes/object_mode.c | 4 +- source/blender/editors/curve/editcurve.c | 4 +- source/blender/editors/object/object_add.c | 6 +-- source/blender/editors/object/object_relations.c | 2 +- source/blender/editors/space_info/info_stats.c | 4 +- .../editors/space_view3d/view3d_iterators.c | 2 +- source/blender/makesdna/DNA_object_types.h | 7 ++-- source/blender/modifiers/intern/MOD_array.c | 5 ++- 27 files changed, 131 insertions(+), 138 deletions(-) (limited to 'source') diff --git a/source/blender/alembic/intern/abc_mball.cc b/source/blender/alembic/intern/abc_mball.cc index d6e54407922..62ab561274a 100644 --- a/source/blender/alembic/intern/abc_mball.cc +++ b/source/blender/alembic/intern/abc_mball.cc @@ -52,7 +52,7 @@ AbcMBallWriter::AbcMBallWriter( m_is_animated = isAnimated(); m_mesh_ob = BKE_object_copy(bmain, ob); - m_mesh_ob->curve_cache = (CurveCache *)MEM_callocN( + m_mesh_ob->runtime.curve_cache = (CurveCache *)MEM_callocN( sizeof(CurveCache), "CurveCache for AbcMBallWriter"); diff --git a/source/blender/alembic/intern/abc_nurbs.cc b/source/blender/alembic/intern/abc_nurbs.cc index 95d06fc5efe..bf41b44e418 100644 --- a/source/blender/alembic/intern/abc_nurbs.cc +++ b/source/blender/alembic/intern/abc_nurbs.cc @@ -130,8 +130,8 @@ void AbcNurbsWriter::do_write() Curve *curve = static_cast(m_object->data); ListBase *nulb; - if (m_object->curve_cache->deformed_nurbs.first != NULL) { - nulb = &m_object->curve_cache->deformed_nurbs; + if (m_object->runtime.curve_cache->deformed_nurbs.first != NULL) { + nulb = &m_object->runtime.curve_cache->deformed_nurbs; } else { nulb = BKE_curve_nurbs_get(curve); diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index a867accfe44..7df889d22b2 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -537,18 +537,18 @@ void calc_curvepath(Object *ob, ListBase *nurbs) return; } - if (ob->curve_cache->path) free_path(ob->curve_cache->path); - ob->curve_cache->path = NULL; + if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path); + ob->runtime.curve_cache->path = NULL; /* weak! can only use first curve */ - bl = ob->curve_cache->bev.first; + bl = ob->runtime.curve_cache->bev.first; if (bl == NULL || !bl->nr) { return; } nu = nurbs->first; - ob->curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath"); + ob->runtime.curve_cache->path = path = MEM_callocN(sizeof(Path), "calc_curvepath"); /* if POLY: last vertice != first vertice */ cycl = (bl->poly != -1); @@ -665,15 +665,15 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua if (ob == NULL || ob->type != OB_CURVE) return 0; cu = ob->data; - if (ob->curve_cache == NULL || ob->curve_cache->path == NULL || ob->curve_cache->path->data == NULL) { + if (ob->runtime.curve_cache == NULL || ob->runtime.curve_cache->path == NULL || ob->runtime.curve_cache->path->data == NULL) { printf("no path!\n"); return 0; } - path = ob->curve_cache->path; + path = ob->runtime.curve_cache->path; pp = path->data; /* test for cyclic */ - bl = ob->curve_cache->bev.first; + bl = ob->runtime.curve_cache->bev.first; if (!bl) return 0; if (!bl->nr) return 0; if (bl->poly > -1) cycl = 1; diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 628f92c7803..26fbd22c67e 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -201,7 +201,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos /* get the current length of the curve */ /* NOTE: this is assumed to be correct even after the curve was resized */ - splineLen = ikData->tar->curve_cache->path->totdist; + splineLen = ikData->tar->runtime.curve_cache->path->totdist; /* calculate the scale factor to multiply all the path values by so that the * bone chain retains its current length, such that diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 72a1f941c26..3f50321b4d5 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -655,8 +655,8 @@ DerivedMesh *CDDM_from_curve(Object *ob) { ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } return CDDM_from_curve_displist(ob, &disp); diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 5aa192d527a..ef412f0006e 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -496,7 +496,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m { Lattice *lt = (Lattice *)ob->data; - DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL; const float *co = dl ? dl->verts : NULL; BPoint *bp = lt->def; @@ -1266,7 +1266,7 @@ static void followpath_get_tarmat(struct Depsgraph *UNUSED(depsgraph), * currently for paths to work it needs to go through the bevlist/displist system (ton) */ - if (ct->tar->curve_cache && ct->tar->curve_cache->path && ct->tar->curve_cache->path->data) { + if (ct->tar->runtime.curve_cache && ct->tar->runtime.curve_cache->path && ct->tar->runtime.curve_cache->path->data) { float quat[4]; if ((data->followflag & FOLLOWPATH_STATIC) == 0) { /* animated position along curve depending on time */ @@ -2037,7 +2037,7 @@ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), #endif if (VALID_CONS_TARGET(ct)) { - if (ct->tar->type == OB_CURVE && ct->tar->curve_cache == NULL) { + if (ct->tar->type == OB_CURVE && ct->tar->runtime.curve_cache == NULL) { unit_m4(ct->matrix); return; } @@ -3104,7 +3104,7 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar BKE_object_minmax(ct->tar, curveMin, curveMax, true); /* get targetmatrix */ - if (data->tar->curve_cache && data->tar->curve_cache->path && data->tar->curve_cache->path->data) { + if (data->tar->runtime.curve_cache && data->tar->runtime.curve_cache->path && data->tar->runtime.curve_cache->path->data) { float vec[4], dir[3], totmat[4][4]; float curvetime; short clamp_axis; diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 33a24f77937..39b28540205 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -1752,11 +1752,11 @@ void BKE_curve_bevel_make( BKE_displist_make_curveTypes_forRender(depsgraph, scene, cu->bevobj, &bevdisp, NULL, false, use_render_resolution); dl = bevdisp.first; } - else if (cu->bevobj->curve_cache) { - dl = cu->bevobj->curve_cache->disp.first; + else if (cu->bevobj->runtime.curve_cache) { + dl = cu->bevobj->runtime.curve_cache->disp.first; } else { - BLI_assert(cu->bevobj->curve_cache != NULL); + BLI_assert(cu->bevobj->runtime.curve_cache != NULL); dl = NULL; } @@ -2669,14 +2669,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render) ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE); - bev = &ob->curve_cache->bev; + bev = &ob->runtime.curve_cache->bev; /* do we need to calculate the radius for each point? */ /* do_radius = (cu->bevobj || cu->taperobj || (cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) ? 0 : 1; */ /* STEP 1: MAKE POLYS */ - BKE_curve_bevelList_free(&ob->curve_cache->bev); + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); nu = nurbs->first; if (cu->editnurb && ob->type != OB_FONT) { is_editmode = 1; diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 34fd32b2908..562e2257ea0 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -692,10 +692,10 @@ static float displist_calc_taper(Depsgraph *depsgraph, Scene *scene, Object *tap if (taperobj == NULL || taperobj->type != OB_CURVE) return 1.0; - dl = taperobj->curve_cache ? taperobj->curve_cache->disp.first : NULL; + dl = taperobj->runtime.curve_cache ? taperobj->runtime.curve_cache->disp.first : NULL; if (dl == NULL) { BKE_displist_make_curveTypes(depsgraph, scene, taperobj, 0); - dl = taperobj->curve_cache->disp.first; + dl = taperobj->runtime.curve_cache->disp.first; } if (dl) { float minx, dx, *fp; @@ -738,17 +738,17 @@ void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob) return; if (ob == BKE_mball_basis_find(scene, ob)) { - if (ob->curve_cache) { - BKE_displist_free(&(ob->curve_cache->disp)); + if (ob->runtime.curve_cache) { + BKE_displist_free(&(ob->runtime.curve_cache->disp)); } else { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall"); } - BKE_mball_polygonize(depsgraph, scene, ob, &ob->curve_cache->disp); + BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp); BKE_mball_texspace_calc(ob); - object_deform_mball(ob, &ob->curve_cache->disp); + object_deform_mball(ob, &ob->runtime.curve_cache->disp); /* NOP for MBALLs anyway... */ boundbox_displist_object(ob); @@ -1314,7 +1314,7 @@ void BKE_displist_make_surf( } if (!for_orco) { - BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase); + BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution); } @@ -1558,15 +1558,15 @@ static void do_makeDispListCurveTypes( ListBase dlbev; ListBase nubase = {NULL, NULL}; - BKE_curve_bevelList_free(&ob->curve_cache->bev); + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); /* We only re-evaluate path if evaluation is not happening for orco. * If the calculation happens for orco, we should never free data which * was needed before and only not needed for orco calculation. */ if (!for_orco) { - if (ob->curve_cache->path) free_path(ob->curve_cache->path); - ob->curve_cache->path = NULL; + if (ob->runtime.curve_cache->path) free_path(ob->runtime.curve_cache->path); + ob->runtime.curve_cache->path = NULL; } if (ob->type == OB_FONT) { @@ -1590,7 +1590,7 @@ static void do_makeDispListCurveTypes( } else { float widfac = cu->width - 1.0f; - BevList *bl = ob->curve_cache->bev.first; + BevList *bl = ob->runtime.curve_cache->bev.first; Nurb *nu = nubase.first; for (; bl && nu; bl = bl->next, nu = nu->next) { @@ -1777,7 +1777,7 @@ static void do_makeDispListCurveTypes( } if (!for_orco) { - BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase); + BKE_nurbList_duplicate(&ob->runtime.curve_cache->deformed_nurbs, &nubase); curve_calc_modifiers_post(depsgraph, scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution); } @@ -1801,11 +1801,11 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, Scene *scene, Object *ob BKE_object_free_derived_caches(ob); - if (!ob->curve_cache) { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); + if (!ob->runtime.curve_cache) { + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); } - dispbase = &(ob->curve_cache->disp); + dispbase = &(ob->runtime.curve_cache->disp); do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, &ob->derivedFinal, 0, for_orco, 0); @@ -1817,8 +1817,8 @@ void BKE_displist_make_curveTypes_forRender( DerivedMesh **r_dm_final, const bool for_orco, const bool use_render_resolution) { - if (ob->curve_cache == NULL) { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); + if (ob->runtime.curve_cache == NULL) { + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); } do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution); @@ -1827,8 +1827,8 @@ void BKE_displist_make_curveTypes_forRender( void BKE_displist_make_curveTypes_forOrco( Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase) { - if (ob->curve_cache == NULL) { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); + if (ob->runtime.curve_cache == NULL) { + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve"); } do_makeDispListCurveTypes(depsgraph, scene, ob, dispbase, NULL, 1, 1, 1); @@ -1903,7 +1903,7 @@ static void boundbox_displist_object(Object *ob) float min[3], max[3]; INIT_MINMAX(min, max); - BKE_displist_minmax(&ob->curve_cache->disp, min, max); + BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max); BKE_boundbox_init_from_minmax(ob->bb, min, max); ob->bb->flag &= ~BOUNDBOX_DIRTY; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index b6eb26443ea..52ea4bf4a5e 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -163,10 +163,10 @@ static void precalculate_effector(struct Depsgraph *depsgraph, EffectorCache *ef if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) { Curve *cu= eff->ob->data; if (cu->flag & CU_PATH) { - if (eff->ob->curve_cache == NULL || eff->ob->curve_cache->path==NULL || eff->ob->curve_cache->path->data==NULL) + if (eff->ob->runtime.curve_cache == NULL || eff->ob->runtime.curve_cache->path==NULL || eff->ob->runtime.curve_cache->path->data==NULL) BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, 0); - if (eff->ob->curve_cache->path && eff->ob->curve_cache->path->data) { + if (eff->ob->runtime.curve_cache->path && eff->ob->runtime.curve_cache->path->data) { where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius, NULL); mul_m4_v3(eff->ob->obmat, eff->guide_loc); mul_mat3_m4_v3(eff->ob->obmat, eff->guide_dir); diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 36633663f9d..b5fba6d30e8 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -1075,8 +1075,8 @@ makebreak: /* TEXT ON CURVE */ /* Note: Only OB_CURVE objects could have a path */ if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) { - BLI_assert(cu->textoncurve->curve_cache != NULL); - if (cu->textoncurve->curve_cache->path) { + BLI_assert(cu->textoncurve->runtime.curve_cache != NULL); + if (cu->textoncurve->runtime.curve_cache->path) { float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; @@ -1106,7 +1106,7 @@ makebreak: /* we put the x-coordinaat exact at the curve, the y is rotated */ /* length correction */ - distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx); + distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx); timeofs = 0.0f; if (distfac > 1.0f) { diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 78ff43c2981..04830eb1081 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -211,9 +211,9 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb) /* works best if we force to linear type (endpoints match) */ lt->typeu = lt->typev = lt->typew = KEY_LINEAR; - if (ltOb->curve_cache) { + if (ltOb->runtime.curve_cache) { /* prevent using deformed locations */ - BKE_displist_free(<Ob->curve_cache->disp); + BKE_displist_free(<Ob->runtime.curve_cache->disp); } copy_m4_m4(mat, ltOb->obmat); @@ -349,7 +349,7 @@ LatticeDeformData *init_latt_deform(Object *oblatt, Object *ob) /* we make an array with all differences */ Lattice *lt = oblatt->data; BPoint *bp; - DispList *dl = oblatt->curve_cache ? BKE_displist_find(&oblatt->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = oblatt->runtime.curve_cache ? BKE_displist_find(&oblatt->runtime.curve_cache->disp, DL_VERTS) : NULL; const float *co = dl ? dl->verts : NULL; float *fp, imat[4][4]; float fu, fv, fw; @@ -558,7 +558,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di int cycl = 0; /* test for cyclic */ - bl = ob->curve_cache->bev.first; + bl = ob->runtime.curve_cache->bev.first; if (!bl->nr) return false; if (bl->poly > -1) cycl = 1; @@ -573,7 +573,7 @@ static bool where_on_path_deform(Object *ob, float ctime, float vec[4], float di if (where_on_path(ob, ctime1, vec, dir, quat, radius, NULL)) { if (cycl == 0) { - Path *path = ob->curve_cache->path; + Path *path = ob->runtime.curve_cache->path; float dvec[3]; if (ctime < 0.0f) { @@ -610,12 +610,12 @@ static bool calc_curve_deform(Object *par, float co[3], short index; const bool is_neg_axis = (axis > 2); - if (par->curve_cache == NULL) { + if (par->runtime.curve_cache == NULL) { /* Happens with a cyclic dependencies. */ return false; } - if (par->curve_cache->path == NULL) { + if (par->runtime.curve_cache->path == NULL) { return false; /* happens on append, cyclic dependencies and empty curves */ } @@ -625,7 +625,7 @@ static bool calc_curve_deform(Object *par, float co[3], if (cu->flag & CU_STRETCH) fac = (-co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); else - fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist); + fac = -(co[index] - cd->dmax[index]) / (par->runtime.curve_cache->path->totdist); } else { index = axis; @@ -633,8 +633,8 @@ static bool calc_curve_deform(Object *par, float co[3], fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); } else { - if (LIKELY(par->curve_cache->path->totdist > FLT_EPSILON)) { - fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist); + if (LIKELY(par->runtime.curve_cache->path->totdist > FLT_EPSILON)) { + fac = +(co[index] - cd->dmin[index]) / (par->runtime.curve_cache->path->totdist); } else { fac = 0.0f; @@ -1035,11 +1035,11 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec int numVerts, editmode = (lt->editlatt != NULL); const ModifierEvalContext mectx = {depsgraph, ob, 0}; - if (ob->curve_cache) { - BKE_displist_free(&ob->curve_cache->disp); + if (ob->runtime.curve_cache) { + BKE_displist_free(&ob->runtime.curve_cache->disp); } else { - ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); + ob->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for lattice"); } for (; md; md = md->next) { @@ -1071,7 +1071,7 @@ void BKE_lattice_modifiers_calc(struct Depsgraph *depsgraph, Scene *scene, Objec dl->nr = numVerts; dl->verts = (float *) vertexCos; - BLI_addtail(&ob->curve_cache->disp, dl); + BLI_addtail(&ob->runtime.curve_cache->disp, dl); } } @@ -1145,7 +1145,7 @@ BoundBox *BKE_lattice_boundbox_get(Object *ob) void BKE_lattice_minmax_dl(Object *ob, Lattice *lt, float min[3], float max[3]) { - DispList *dl = ob->curve_cache ? BKE_displist_find(&ob->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = ob->runtime.curve_cache ? BKE_displist_find(&ob->runtime.curve_cache->disp, DL_VERTS) : NULL; if (!dl) { BKE_lattice_minmax(lt, min, max); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index ab8c8695495..28d75811185 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -926,8 +926,8 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob) /* check indices from mesh */ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { material_data_index_remove_id((ID *)ob->data, actcol - 1); - if (ob->curve_cache) { - BKE_displist_free(&ob->curve_cache->disp); + if (ob->runtime.curve_cache) { + BKE_displist_free(&ob->runtime.curve_cache->disp); } } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 2ff69c5ee6d..43b7eba2810 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -207,7 +207,7 @@ void BKE_mball_texspace_calc(Object *ob) (min)[0] = (min)[1] = (min)[2] = 1.0e30f; (max)[0] = (max)[1] = (max)[2] = -1.0e30f; - dl = ob->curve_cache->disp.first; + dl = ob->runtime.curve_cache->disp.first; while (dl) { tot = dl->nr; if (tot) do_it = true; diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index 738f116310b..2e2afa6834b 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -217,8 +217,8 @@ int BKE_mesh_nurbs_to_mdata( { ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } return BKE_mesh_nurbs_displist_to_mdata( @@ -537,8 +537,8 @@ Mesh *BKE_mesh_new_nomain_from_curve(Object *ob) { ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } return BKE_mesh_new_nomain_from_curve_displist(ob, &disp); @@ -650,8 +650,8 @@ void BKE_mesh_from_nurbs(Main *bmain, Object *ob) bool use_orco_uv = (cu->flag & CU_UV_ORCO) != 0; ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } BKE_mesh_from_nurbs_displist(bmain, ob, &disp, use_orco_uv, cu->id.name, false); @@ -871,11 +871,11 @@ Mesh *BKE_mesh_new_from_object( * * TODO(sergey): Look into more proper solution. */ - if (ob->curve_cache != NULL) { - if (tmpobj->curve_cache == NULL) { - tmpobj->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); + if (ob->runtime.curve_cache != NULL) { + if (tmpobj->runtime.curve_cache == NULL) { + tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types"); } - BKE_displist_copy(&tmpobj->curve_cache->disp, &ob->curve_cache->disp); + BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &ob->runtime.curve_cache->disp); } /* if getting the original caged mesh, delete object modifiers */ @@ -953,8 +953,8 @@ Mesh *BKE_mesh_new_from_object( } else { ListBase disp = {NULL, NULL}; - if (ob->curve_cache) { - disp = ob->curve_cache->disp; + if (ob->runtime.curve_cache) { + disp = ob->runtime.curve_cache->disp; } BKE_mesh_from_metaball(&disp, tmpmesh); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 1d6b23ce7f7..21b5bb89f19 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -170,15 +170,15 @@ void BKE_object_free_softbody(Object *ob) void BKE_object_free_curve_cache(Object *ob) { - if (ob->curve_cache) { - BKE_displist_free(&ob->curve_cache->disp); - BKE_curve_bevelList_free(&ob->curve_cache->bev); - if (ob->curve_cache->path) { - free_path(ob->curve_cache->path); + if (ob->runtime.curve_cache) { + BKE_displist_free(&ob->runtime.curve_cache->disp); + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); + if (ob->runtime.curve_cache->path) { + free_path(ob->runtime.curve_cache->path); } - BKE_nurbList_free(&ob->curve_cache->deformed_nurbs); - MEM_freeN(ob->curve_cache); - ob->curve_cache = NULL; + BKE_nurbList_free(&ob->runtime.curve_cache->deformed_nurbs); + MEM_freeN(ob->runtime.curve_cache); + ob->runtime.curve_cache = NULL; } } @@ -460,12 +460,12 @@ void BKE_object_free(Object *ob) BLI_freelistN(&ob->lodlevels); /* Free runtime curves data. */ - if (ob->curve_cache) { - BKE_curve_bevelList_free(&ob->curve_cache->bev); - if (ob->curve_cache->path) - free_path(ob->curve_cache->path); - MEM_freeN(ob->curve_cache); - ob->curve_cache = NULL; + if (ob->runtime.curve_cache) { + BKE_curve_bevelList_free(&ob->runtime.curve_cache->bev); + if (ob->runtime.curve_cache->path) + free_path(ob->runtime.curve_cache->path); + MEM_freeN(ob->runtime.curve_cache); + ob->runtime.curve_cache = NULL; } BKE_previewimg_free(&ob->preview); @@ -1154,6 +1154,9 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con { ModifierData *md; + /* Do not copy runtime data. */ + BKE_object_runtime_reset(ob_dst); + /* We never handle usercount here for own data. */ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; @@ -1212,9 +1215,6 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con copy_object_lod(ob_dst, ob_src, flag_subdata); - /* Do not copy runtime curve data. */ - ob_dst->curve_cache = NULL; - /* Do not copy object's preview (mostly due to the fact renderers create temp copy of objects). */ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ BKE_previewimg_id_copy(&ob_dst->id, &ob_src->id); @@ -1725,7 +1725,7 @@ static bool ob_parcurve(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, } #endif - if (par->curve_cache->path == NULL) { + if (par->runtime.curve_cache->path == NULL) { return false; } @@ -1944,10 +1944,10 @@ static void give_parvert(Object *par, int nr, float vec[3]) ListBase *nurb; /* Unless there's some weird depsgraph failure the cache should exist. */ - BLI_assert(par->curve_cache != NULL); + BLI_assert(par->runtime.curve_cache != NULL); - if (par->curve_cache->deformed_nurbs.first != NULL) { - nurb = &par->curve_cache->deformed_nurbs; + if (par->runtime.curve_cache->deformed_nurbs.first != NULL) { + nurb = &par->runtime.curve_cache->deformed_nurbs; } else { Curve *cu = par->data; @@ -1958,7 +1958,7 @@ static void give_parvert(Object *par, int nr, float vec[3]) } else if (par->type == OB_LATTICE) { Lattice *latt = par->data; - DispList *dl = par->curve_cache ? BKE_displist_find(&par->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = par->runtime.curve_cache ? BKE_displist_find(&par->runtime.curve_cache->disp, DL_VERTS) : NULL; float (*co)[3] = dl ? (float (*)[3])dl->verts : NULL; int tot; @@ -2539,10 +2539,10 @@ void BKE_object_foreach_display_point( func_cb(co, user_data); } } - else if (ob->curve_cache && ob->curve_cache->disp.first) { + else if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) { DispList *dl; - for (dl = ob->curve_cache->disp.first; dl; dl = dl->next) { + for (dl = ob->runtime.curve_cache->disp.first; dl; dl = dl->next) { const float *v3 = dl->verts; int totvert = dl->nr; int i; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f226693b989..816a527d829 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5547,9 +5547,6 @@ static void direct_link_object(FileData *fd, Object *ob) BKE_object_runtime_reset(ob); link_list(fd, &ob->pc_ids); - /* Runtime curve data */ - ob->curve_cache = NULL; - /* in case this value changes in future, clamp else we get undefined behavior */ CLAMP(ob->rotmode, ROT_MODE_MIN, ROT_MODE_MAX); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 20aec0ba5ed..b5b33900105 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -732,7 +732,7 @@ static void deg_backup_object_runtime( Object *object, ObjectRuntimeBackup *object_runtime_backup) { - /* Store evaluated mesh, and make sure we don't free it. */ + /* Store evaluated mesh and curve_cache, and make sure we don't free it. */ Mesh *mesh_eval = object->runtime.mesh_eval; object_runtime_backup->runtime = object->runtime; BKE_object_runtime_reset(object); @@ -743,9 +743,6 @@ static void deg_backup_object_runtime( if (mesh_eval != NULL && object->data == mesh_eval) { object->data = object->runtime.mesh_orig; } - /* Store curve cache and make sure we don't free it. */ - object_runtime_backup->curve_cache = object->curve_cache; - object->curve_cache = NULL; /* Make a backup of base flags. */ object_runtime_backup->base_flag = object->base_flag; } @@ -783,9 +780,6 @@ static void deg_restore_object_runtime( } } } - if (object_runtime_backup->curve_cache != NULL) { - object->curve_cache = object_runtime_backup->curve_cache; - } object->base_flag = object_runtime_backup->base_flag; } diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index dff863b11bb..bdfa3211f7c 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -2954,7 +2954,7 @@ GPUBatch *DRW_cache_curve_edge_wire_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_wire_edge(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_wire_edge(cu, ob->runtime.curve_cache); } GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob, float normal_size) @@ -2962,7 +2962,7 @@ GPUBatch *DRW_cache_curve_edge_normal_get(Object *ob, float normal_size) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_normal_edge(cu, ob->curve_cache, normal_size); + return DRW_curve_batch_cache_get_normal_edge(cu, ob->runtime.curve_cache, normal_size); } GPUBatch *DRW_cache_curve_edge_overlay_get(Object *ob) @@ -2986,7 +2986,7 @@ GPUBatch *DRW_cache_curve_surface_get(Object *ob) BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache); } /* Return list of batches */ @@ -2996,7 +2996,7 @@ GPUBatch **DRW_cache_curve_surface_shaded_get( BLI_assert(ob->type == OB_CURVE); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len); + return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len); } /** \} */ @@ -3032,7 +3032,7 @@ GPUBatch *DRW_cache_text_edge_wire_get(Object *ob) BLI_assert(ob->type == OB_FONT); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_wire_edge(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_wire_edge(cu, ob->runtime.curve_cache); } GPUBatch *DRW_cache_text_surface_get(Object *ob) @@ -3042,7 +3042,7 @@ GPUBatch *DRW_cache_text_surface_get(Object *ob) if (cu->editfont && (cu->flag & CU_FAST)) { return NULL; } - return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache); } GPUBatch **DRW_cache_text_surface_shaded_get( @@ -3053,7 +3053,7 @@ GPUBatch **DRW_cache_text_surface_shaded_get( if (cu->editfont && (cu->flag & CU_FAST)) { return NULL; } - return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len); + return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len); } GPUBatch *DRW_cache_text_cursor_overlay_get(Object *ob) @@ -3082,7 +3082,7 @@ GPUBatch *DRW_cache_surf_surface_get(Object *ob) BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->curve_cache); + return DRW_curve_batch_cache_get_triangles_with_normals(cu, ob->runtime.curve_cache); } /* Return list of batches */ @@ -3092,7 +3092,7 @@ GPUBatch **DRW_cache_surf_surface_shaded_get( BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - return DRW_curve_batch_cache_get_surface_shaded(cu, ob->curve_cache, gpumat_array, gpumat_array_len); + return DRW_curve_batch_cache_get_surface_shaded(cu, ob->runtime.curve_cache, gpumat_array, gpumat_array_len); } /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_metaball.c b/source/blender/draw/intern/draw_cache_impl_metaball.c index 375b0ba6bb2..2172997a714 100644 --- a/source/blender/draw/intern/draw_cache_impl_metaball.c +++ b/source/blender/draw/intern/draw_cache_impl_metaball.c @@ -140,7 +140,7 @@ GPUBatch *DRW_metaball_batch_cache_get_triangles_with_normals(Object *ob) MetaBallBatchCache *cache = metaball_batch_cache_get(mb); if (cache->batch == NULL) { - ListBase *lb = &ob->curve_cache->disp; + ListBase *lb = &ob->runtime.curve_cache->disp; cache->batch = GPU_batch_create_ex( GPU_PRIM_TRIS, DRW_displist_vertbuf_calc_pos_with_normals(lb), diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 9e9785f5e5c..db906714dd5 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -1663,7 +1663,7 @@ static void DRW_shgroup_forcefield(OBJECT_StorageList *stl, Object *ob, ViewLaye } break; case PFIELD_GUIDE: - if (cu && (cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) { + if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path && ob->runtime.curve_cache->path->data) { where_on_path(ob, 0.0f, pd->drawvec1, tmp, NULL, NULL, NULL); where_on_path(ob, 1.0f, pd->drawvec2, tmp, NULL, NULL, NULL); } @@ -1704,7 +1704,7 @@ static void DRW_shgroup_forcefield(OBJECT_StorageList *stl, Object *ob, ViewLaye DRW_shgroup_call_dynamic_add(stl->g_data->field_vortex, color, &pd->drawvec1, ob->obmat); break; case PFIELD_GUIDE: - if (cu && (cu->flag & CU_PATH) && ob->curve_cache->path && ob->curve_cache->path->data) { + if (cu && (cu->flag & CU_PATH) && ob->runtime.curve_cache->path && ob->runtime.curve_cache->path->data) { DRW_shgroup_call_dynamic_add(stl->g_data->field_curve_sta, color, &pd->f_strength, ob->obmat); DRW_shgroup_call_dynamic_add(stl->g_data->field_curve_end, color, &pd->f_strength, ob->obmat); } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 1d7a9ac46c7..f7d54e3bc4f 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6260,12 +6260,12 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op)) float min[3], max[3], size[3], loc[3]; int a; - if (object->curve_cache == NULL) { + if (object->runtime.curve_cache == NULL) { BKE_displist_make_curveTypes(depsgraph, scene, object, false); } INIT_MINMAX(min, max); - BKE_displist_minmax(&object->curve_cache->disp, min, max); + BKE_displist_minmax(&object->runtime.curve_cache->disp, min, max); mid_v3_v3v3(loc, min, max); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 8c60dd01e89..68e84ec3f3b 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1479,7 +1479,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, ob_dst->parent = NULL; BKE_constraints_free(&ob_dst->constraints); - ob_dst->curve_cache = NULL; + ob_dst->runtime.curve_cache = NULL; ob_dst->transflag &= ~OB_DUPLI; copy_m4_m4(ob_dst->obmat, dob->mat); @@ -1638,7 +1638,7 @@ static const EnumPropertyItem convert_target_items[] = { static void convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob) { - if (ob->curve_cache == NULL) { + if (ob->runtime.curve_cache == NULL) { /* Force creation. This is normally not needed but on operator * redo we might end up with an object which isn't evaluated yet. */ @@ -1966,7 +1966,7 @@ static int convert_exec(bContext *C, wmOperator *op) } convert_ensure_curve_cache(depsgraph, scene, baseob); - BKE_mesh_from_metaball(&baseob->curve_cache->disp, newob->data); + BKE_mesh_from_metaball(&baseob->runtime.curve_cache->disp, newob->data); if (obact->type == OB_MBALL) { basact = basen; diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 4745a484475..331b4af077d 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -716,7 +716,7 @@ bool ED_object_parent_set(ReportList *reports, const bContext *C, Scene *scene, if (md) { ((CurveModifierData *)md)->object = par; } - if (par->curve_cache && par->curve_cache->path == NULL) { + if (par->runtime.curve_cache && par->runtime.curve_cache->path == NULL) { DEG_id_tag_update(&par->id, OB_RECALC_DATA); } } diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 3830e6d2792..8aa37bb5e16 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -127,8 +127,8 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) { int totv = 0, totf = 0, tottri = 0; - if (ob->curve_cache && ob->curve_cache->disp.first) - BKE_displist_count(&ob->curve_cache->disp, &totv, &totf, &tottri); + if (ob->runtime.curve_cache && ob->runtime.curve_cache->disp.first) + BKE_displist_count(&ob->runtime.curve_cache->disp, &totv, &totf, &tottri); totv *= totob; totf *= totob; diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index eae0cf8e459..74071e77901 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -380,7 +380,7 @@ void lattice_foreachScreenVert( Object *obedit = vc->obedit; Lattice *lt = obedit->data; BPoint *bp = lt->editlatt->latt->def; - DispList *dl = obedit->curve_cache ? BKE_displist_find(&obedit->curve_cache->disp, DL_VERTS) : NULL; + DispList *dl = obedit->runtime.curve_cache ? BKE_displist_find(&obedit->runtime.curve_cache->disp, DL_VERTS) : NULL; const float *co = dl ? dl->verts : NULL; int i, N = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index edc87c492a6..a8d50543e80 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -142,6 +142,10 @@ typedef struct Object_Runtime { * It has deforemation only modifiers applied on it. */ struct Mesh *mesh_deform_eval; + + + /* Runtime evaluated curve-specific data, not stored in the file. */ + struct CurveCache *curve_cache; } Object_Runtime; typedef struct Object { @@ -280,9 +284,6 @@ typedef struct Object { uint64_t lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */ uint64_t customdata_mask; /* (extra) custom data layer mask to use for creating derivedmesh, set by depsgraph */ - /* Runtime valuated curve-specific data, not stored in the file */ - struct CurveCache *curve_cache; - ListBase pc_ids; struct RigidBodyOb *rigidbody_object; /* settings for Bullet rigid body */ diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 5ae0013aab0..085f21fe138 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -456,9 +456,10 @@ static Mesh *arrayModifier_doArray( if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) { Curve *cu = amd->curve_ob->data; if (cu) { - if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) { + CurveCache *curve_cache = amd->curve_ob->runtime.curve_cache; + if (curve_cache != NULL && curve_cache->path != NULL) { float scale_fac = mat4_to_scale(amd->curve_ob->obmat); - length = scale_fac * amd->curve_ob->curve_cache->path->totdist; + length = scale_fac * curve_cache->path->totdist; } } } -- cgit v1.2.3 From d28248595b5936ed5f268418ff9905200660ec69 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 31 Jul 2018 02:57:53 +1200 Subject: Silencing a bunch of compiler warnings Most of these were mismatched const qualifiers --- source/blender/blenkernel/intern/collection.c | 2 +- source/blender/editors/include/ED_view3d.h | 2 +- source/blender/editors/space_view3d/view3d_edit.c | 2 +- source/blender/editors/transform/transform_conversions.c | 2 +- source/blender/makesrna/intern/rna_define.c | 2 +- source/blender/nodes/composite/nodes/node_composite_cryptomatte.c | 2 +- source/blender/windowmanager/gizmo/WM_gizmo_api.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 0c93f304218..04e09d06405 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -57,7 +57,7 @@ /******************************** Prototypes ********************************/ -static bool collection_child_add(Collection *parent, Collection *collection, int flag, const bool add_us); +static bool collection_child_add(Collection *parent, Collection *collection, const int flag, const bool add_us); static bool collection_child_remove(Collection *parent, Collection *collection); static bool collection_object_add(Main *bmain, Collection *collection, Object *ob, int flag, const bool add_us); static bool collection_object_remove(Main *bmain, Collection *collection, Object *ob, const bool free_us); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 516b121031e..6b0c59fb557 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -119,7 +119,7 @@ void ED_view3d_cursor3d_position_rotation( float cursor_co[3], float cursor_quat[4]); void ED_view3d_cursor3d_update( struct bContext *C, const int mval[2], - bool use_depth, enum eV3DCursorOrient orientation); + const bool use_depth, enum eV3DCursorOrient orientation); struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 2cc1236e5c6..e94d3a13225 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4625,7 +4625,7 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot) /* cursor position in vec, result in vec, mval in region coords */ /* note: cannot use event->mval here (called by object_add() */ -void ED_view3d_cursor3d_position(bContext *C, const int mval[2], bool use_depth, float cursor_co[3]) +void ED_view3d_cursor3d_position(bContext *C, const int mval[2], const bool use_depth, float cursor_co[3]) { ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index a5706f4a003..675441189b0 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -747,7 +747,7 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) /* sets transform flags in the bones * returns total number of bones with BONE_TRANSFORM */ -int count_set_pose_transflags(Object *ob, const int mode, short around, bool has_translate_rotate[2]) +int count_set_pose_transflags(Object *ob, const int mode, const short around, bool has_translate_rotate[2]) { bArmature *arm = ob->data; bPoseChannel *pchan; diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index c84ce56c58b..4964e94652c 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -2282,7 +2282,7 @@ void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func) void RNA_def_property_poll_runtime(PropertyRNA *prop, const void *func) { if (prop->type == PROP_POINTER) { - ((PointerPropertyRNA *)prop)->poll = func; + ((PointerPropertyRNA *)prop)->poll = (void *)func; } else { fprintf(stderr, "%s: %s is not a Pointer Property.\n", __func__, prop->identifier); diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c index bf9ab4a5064..af988c0df39 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.c @@ -37,7 +37,7 @@ /* this is taken from the cryptomatte specification 1.0 */ -static inline float hash_to_float(uint32_t hash) +BLI_INLINE float hash_to_float(uint32_t hash) { uint32_t mantissa = hash & ((1 << 23) - 1); uint32_t exponent = (hash >> 23) & ((1 << 8) - 1); diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h index 9b8cecfb4bc..dd39cc96d6f 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h @@ -104,7 +104,7 @@ void WM_gizmo_set_matrix_offset_rotation_from_yz_axis( struct wmGizmo *gz, const float y_axis[3], const float z_axis[3]); void WM_gizmo_set_flag(struct wmGizmo *gz, const int flag, const bool enable); -void WM_gizmo_set_scale(struct wmGizmo *gz, float scale); +void WM_gizmo_set_scale(struct wmGizmo *gz, const float scale); void WM_gizmo_set_line_width(struct wmGizmo *gz, const float line_width); void WM_gizmo_get_color(const struct wmGizmo *gz, float color[4]); -- cgit v1.2.3 From 885cc4cf9a1d5c167e4cbd26c3294d8b1ad400d8 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 25 Jul 2018 16:59:46 +0200 Subject: Build: require C11/C++11 for all operating systems in master. This is in preparation of upgrading our library dependencies, some of which need C++11. We already use C++11 in blender2.8 and for Windows and macOS, so this just affects Linux. On many distributions this will not require any changes, on some install_deps.sh will need to be run again to rebuild libraries. Differential Revision: https://developer.blender.org/D3568 --- source/blender/alembic/intern/abc_customdata.cc | 9 +-- source/blender/blenlib/BLI_compiler_compat.h | 6 +- source/blender/depsgraph/CMakeLists.txt | 22 ------- source/blender/depsgraph/util/deg_util_foreach.h | 17 +----- source/blender/depsgraph/util/deg_util_function.h | 73 ----------------------- 5 files changed, 4 insertions(+), 123 deletions(-) (limited to 'source') diff --git a/source/blender/alembic/intern/abc_customdata.cc b/source/blender/alembic/intern/abc_customdata.cc index 87545007870..f2ae1c831d1 100644 --- a/source/blender/alembic/intern/abc_customdata.cc +++ b/source/blender/alembic/intern/abc_customdata.cc @@ -26,14 +26,7 @@ #include #include - -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1900) #include -typedef std::unordered_map uv_index_map; -#else -#include -typedef std::map uv_index_map; -#endif extern "C" { #include "DNA_customdata_types.h" @@ -60,6 +53,8 @@ using Alembic::AbcGeom::OV2fGeomParam; using Alembic::AbcGeom::OC4fGeomParam; +typedef std::unordered_map uv_index_map; + static inline uint64_t uv_to_hash_key(Imath::V2f v) { /* Convert -0.0f to 0.0f, so bitwise comparison works. */ diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h index 0726e3bb343..2b53975a106 100644 --- a/source/blender/blenlib/BLI_compiler_compat.h +++ b/source/blender/blenlib/BLI_compiler_compat.h @@ -32,11 +32,7 @@ # define alloca _alloca #endif -#if defined(__cplusplus) && ((__cplusplus >= 201103L) || defined(_MSC_VER)) -# define HAS_CPP11_FEATURES -#endif - -#if (defined(__GNUC__) || defined(__clang__)) && defined(HAS_CPP11_FEATURES) +#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus) extern "C++" { /* Some magic to be sure we don't have reference in the type. */ template static inline T decltype_helper(T x) { return x; } diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index 50c0910ef02..ced045e9e2f 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -100,28 +100,6 @@ set(SRC util/deg_util_function.h ) -if(WITH_CXX11) - add_definitions(-DDEG_STD_UNORDERED_MAP) -elseif(HAVE_STD_UNORDERED_MAP_HEADER) - if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE) - add_definitions(-DDEG_STD_UNORDERED_MAP) - else() - if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE) - add_definitions(-DDEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) - else() - add_definitions(-DDEG_NO_UNORDERED_MAP) - message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)") - endif() - endif() -else() - if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE) - add_definitions(-DDEG_TR1_UNORDERED_MAP) - else() - add_definitions(-DDEG_NO_UNORDERED_MAP) - message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)") - endif() -endif() - if(WITH_LEGACY_DEPSGRAPH) add_definitions(-DWITH_LEGACY_DEPSGRAPH) endif() diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h index cb7361fc708..5484192207b 100644 --- a/source/blender/depsgraph/util/deg_util_foreach.h +++ b/source/blender/depsgraph/util/deg_util_foreach.h @@ -30,19 +30,4 @@ #pragma once -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -# define foreach(x, y) for(x : y) -#elif defined(HAVE_BOOST_FUNCTION_BINDINGS) -# include -# define foreach BOOST_FOREACH -#else -#pragma message("No available foreach() implementation. Using stub instead, disabling new depsgraph") - -#ifndef WITH_LEGACY_DEPSGRAPH -# error "Unable to build new depsgraph and legacy one is disabled." -#endif - -#define DISABLE_NEW_DEPSGRAPH - -# define foreach(x, y) for (x; false; (void)y) -#endif +#define foreach(x, y) for(x : y) diff --git a/source/blender/depsgraph/util/deg_util_function.h b/source/blender/depsgraph/util/deg_util_function.h index 38e753ce925..8863d92eb74 100644 --- a/source/blender/depsgraph/util/deg_util_function.h +++ b/source/blender/depsgraph/util/deg_util_function.h @@ -30,81 +30,8 @@ #pragma once -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1900) - #include using std::function; using namespace std::placeholders; #define function_bind std::bind - -#elif defined(HAVE_BOOST_FUNCTION_BINDINGS) - -#include -#include - -using boost::function; -#define function_bind boost::bind - -#else - -#pragma message("No available function binding implementation. Using stub instead, disabling new depsgraph") - -#ifndef WITH_LEGACY_DEPSGRAPH -# error "Unable to build new depsgraph and legacy one is disabled." -#endif - -#define DISABLE_NEW_DEPSGRAPH - -#include "BLI_utildefines.h" -#include - -template -class function { -public: - function() {}; - function(void *) {} - operator bool() const { return false; } - bool operator== (void *) { return false; } - - template - void operator() (T1) { - BLI_assert(!"Should not be used"); - } -}; - -class Wrap { -public: - Wrap() {} - template - Wrap(T /*arg*/) {} -}; - -template -void *function_bind(T func, - Wrap arg1 = Wrap(), - Wrap arg2 = Wrap(), - Wrap arg3 = Wrap(), - Wrap arg4 = Wrap(), - Wrap arg5 = Wrap(), - Wrap arg6 = Wrap(), - Wrap arg7 = Wrap()) -{ - BLI_assert(!"Should not be used"); - (void)func; - (void)arg1; - (void)arg2; - (void)arg3; - (void)arg4; - (void)arg5; - (void)arg6; - (void)arg7; - return NULL; -} - -#define _1 Wrap() -#define _2 Wrap() -#define _3 Wrap() -#define _4 Wrap() - -#endif -- cgit v1.2.3 From dee31f2cb0c3eacbd1d7a33c7fbaf3841e4a7623 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 30 Jul 2018 17:42:28 +0200 Subject: Minor cleanup. --- source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index b5b33900105..ee814e11d40 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -719,13 +719,12 @@ static void deg_update_copy_on_write_animation(const Depsgraph *depsgraph, } typedef struct ObjectRuntimeBackup { - CurveCache *curve_cache; Object_Runtime runtime; short base_flag; } ObjectRuntimeBackup; /* Make a backup of object's evaluation runtime data, additionally - * male object to be safe for free without invalidating backed up + * make object to be safe for free without invalidating backed up * pointers. */ static void deg_backup_object_runtime( -- cgit v1.2.3 From f08f6c1adecd5f65c77a33213be3a1bd80968473 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 31 Jul 2018 03:48:37 +1200 Subject: Clean Keyframes operator tweaks By popular demand, the CLean Keyframes operator will now leave handles and other interpolation settings untouched. Previously, it would recreate the keyframes from scratch, keeping only the frame + value, under the assumption that the handle information was "bad" (i.e. the source of bumps and roughness, due to bad hand tweaking). However, since most animators use this on hand-keyed animation instead of motion-capture data, this assumption didn't hold, and was actually overly destructive - wiping out lots of hand-adjusted curve data. --- source/blender/editors/animation/keyframes_general.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'source') diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index a6ed6643257..b98feac2384 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -183,7 +183,8 @@ void duplicate_fcurve_keys(FCurve *fcu) /* Various Tools */ /* Basic F-Curve 'cleanup' function that removes 'double points' and unnecessary keyframes on linear-segments only - * optionally clears up curve if one keyframe with default value remains */ + * optionally clears up curve if one keyframe with default value remains + */ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, bool cleardefault) { FCurve *fcu = (FCurve *)ale->key_data; @@ -206,7 +207,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo /* now insert first keyframe, as it should be ok */ bezt = old_bezts; - insert_vert_fcurve(fcu, bezt->vec[1][0], bezt->vec[1][1], BEZKEYTYPE(bezt), 0); + insert_bezt_fcurve(fcu, bezt, 0); if (!(bezt->f2 & SELECT)) { lastb = fcu->bezt; lastb->f1 = lastb->f2 = lastb->f3 = 0; @@ -235,7 +236,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1]; if (!(bezt->f2 & SELECT)) { - insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); + insert_bezt_fcurve(fcu, bezt, 0); lastb = (fcu->bezt + (fcu->totvert - 1)); lastb->f1 = lastb->f2 = lastb->f3 = 0; continue; @@ -254,7 +255,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo if (cur[1] > next[1]) { if (IS_EQT(cur[1], prev[1], thresh) == 0) { /* add new keyframe */ - insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); + insert_bezt_fcurve(fcu, bezt, 0); } } } @@ -262,7 +263,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo /* only add if values are a considerable distance apart */ if (IS_EQT(cur[1], prev[1], thresh) == 0) { /* add new keyframe */ - insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); + insert_bezt_fcurve(fcu, bezt, 0); } } } @@ -271,19 +272,19 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo if (beztn) { /* does current have same value as previous and next? */ if (IS_EQT(cur[1], prev[1], thresh) == 0) { - /* add new keyframe*/ - insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); + /* add new keyframe */ + insert_bezt_fcurve(fcu, bezt, 0); } else if (IS_EQT(cur[1], next[1], thresh) == 0) { /* add new keyframe */ - insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); + insert_bezt_fcurve(fcu, bezt, 0); } } else { /* add if value doesn't equal that of previous */ if (IS_EQT(cur[1], prev[1], thresh) == 0) { /* add new keyframe */ - insert_vert_fcurve(fcu, cur[0], cur[1], BEZKEYTYPE(bezt), 0); + insert_bezt_fcurve(fcu, bezt, 0); } } } -- cgit v1.2.3 From cc397b918ff1b2a51b3b82367506eb7684860cea Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 30 Jul 2018 18:25:01 +0200 Subject: UI: make horizontal wheel scroll in 2D view match vertical scroll speed. --- source/blender/editors/interface/view2d_ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index dfc401c1635..1c56dabb396 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -354,7 +354,7 @@ static int view_scrollright_exec(bContext *C, wmOperator *op) } /* set RNA-Props - only movement in positive x-direction */ - RNA_int_set(op->ptr, "deltax", 20); + RNA_int_set(op->ptr, "deltax", 40); RNA_int_set(op->ptr, "deltay", 0); /* apply movement, then we're done */ @@ -398,7 +398,7 @@ static int view_scrollleft_exec(bContext *C, wmOperator *op) } /* set RNA-Props - only movement in negative x-direction */ - RNA_int_set(op->ptr, "deltax", -20); + RNA_int_set(op->ptr, "deltax", -40); RNA_int_set(op->ptr, "deltay", 0); /* apply movement, then we're done */ -- cgit v1.2.3 From c86b5fa820d181c2beabdf4147ac17cb6ff8149b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 30 Jul 2018 15:44:25 +0200 Subject: Viewport: use Filmic without scene exposure/gamma/curves for workbench. This ignores the scene color managment view settings for solid mode and lookdev when not using scene lights and world. The scene settings are intended for tweaking renders and should not affect studio lighting and matcaps. There may be cases where a simple sRGB transform is better than Filmic and we could add configuration for this. Not sure if it really matters and it may be better if we just assume matcaps and studiolights are all created for one view transform. Differential Revision: https://developer.blender.org/D3569 --- source/blender/draw/engines/eevee/eevee_engine.c | 23 ++++++++++++---------- source/blender/draw/engines/eevee/eevee_private.h | 3 +++ .../draw/engines/workbench/workbench_data.c | 3 +++ .../draw/engines/workbench/workbench_effect_aa.c | 12 +++++------ .../draw/engines/workbench/workbench_private.h | 3 +++ source/blender/draw/intern/DRW_render.h | 2 +- source/blender/draw/intern/draw_manager.c | 7 +++++-- 7 files changed, 34 insertions(+), 19 deletions(-) (limited to 'source') diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index adbe165354a..8c66ba057b5 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -66,6 +66,7 @@ static void eevee_engine_init(void *ved) /* Alloc transient pointers */ stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); } + stl->g_data->use_color_view_settings = USE_SCENE_LIGHT(v3d) || !LOOK_DEV_STUDIO_LIGHT_ENABLED(v3d); stl->g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f; stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL); @@ -316,37 +317,39 @@ static void eevee_draw_background(void *vedata) /* Tonemapping and transfer result to default framebuffer. */ + bool use_view_settings = stl->g_data->use_color_view_settings; + GPU_framebuffer_bind(dfbl->default_fb); - DRW_transform_to_display(stl->effects->final_tx); + DRW_transform_to_display(stl->effects->final_tx, use_view_settings); /* Debug : Ouput buffer to view. */ switch (G.debug_value) { case 1: - if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer); + if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer, use_view_settings); break; case 2: - if (effects->ssr_pdf_output) DRW_transform_to_display(effects->ssr_pdf_output); + if (effects->ssr_pdf_output) DRW_transform_to_display(effects->ssr_pdf_output, use_view_settings); break; case 3: - if (effects->ssr_normal_input) DRW_transform_to_display(effects->ssr_normal_input); + if (effects->ssr_normal_input) DRW_transform_to_display(effects->ssr_normal_input, use_view_settings); break; case 4: - if (effects->ssr_specrough_input) DRW_transform_to_display(effects->ssr_specrough_input); + if (effects->ssr_specrough_input) DRW_transform_to_display(effects->ssr_specrough_input, use_view_settings); break; case 5: - if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer); + if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer, use_view_settings); break; case 6: - if (effects->gtao_horizons_debug) DRW_transform_to_display(effects->gtao_horizons_debug); + if (effects->gtao_horizons_debug) DRW_transform_to_display(effects->gtao_horizons_debug, use_view_settings); break; case 7: - if (effects->gtao_horizons) DRW_transform_to_display(effects->gtao_horizons); + if (effects->gtao_horizons) DRW_transform_to_display(effects->gtao_horizons, use_view_settings); break; case 8: - if (effects->sss_data) DRW_transform_to_display(effects->sss_data); + if (effects->sss_data) DRW_transform_to_display(effects->sss_data, use_view_settings); break; case 9: - if (effects->velocity_tx) DRW_transform_to_display(effects->velocity_tx); + if (effects->velocity_tx) DRW_transform_to_display(effects->velocity_tx, use_view_settings); break; default: break; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 349a27a1765..bd1323dab3b 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -774,6 +774,9 @@ typedef struct EEVEE_PrivateData { /* Mist Settings */ float mist_start, mist_inv_dist, mist_falloff; + + /* Color Management */ + bool use_color_view_settings; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 24eb0f38a46..2b716b8ffe3 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -21,14 +21,17 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) View3D *v3d = draw_ctx->v3d; if (!v3d) { wpd->shading = scene->display.shading; + wpd->use_color_view_settings = true; } else if (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_opengl(scene)) { wpd->shading = scene->display.shading; + wpd->use_color_view_settings = true; } else { wpd->shading = v3d->shading; + wpd->use_color_view_settings = false; } if (wpd->shading.light == V3D_LIGHTING_MATCAP) { diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c index 6269496f568..deb9a517f96 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_aa.c +++ b/source/blender/draw/engines/workbench/workbench_effect_aa.c @@ -56,7 +56,7 @@ void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx) } } -static void workspace_aa_draw_transform(GPUTexture *tx) +static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *wpd) { if (DRW_state_is_image_render()) { /* Linear result for render. */ @@ -64,7 +64,7 @@ static void workspace_aa_draw_transform(GPUTexture *tx) } else { /* Display space result for viewport. */ - DRW_transform_to_display(tx); + DRW_transform_to_display(tx, wpd->use_color_view_settings); } } @@ -79,7 +79,7 @@ void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx) DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); if (FXAA_ENABLED(wpd)) { GPU_framebuffer_bind(fbl->effect_fb); - workspace_aa_draw_transform(tx); + workspace_aa_draw_transform(tx, wpd); GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->effect_aa_pass); } @@ -92,11 +92,11 @@ void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx) */ if (effect_info->jitter_index == 1) { GPU_framebuffer_bind(dfbl->color_only_fb); - workspace_aa_draw_transform(tx); + workspace_aa_draw_transform(tx, wpd); } else { GPU_framebuffer_bind(fbl->effect_fb); - workspace_aa_draw_transform(tx); + workspace_aa_draw_transform(tx, wpd); GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->effect_aa_pass); } @@ -104,6 +104,6 @@ void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx) } else { GPU_framebuffer_bind(dfbl->color_only_fb); - workspace_aa_draw_transform(tx); + workspace_aa_draw_transform(tx, wpd); } } diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index dc2894f0207..10ea0152b90 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -187,6 +187,9 @@ typedef struct WORKBENCH_PrivateData { float viewvecs[3][4]; float ssao_params[4]; float ssao_settings[4]; + + /* Color Management */ + bool use_color_view_settings; } WORKBENCH_PrivateData; /* Transient data */ typedef struct WORKBENCH_EffectInfo { diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index d2c44cfef2a..0db16ab5472 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -234,7 +234,7 @@ void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo); } \ } while (0) -void DRW_transform_to_display(struct GPUTexture *tex); +void DRW_transform_to_display(struct GPUTexture *tex, bool use_view_settings); void DRW_transform_none(struct GPUTexture *tex); void DRW_multisamples_resolve( struct GPUTexture *src_depth, struct GPUTexture *src_color, bool use_depth); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 87239e7d93e..714edc23719 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -224,7 +224,7 @@ bool DRW_check_psys_visible_within_active_context( * \{ */ /* Use color management profile to draw texture to framebuffer */ -void DRW_transform_to_display(GPUTexture *tex) +void DRW_transform_to_display(GPUTexture *tex, bool use_view_settings) { drw_state_set(DRW_STATE_WRITE_COLOR); @@ -239,8 +239,11 @@ void DRW_transform_to_display(GPUTexture *tex) /* View transform is already applied for offscreen, don't apply again, see: T52046 */ if (!(DST.options.is_image_render && !DST.options.is_scene_render)) { Scene *scene = DST.draw_ctx.scene; + ColorManagedDisplaySettings *display_settings = &scene->display_settings; + ColorManagedViewSettings *view_settings = (use_view_settings) ? &scene->view_settings : NULL; + use_ocio = IMB_colormanagement_setup_glsl_draw_from_space( - &scene->view_settings, &scene->display_settings, NULL, dither, false); + view_settings, display_settings, NULL, dither, false); } if (!use_ocio) { -- cgit v1.2.3 From 1195a4a040ba8ecffd3221f5aa38c7be5272124b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 10:37:46 +1000 Subject: UI: add check for any kind of popup Fixes T56155 when merging into 2.8 --- source/blender/editors/interface/interface_context_menu.c | 2 +- source/blender/editors/interface/interface_intern.h | 1 + source/blender/editors/interface/interface_query.c | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 0306139bac0..54e755f6cc6 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -533,7 +533,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) } /* Show header tools for header buttons. */ - if (ui_block_is_menu(but->block) == false) { + if (ui_block_is_popup_any(but->block) == false) { ARegion *ar = CTX_wm_region(C); if (ar && (ar->regiontype == RGN_TYPE_HEADER)) { uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index dc5e100b5f2..75f2efdf3aa 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -752,6 +752,7 @@ bool ui_but_is_toggle(const uiBut *but); extern bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; +extern bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; /* interface_context_menu.c */ bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but); diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index f7dbb9b14ed..1ad4a7d7f31 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -86,6 +86,14 @@ bool ui_block_is_pie_menu(const uiBlock *block) return ((block->flag & UI_BLOCK_RADIAL) != 0); } +bool ui_block_is_popup_any(const uiBlock *block) +{ + return ( + ui_block_is_menu(block) || + ui_block_is_pie_menu(block) + ); +} + bool UI_block_is_empty(const uiBlock *block) { for (const uiBut *but = block->buttons.first; but; but = but->next) { -- cgit v1.2.3 From 0c955ed6eab2544ebad8823e509cc348b33c3556 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 10:45:35 +1000 Subject: Fix T56155: Header shows in popover context menu --- source/blender/editors/interface/interface_intern.h | 1 + source/blender/editors/interface/interface_query.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'source') diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 4f260c35797..d4fccc48bfc 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -831,6 +831,7 @@ bool ui_but_is_toggle(const uiBut *but); bool ui_but_is_popover_once_compat(const uiBut *but); extern bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; +extern bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; extern bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index 8893a5e17cc..d0f7e1341de 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -109,6 +109,11 @@ bool ui_block_is_menu(const uiBlock *block) ((block->flag & UI_BLOCK_KEEP_OPEN) == 0)); } +bool ui_block_is_popover(const uiBlock *block) +{ + return (block->flag & UI_BLOCK_POPOVER) != 0; +} + bool ui_block_is_pie_menu(const uiBlock *block) { return ((block->flag & UI_BLOCK_RADIAL) != 0); @@ -118,6 +123,7 @@ bool ui_block_is_popup_any(const uiBlock *block) { return ( ui_block_is_menu(block) || + ui_block_is_popover(block) || ui_block_is_pie_menu(block) ); } -- cgit v1.2.3 From 18888b7b0c3556d3a2177fe7693fda02bf2a8cb5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 16:05:31 +1000 Subject: UI: use text hinting (now user preference) D3201 by @ambient w/ edits not to impact fonts used for rendering (only change display for UI text). --- source/blender/editors/interface/interface_style.c | 22 ++++++++++++++++++++++ source/blender/makesdna/DNA_userdef_types.h | 3 ++- source/blender/makesrna/intern/rna_userdef.c | 6 ++++++ 3 files changed, 30 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index eabc5150424..9a09ae67601 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -521,6 +521,28 @@ void uiStyleInit(void) BLF_size(blf_mono_font, 12 * U.pixelsize, 72); + /* Set default flags based on UI preferences (not render fonts) */ + { + int flag_enable = 0, flag_disable = 0; + if ((U.text_render & USER_TEXT_DISABLE_HINTING) == 0) { + flag_enable |= BLF_HINTING; + } + else { + flag_disable |= BLF_HINTING; + } + + for (font = U.uifonts.first; font; font = font->next) { + if (font->blf_id != -1) { + BLF_enable(font->blf_id, flag_enable); + BLF_disable(font->blf_id, flag_disable); + } + } + if (blf_mono_font != -1) { + BLF_enable(blf_mono_font, flag_enable); + BLF_disable(blf_mono_font, flag_disable); + } + } + /** * Second for rendering else we get threading problems, * diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 2d52c1a67de..6f0f97261ee 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -804,7 +804,8 @@ typedef enum eWM_DrawMethod { /* text draw options * UserDef.text_render */ typedef enum eText_Draw_Options { - USER_TEXT_DISABLE_AA = (1 << 0), + USER_TEXT_DISABLE_AA = (1 << 0), + USER_TEXT_DISABLE_HINTING = (1 << 1), } eText_Draw_Options; /* tw_flag (transform widget) */ diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 487f62cdfe6..739303e20ea 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -447,6 +447,7 @@ static void rna_userdef_temp_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P static void rna_userdef_text_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { BLF_cache_clear(); + UI_reinit_font(); WM_main_add_notifier(NC_WINDOW, NULL); } @@ -4212,6 +4213,11 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); RNA_def_property_update(prop, 0, "rna_userdef_text_antialiasing_update"); + prop = RNA_def_property(srna, "use_text_hinting", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_HINTING); + RNA_def_property_ui_text(prop, "Text Hinting", "Draw user interface text with hinting"); + RNA_def_property_update(prop, 0, "rna_userdef_text_update"); + prop = RNA_def_property(srna, "select_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "gpu_select_method"); RNA_def_property_enum_items(prop, gpu_select_method_items); -- cgit v1.2.3 From b51dcb6f07f34c904b036887e24f96542d9fb76d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 16:44:35 +1000 Subject: Fix crash w/ missing matcaps Building w/o EXR caused this. --- source/blender/draw/engines/workbench/workbench_data.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'source') diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 2b716b8ffe3..49cdab256f0 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -42,6 +42,13 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->studio_light = BKE_studiolight_find( wpd->shading.studio_light, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD); } + + /* If matcaps are missing, use this as fallback. */ + if (UNLIKELY(wpd->studio_light == NULL)) { + wpd->studio_light = BKE_studiolight_find( + wpd->shading.studio_light, STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD); + } + wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; WORKBENCH_UBO_World *wd = &wpd->world_data; -- cgit v1.2.3 From 21f61cbe73a1bc24d2e74b82b039ea5f36c960a5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 16:57:05 +1000 Subject: BLF: replace global aa pref w/ monochrome flag Now disabling anti-aliasing doesn't impact sequencer, render stamp etc. --- source/blender/blenfont/BLF_api.h | 4 +--- source/blender/blenfont/intern/blf.c | 11 ----------- source/blender/blenfont/intern/blf_glyph.c | 11 ++++++----- source/blender/editors/interface/interface_style.c | 7 +++++++ source/blender/makesrna/intern/rna_userdef.c | 8 +------- source/blender/python/generic/blf_py_api.c | 1 + source/blender/windowmanager/intern/wm_files.c | 2 -- 7 files changed, 16 insertions(+), 28 deletions(-) (limited to 'source') diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index eafcf74b611..9bb3dd39aa6 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -44,9 +44,6 @@ void BLF_exit(void); void BLF_default_dpi(int dpi); void BLF_default_set(int fontid); -void BLF_antialias_set(bool enabled); -bool BLF_antialias_get(void); - void BLF_cache_clear(void); int BLF_load(const char *name) ATTR_NONNULL(); @@ -223,6 +220,7 @@ void BLF_state_print(int fontid); #define BLF_ASPECT (1 << 5) #define BLF_HINTING (1 << 6) #define BLF_WORD_WRAP (1 << 7) +#define BLF_MONOCHROME (1 << 8) /* no-AA */ #define BLF_DRAW_STR_DUMMY_MAX 1024 diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 2a8fc14f4ae..75aabf1f713 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -84,7 +84,6 @@ static FontBLF *global_font[BLF_MAX_FONT] = {NULL}; static int global_font_default = -1; static int global_font_points = 11; static int global_font_dpi = 72; -static bool global_use_antialias = true; /* XXX, should these be made into global_font_'s too? */ int blf_mono_font = -1; @@ -176,16 +175,6 @@ void BLF_default_set(int fontid) } } -void BLF_antialias_set(bool enabled) -{ - global_use_antialias = enabled; -} - -bool BLF_antialias_get(void) -{ - return global_use_antialias; -} - int BLF_load(const char *name) { FontBLF *font; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 9af347908e1..f1301d38ab6 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -221,7 +221,6 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) GlyphBLF *g; FT_Error err; FT_Bitmap bitmap, tempbitmap; - const bool is_sharp = !BLF_antialias_get(); int flags = FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; FT_BBox bbox; unsigned int key; @@ -246,10 +245,12 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) if (font->flags & BLF_HINTING) flags &= ~FT_LOAD_NO_HINTING; - if (is_sharp) + if (font->flags & BLF_MONOCHROME) { err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_MONO); - else + } + else { err = FT_Load_Glyph(font->face, (FT_UInt)index, flags); + } if (err) { BLI_spin_unlock(font->ft_lib_mutex); @@ -259,7 +260,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) /* get the glyph. */ slot = font->face->glyph; - if (is_sharp) { + if (font->flags & BLF_MONOCHROME) { err = FT_Render_Glyph(slot, FT_RENDER_MODE_MONO); /* Convert result from 1 bit per pixel to 8 bit per pixel */ @@ -288,7 +289,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) g->height = (int)bitmap.rows; if (g->width && g->height) { - if (is_sharp) { + if (font->flags & BLF_MONOCHROME) { /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */ int i; for (i = 0; i < (g->width * g->height); i++) { diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 9a09ae67601..0257fb0d428 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -531,6 +531,13 @@ void uiStyleInit(void) flag_disable |= BLF_HINTING; } + if (U.text_render & USER_TEXT_DISABLE_AA) { + flag_enable |= BLF_MONOCHROME; + } + else { + flag_disable |= BLF_MONOCHROME; + } + for (font = U.uifonts.first; font; font = font->next) { if (font->blf_id != -1) { BLF_enable(font->blf_id, flag_enable); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 739303e20ea..315ac26c1d2 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -451,12 +451,6 @@ static void rna_userdef_text_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P WM_main_add_notifier(NC_WINDOW, NULL); } -static void rna_userdef_text_antialiasing_update(Main *bmain, Scene *scene, PointerRNA *ptr) -{ - BLF_antialias_set((U.text_render & USER_TEXT_DISABLE_AA) == 0); - rna_userdef_text_update(bmain, scene, ptr); -} - static PointerRNA rna_Theme_space_generic_get(PointerRNA *ptr) { return rna_pointer_inherit_refine(ptr, &RNA_ThemeSpaceGeneric, ptr->data); @@ -4211,7 +4205,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "use_text_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA); RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); - RNA_def_property_update(prop, 0, "rna_userdef_text_antialiasing_update"); + RNA_def_property_update(prop, 0, "rna_userdef_text_update"); prop = RNA_def_property(srna, "use_text_hinting", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_HINTING); diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 629335888e4..7d124966334 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -461,6 +461,7 @@ PyObject *BPyInit_blf(void) PyModule_AddIntConstant(submodule, "SHADOW", BLF_SHADOW); PyModule_AddIntConstant(submodule, "KERNING_DEFAULT", BLF_KERNING_DEFAULT); PyModule_AddIntConstant(submodule, "WORD_WRAP", BLF_WORD_WRAP); + PyModule_AddIntConstant(submodule, "MONOCHROME", BLF_MONOCHROME); return submodule; } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 19b48e3f79e..a802c695dd1 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -343,8 +343,6 @@ static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory) /* update tempdir from user preferences */ BKE_tempdir_init(U.tempdir); - - BLF_antialias_set((U.text_render & USER_TEXT_DISABLE_AA) == 0); } -- cgit v1.2.3 From 51c38b5d495e406a0c13216470927c5ce0f71e4f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 25 Jul 2018 16:51:48 +0200 Subject: Subsurf: Rework in a way that patches boundaries are merged together The idea is to create vertices along the coarse edges once, without splitting coarse edges on separate ptex faces. This requires some indexing magic, vertices within a patch are no longer sequential. Not sure how to make it nicer without such a black magic looking calculations (which are basically boiling down to mimicking order of verts/edges creation). In the current offsets calculation loose verts and edges are not properly taken into account, but those are causing topology refiner to fail anyway, so it needs a bit deeper change. Reviewers: brecht Differential Revision: https://developer.blender.org/D3570 --- source/blender/blenkernel/BKE_subdiv.h | 3 + source/blender/blenkernel/intern/subdiv_mesh.c | 1707 +++++++++++++++++++---- source/blender/blenkernel/intern/subdiv_stats.c | 4 + source/blender/blenlib/BLI_bitmap.h | 6 + source/blender/modifiers/intern/MOD_subsurf.c | 2 +- 5 files changed, 1464 insertions(+), 258 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h index 003dc7a37d3..ad829946db8 100644 --- a/source/blender/blenkernel/BKE_subdiv.h +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -57,6 +57,7 @@ typedef struct SubdivSettings { typedef enum eSubdivStatsValue { SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME = 0, SUBDIV_STATS_SUBDIV_TO_MESH, + SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY, SUBDIV_STATS_EVALUATOR_CREATE, SUBDIV_STATS_EVALUATOR_REFINE, @@ -73,6 +74,8 @@ typedef struct SubdivStats { double topology_refiner_creation_time; /* Total time spent in BKE_subdiv_to_mesh(). */ double subdiv_to_mesh_time; + /* Geometry (MVert and co) creation time during SUBDIV_TYO_MESH. */ + double subdiv_to_mesh_geometry_time; /* Time spent on evaluator creation from topology refiner. */ double evaluator_creation_time; /* Time spent on evaluator->refine(). */ diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 76f41d512bc..40c95964fb3 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -29,10 +29,13 @@ #include "BKE_subdiv.h" +#include "atomic_ops.h" + #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "BLI_alloca.h" +#include "BLI_bitmap.h" #include "BLI_math_vector.h" #include "BLI_task.h" @@ -55,6 +58,15 @@ BLI_INLINE int num_edges_per_ptex_face_get(const int resolution) return 2 * (resolution - 1) * resolution; } +BLI_INLINE int num_inner_edges_per_ptex_face_get(const int resolution) +{ + if (resolution < 2) { + return 0; + } + return (resolution - 2) * resolution + + (resolution - 1) * (resolution - 1); +} + /* Number of subdivision polygons per ptex face. */ BLI_INLINE int num_polys_per_ptex_get(const int resolution) { @@ -85,7 +97,19 @@ typedef struct SubdivMeshContext { /* UV layers interpolation. */ int num_uv_layers; MLoopUV *uv_layers[MAX_MTFACE]; - + /* Counters of geometry in subdivided mesh, initialized as a part of + * offsets calculation. + */ + int num_subdiv_vertices; + int num_subdiv_edges; + int num_subdiv_loops; + int num_subdiv_polygons; + /* Offsets of various geometry in the subdivision mesh arrays. */ + int vertices_corner_offset; + int vertices_edge_offset; + int vertices_inner_offset; + int edge_boundary_offset; + int edge_inner_offset; /* Indexed by coarse polygon index, indicates offset in subdivided mesh * vertices, edges and polygons arrays, where first element of the poly * begins. @@ -97,14 +121,18 @@ typedef struct SubdivMeshContext { * created for preceding base faces. */ int *face_ptex_offset; - - /* Counters of geometry in subdivided mesh, initialized as a part of - * offsets calculation. + /* Bitmap indicating whether vertex was used already or not. + * - During patch evaluation indicates whether coarse vertex was already + * evaluated and its position on limit is already known. */ - int num_subdiv_vertices; - int num_subdiv_edges; - int num_subdiv_loops; - int num_subdiv_polygons; + BLI_bitmap *coarse_vertices_used_map; + /* Bitmap indicating whether edge was used already or not. This includes: + * - During context initialization it indicates whether subdivided verticies + * for corresponding edge were already calculated or not. + * - During patch evaluation it indicates whether vertices along this edge + * were already evaluated. + */ + BLI_bitmap *coarse_edges_used_map; } SubdivMeshContext; static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx) @@ -134,60 +162,162 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx) subdiv_mesh_ctx_cache_uv_layers(ctx); } +/* NOTE: Expects edge map to be zeroed. */ +static void subdiv_mesh_ctx_count(SubdivMeshContext *ctx) +{ + /* Reset counters. */ + ctx->num_subdiv_vertices = 0; + ctx->num_subdiv_edges = 0; + ctx->num_subdiv_loops = 0; + ctx->num_subdiv_polygons = 0; + /* Static geometry counters. */ + const int resolution = ctx->settings->resolution; + const int no_quad_patch_resolution = ((resolution >> 1) + 1); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_inner_vertices_per_quad = (resolution - 2) * (resolution - 2); + const int num_inner_vertices_per_noquad_patch = + (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 2); + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + ctx->num_subdiv_vertices = coarse_mesh->totvert; + ctx->num_subdiv_edges = + coarse_mesh->totedge * (num_subdiv_vertices_per_coarse_edge + 1); + for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + const int num_ptex_faces_per_poly = + num_ptex_faces_per_poly_get(coarse_poly); + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *loop = &coarse_mloop[coarse_poly->loopstart + corner]; + const bool is_edge_used = + BLI_BITMAP_TEST_BOOL(ctx->coarse_edges_used_map, loop->e); + /* Edges which aren't counted yet. */ + if (!is_edge_used) { + BLI_BITMAP_ENABLE(ctx->coarse_edges_used_map, loop->e); + ctx->num_subdiv_vertices += num_subdiv_vertices_per_coarse_edge; + } + } + /* Inner verticies of polygon. */ + if (num_ptex_faces_per_poly == 1) { + ctx->num_subdiv_vertices += num_inner_vertices_per_quad; + ctx->num_subdiv_edges += + num_edges_per_ptex_face_get(resolution - 2) + + 4 * num_subdiv_vertices_per_coarse_edge; + ctx->num_subdiv_polygons += num_polys_per_ptex_get(resolution); + } + else { + ctx->num_subdiv_vertices += + 1 + + num_ptex_faces_per_poly * (no_quad_patch_resolution - 2) + + num_ptex_faces_per_poly * num_inner_vertices_per_noquad_patch; + ctx->num_subdiv_edges += + num_ptex_faces_per_poly * + (num_inner_edges_per_ptex_face_get( + no_quad_patch_resolution - 1) + + (no_quad_patch_resolution - 2) + + num_subdiv_vertices_per_coarse_edge); + if (no_quad_patch_resolution >= 3) { + ctx->num_subdiv_edges += coarse_poly->totloop; + } + ctx->num_subdiv_polygons += + num_ptex_faces_per_poly * + num_polys_per_ptex_get(no_quad_patch_resolution); + } + } + ctx->num_subdiv_loops = ctx->num_subdiv_polygons * 4; +} + static void subdiv_mesh_ctx_init_offsets(SubdivMeshContext *ctx) { const Mesh *coarse_mesh = ctx->coarse_mesh; + const int resolution = ctx->settings->resolution; + const int resolution_2 = resolution - 2; + const int resolution_2_squared = resolution_2 * resolution_2; + const int no_quad_patch_resolution = ((resolution >> 1) + 1); + const int num_irregular_vertices_per_patch = + (no_quad_patch_resolution - 2) * (no_quad_patch_resolution - 1); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + /* Constant offsets in arrays. */ + ctx->vertices_corner_offset = 0; + ctx->vertices_edge_offset = coarse_mesh->totvert; + ctx->vertices_inner_offset = + ctx->vertices_edge_offset + + coarse_mesh->totedge * num_subdiv_vertices_per_coarse_edge; + ctx->edge_boundary_offset = 0; + ctx->edge_inner_offset = + ctx->edge_boundary_offset + + coarse_mesh->totedge * num_subdiv_edges_per_coarse_edge; + /* "Indexed" offsets. */ const MPoly *coarse_mpoly = coarse_mesh->mpoly; - /* Allocate memory. */ - ctx->subdiv_vertex_offset = MEM_malloc_arrayN( - coarse_mesh->totpoly, - sizeof(*ctx->subdiv_vertex_offset), - "vertex_offset"); - ctx->subdiv_edge_offset = MEM_malloc_arrayN( - coarse_mesh->totpoly, - sizeof(*ctx->subdiv_edge_offset), - "subdiv_edge_offset"); - ctx->subdiv_polygon_offset = MEM_malloc_arrayN( - coarse_mesh->totpoly, - sizeof(*ctx->subdiv_polygon_offset), - "subdiv_polygon_offset"); - ctx->face_ptex_offset = MEM_malloc_arrayN(coarse_mesh->totpoly, - sizeof(*ctx->face_ptex_offset), - "face_ptex_offset"); - /* Fill in offsets. */ int vertex_offset = 0; int edge_offset = 0; int polygon_offset = 0; int face_ptex_offset = 0; for (int poly_index = 0; poly_index < coarse_mesh->totpoly; poly_index++) { const MPoly *coarse_poly = &coarse_mpoly[poly_index]; - const int ptex_face_resolution = ptex_face_resolution_get( - coarse_poly, ctx->settings->resolution); - const int ptex_face_resolution2 = - ptex_face_resolution * ptex_face_resolution; const int num_ptex_faces_per_poly = num_ptex_faces_per_poly_get(coarse_poly); + ctx->face_ptex_offset[poly_index] = face_ptex_offset; ctx->subdiv_vertex_offset[poly_index] = vertex_offset; ctx->subdiv_edge_offset[poly_index] = edge_offset; ctx->subdiv_polygon_offset[poly_index] = polygon_offset; - ctx->face_ptex_offset[poly_index] = face_ptex_offset; - vertex_offset += num_ptex_faces_per_poly * ptex_face_resolution2; - edge_offset += num_ptex_faces_per_poly * - num_edges_per_ptex_face_get(ptex_face_resolution); - polygon_offset += - num_ptex_faces_per_poly * - num_polys_per_ptex_get(ptex_face_resolution); face_ptex_offset += num_ptex_faces_per_poly; + if (num_ptex_faces_per_poly == 1) { + vertex_offset += resolution_2_squared; + edge_offset += num_edges_per_ptex_face_get(resolution - 2) + + 4 * num_subdiv_vertices_per_coarse_edge; + polygon_offset += num_polys_per_ptex_get(resolution); + } + else { + vertex_offset += + 1 + + num_ptex_faces_per_poly * num_irregular_vertices_per_patch; + edge_offset += + num_ptex_faces_per_poly * + (num_inner_edges_per_ptex_face_get( + no_quad_patch_resolution - 1) + + (no_quad_patch_resolution - 2) + + num_subdiv_vertices_per_coarse_edge); + if (no_quad_patch_resolution >= 3) { + edge_offset += coarse_poly->totloop; + } + polygon_offset += + num_ptex_faces_per_poly * + num_polys_per_ptex_get(no_quad_patch_resolution); + } } - ctx->num_subdiv_vertices = vertex_offset; - ctx->num_subdiv_edges = edge_offset; - ctx->num_subdiv_polygons = polygon_offset; - ctx->num_subdiv_loops = 4 * ctx->num_subdiv_polygons; } static void subdiv_mesh_ctx_init(SubdivMeshContext *ctx) { + const Mesh *coarse_mesh = ctx->coarse_mesh; + /* Allocate maps and offsets. */ + ctx->coarse_vertices_used_map = + BLI_BITMAP_NEW(coarse_mesh->totvert, "vertices used map"); + ctx->coarse_edges_used_map = + BLI_BITMAP_NEW(coarse_mesh->totedge, "edges used map"); + ctx->subdiv_vertex_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_vertex_offset), + "vertex_offset"); + ctx->subdiv_edge_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_edge_offset), + "subdiv_edge_offset"); + ctx->subdiv_polygon_offset = MEM_malloc_arrayN( + coarse_mesh->totpoly, + sizeof(*ctx->subdiv_polygon_offset), + "subdiv_edge_offset"); + ctx->face_ptex_offset = MEM_malloc_arrayN(coarse_mesh->totpoly, + sizeof(*ctx->face_ptex_offset), + "face_ptex_offset"); + /* Initialize all offsets. */ subdiv_mesh_ctx_init_offsets(ctx); + /* Calculate number of geometry in the result subdivision mesh. */ + subdiv_mesh_ctx_count(ctx); + /* Re-set maps which were used at this step. */ + BLI_BITMAP_SET_ALL(ctx->coarse_edges_used_map, false, coarse_mesh->totedge); } static void subdiv_mesh_ctx_init_result(SubdivMeshContext *ctx) @@ -197,8 +327,11 @@ static void subdiv_mesh_ctx_init_result(SubdivMeshContext *ctx) static void subdiv_mesh_ctx_free(SubdivMeshContext *ctx) { + MEM_freeN(ctx->coarse_vertices_used_map); + MEM_freeN(ctx->coarse_edges_used_map); MEM_freeN(ctx->subdiv_vertex_offset); MEM_freeN(ctx->subdiv_edge_offset); + MEM_freeN(ctx->subdiv_polygon_offset); MEM_freeN(ctx->face_ptex_offset); } @@ -220,10 +353,11 @@ static void loops_of_ptex_get( const SubdivMeshContext *ctx, LoopsOfPtex *loops_of_ptex, const MPoly *coarse_poly, - const int ptex_face_index) + const int ptex_of_poly_index) { const MLoop *coarse_mloop = ctx->coarse_mesh->mloop; - const int first_ptex_loop_index = coarse_poly->loopstart + ptex_face_index; + const int first_ptex_loop_index = + coarse_poly->loopstart + ptex_of_poly_index; /* Loop which look in the (opposite) V direction of the current * ptex face. * @@ -231,7 +365,8 @@ static void loops_of_ptex_get( */ const int last_ptex_loop_index = coarse_poly->loopstart + - (ptex_face_index + coarse_poly->totloop - 1) % coarse_poly->totloop; + (ptex_of_poly_index + coarse_poly->totloop - 1) % + coarse_poly->totloop; loops_of_ptex->first_loop = &coarse_mloop[first_ptex_loop_index]; loops_of_ptex->last_loop = &coarse_mloop[last_ptex_loop_index]; if (coarse_poly->totloop == 4) { @@ -248,6 +383,8 @@ static void loops_of_ptex_get( * Edge custom data copy helpers. */ +#if 0 + typedef struct EdgesOfPtex { /* First edge of the ptex, starts at ptex (0, 0) and goes in u direction. */ const MEdge *first_edge; @@ -281,6 +418,8 @@ static void edges_of_ptex_get( } } +#endif + /* ============================================================================= * Vertex custom data interpolation helpers. */ @@ -370,7 +509,7 @@ static void vertex_interpolation_from_ptex( const SubdivMeshContext *ctx, VerticesForInterpolation *vertex_interpolation, const MPoly *coarse_poly, - const int ptex_face_index) + const int ptex_of_poly_index) { if (coarse_poly->totloop == 4) { /* Nothing to do, all indices and data is already assigned. */ @@ -380,12 +519,12 @@ static void vertex_interpolation_from_ptex( const Mesh *coarse_mesh = ctx->coarse_mesh; const MLoop *coarse_mloop = coarse_mesh->mloop; LoopsOfPtex loops_of_ptex; - loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, ptex_face_index); + loops_of_ptex_get(ctx, &loops_of_ptex, coarse_poly, ptex_of_poly_index); /* Ptex face corner corresponds to a poly loop with same index. */ CustomData_copy_data( vertex_data, &vertex_interpolation->vertex_data_storage, - coarse_mloop[coarse_poly->loopstart + ptex_face_index].v, + coarse_mloop[coarse_poly->loopstart + ptex_of_poly_index].v, 0, 1); /* Interpolate remaining ptex face corners, which hits loops @@ -563,13 +702,28 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) * Vertex subdivision process. */ -static void subdiv_copy_vertex_data( +/* Custom data interpolation helpers. */ + +static void subdiv_vertex_data_copy( + const SubdivMeshContext *ctx, + const MVert *coarse_vertex, + MVert *subdiv_vertex) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + const int coarse_vertex_index = coarse_vertex - coarse_mesh->mvert; + const int subdiv_vertex_index = subdiv_vertex - subdiv_mesh->mvert; + CustomData_copy_data(&coarse_mesh->vdata, + &ctx->subdiv_mesh->vdata, + coarse_vertex_index, + subdiv_vertex_index, + 1); +} + +static void subdiv_vertex_data_interpolate( const SubdivMeshContext *ctx, MVert *subdiv_vertex, - const Mesh *UNUSED(coarse_mesh), - const MPoly *coarse_poly, const VerticesForInterpolation *vertex_interpolation, - const int UNUSED(ptex_of_poly_index), const float u, const float v) { const int subdiv_vertex_index = subdiv_vertex - ctx->subdiv_mesh->mvert; @@ -585,93 +739,384 @@ static void subdiv_copy_vertex_data( subdiv_vertex_index); if (ctx->vert_origindex != NULL) { ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; - if (coarse_poly->totloop == 4) { - if (u == 0.0f && v == 0.0f) { - // ctx->vert_origindex[subdiv_vertex_index] = - // vertex_interpolation->vertex_indices[0]; - } - else if (u == 1.0f && v == 0.0f) { - // ctx->vert_origindex[subdiv_vertex_index] = - // vertex_interpolation->vertex_indices[1]; - } - else if (u == 1.0f && v == 1.0f) { - // ctx->vert_origindex[subdiv_vertex_index] = - // vertex_interpolation->vertex_indices[2]; - } - else if (u == 0.0f && v == 1.0f) { - // ctx->vert_origindex[subdiv_vertex_index] = - // vertex_interpolation->vertex_indices[3]; + } +} + +/* Evaluation of corner vertices. They are coming from coarse vertices. */ + +static void subdiv_evaluate_corner_vertices_regular( + SubdivMeshContext *ctx, + const MPoly *coarse_poly) +{ + const float weights[4][2] = {{0.0f, 0.0f}, + {1.0f, 0.0f}, + {1.0f, 1.0f}, + {0.0f, 1.0f}}; + Subdiv *subdiv = ctx->subdiv; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MVert *coarse_mvert = coarse_mesh->mvert; + const MLoop *coarse_mloop = coarse_mesh->mloop; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, + coarse_loop->v)) { + continue; + } + const MVert *coarse_vert = &coarse_mvert[coarse_loop->v]; + MVert *subdiv_vert = &subdiv_mvert[ + ctx->vertices_corner_offset + coarse_loop->v]; + subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + weights[corner][0], weights[corner][1], + subdiv_vert->co, subdiv_vert->no); + } +} + +static void subdiv_evaluate_corner_vertices_special( + SubdivMeshContext *ctx, + const MPoly *coarse_poly) +{ + Subdiv *subdiv = ctx->subdiv; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MVert *coarse_mvert = coarse_mesh->mvert; + const MLoop *coarse_mloop = coarse_mesh->mloop; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + int ptex_face_index = ctx->face_ptex_offset[poly_index]; + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, ptex_face_index++) + { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, + coarse_loop->v)) { + continue; + } + const MVert *coarse_vert = &coarse_mvert[coarse_loop->v]; + MVert *subdiv_vert = &subdiv_mvert[ + ctx->vertices_corner_offset + coarse_loop->v]; + subdiv_vertex_data_copy(ctx, coarse_vert, subdiv_vert); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + 0.0f, 0.0f, + subdiv_vert->co, subdiv_vert->no); + } +} + +static void subdiv_evaluate_corner_vertices(SubdivMeshContext *ctx, + const MPoly *coarse_poly) +{ + if (coarse_poly->totloop == 4) { + subdiv_evaluate_corner_vertices_regular(ctx, coarse_poly); + } + else { + subdiv_evaluate_corner_vertices_special(ctx, coarse_poly); + } +} + +/* Evaluation of edge vertices. They are coming from coarse edges. */ + +static void subdiv_evaluate_edge_vertices_regular( + SubdivMeshContext *ctx, + const MPoly *coarse_poly, + VerticesForInterpolation *vertex_interpolation) +{ + const int resolution = ctx->settings->resolution; + const int resolution_1 = resolution - 1; + const float inv_resolution_1 = 1.0f / (float)resolution_1; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + Subdiv *subdiv = ctx->subdiv; + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, + coarse_loop->e)) { + continue; + } + vertex_interpolation_from_ptex(ctx, + vertex_interpolation, + coarse_poly, + corner); + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + MVert *subdiv_vert = &subdiv_mvert[ + ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge]; + for (int vertex_index = 0; + vertex_index < num_subdiv_vertices_per_coarse_edge; + vertex_index++, subdiv_vert++) + { + float fac = (vertex_index + 1) * inv_resolution_1; + if (flip) { + fac = 1.0f - fac; } - else { - ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; + if (corner >= 2) { + fac = 1.0f - fac; } - } else { - if (u == 0.0f && v == 0.0f) { - // const MLoop *coarse_mloop = coarse_mesh->mloop; - // ctx->vert_origindex[subdiv_vertex_index] = - // coarse_mloop[coarse_poly->loopstart + - // ptex_of_poly_index].v; + float u, v; + if ((corner & 1) == 0) { + u = fac; + v = (corner == 2) ? 1.0f : 0.0f; } else { - ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; + u = (corner == 1) ? 1.0f : 0.0f; + v = fac; } + subdiv_vertex_data_interpolate(ctx, + subdiv_vert, + vertex_interpolation, + u, v); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + u, v, + subdiv_vert->co, subdiv_vert->no); } } } -static void subdiv_evaluate_vertices(SubdivMeshContext *ctx, - const int poly_index) +static void subdiv_evaluate_edge_vertices_special( + SubdivMeshContext *ctx, + const MPoly *coarse_poly, + VerticesForInterpolation *vertex_interpolation) { - Subdiv *subdiv = ctx->subdiv; const int resolution = ctx->settings->resolution; - const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; - /* Base/coarse mesh information. */ + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_vertices_per_ptex_edge = ((resolution >> 1) + 1); + const float inv_ptex_resolution_1 = + 1.0f / (float)(num_vertices_per_ptex_edge - 1); + Subdiv *subdiv = ctx->subdiv; const Mesh *coarse_mesh = ctx->coarse_mesh; - const MPoly *coarse_mpoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_mpoly[poly_index]; - const int num_ptex_faces_per_poly = - num_ptex_faces_per_poly_get(coarse_poly); - const int ptex_resolution = - ptex_face_resolution_get(coarse_poly, resolution); - const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1); - /* Hi-poly subdivided mesh. */ + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; Mesh *subdiv_mesh = ctx->subdiv_mesh; - MVert *subdiv_vertex = subdiv_mesh->mvert; - MVert *subdiv_vert = &subdiv_vertex[start_vertex_index]; - /* Actual evaluation. */ - VerticesForInterpolation vertex_interpolation; - vertex_interpolation_init(ctx, &vertex_interpolation, coarse_poly); - const int ptex_face_index = ctx->face_ptex_offset[poly_index]; - for (int ptex_of_poly_index = 0; - ptex_of_poly_index < num_ptex_faces_per_poly; - ptex_of_poly_index++) + MVert *subdiv_mvert = subdiv_mesh->mvert; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_start_index = ctx->face_ptex_offset[poly_index]; + int ptex_face_index = ptex_face_start_index; + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, ptex_face_index++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, + coarse_loop->e)) { + continue; + } vertex_interpolation_from_ptex(ctx, - &vertex_interpolation, + vertex_interpolation, coarse_poly, - ptex_of_poly_index); - const int current_ptex_face_index = - ptex_face_index + ptex_of_poly_index; - BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal( - subdiv, - current_ptex_face_index, - ptex_resolution, - subdiv_vert, offsetof(MVert, co), sizeof(MVert), - subdiv_vert, offsetof(MVert, no), sizeof(MVert)); - for (int y = 0; y < ptex_resolution; y++) { - const float v = y * inv_ptex_resolution_1; - for (int x = 0; x < ptex_resolution; x++, subdiv_vert++) { - const float u = x * inv_ptex_resolution_1; - subdiv_copy_vertex_data(ctx, - subdiv_vert, - coarse_mesh, - coarse_poly, - &vertex_interpolation, - ptex_of_poly_index, - u, v); + corner); + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + MVert *subdiv_vert = &subdiv_mvert[ + ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge]; + int veretx_delta = 1; + if (flip) { + subdiv_vert += num_subdiv_vertices_per_coarse_edge - 1; + veretx_delta = -1; + } + for (int vertex_index = 1; + vertex_index < num_vertices_per_ptex_edge; + vertex_index++, subdiv_vert += veretx_delta) + { + float u = vertex_index * inv_ptex_resolution_1; + subdiv_vertex_data_interpolate(ctx, + subdiv_vert, + vertex_interpolation, + u, 0.0f); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + u, 0.0f, + subdiv_vert->co, subdiv_vert->no); + } + const int next_ptex_face_index = + ptex_face_start_index + (corner + 1) % coarse_poly->totloop; + for (int vertex_index = 1; + vertex_index < num_vertices_per_ptex_edge - 1; + vertex_index++, subdiv_vert += veretx_delta) + { + float v = 1.0f - vertex_index * inv_ptex_resolution_1; + subdiv_vertex_data_interpolate(ctx, + subdiv_vert, + vertex_interpolation, + 0.0f, v); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + next_ptex_face_index, + 0.0f, v, + subdiv_vert->co, subdiv_vert->no); + } + } +} + +static void subdiv_evaluate_edge_vertices( + SubdivMeshContext *ctx, + const MPoly *coarse_poly, + VerticesForInterpolation *vertex_interpolation) +{ + if (coarse_poly->totloop == 4) { + subdiv_evaluate_edge_vertices_regular( + ctx, coarse_poly, vertex_interpolation); + } + else { + subdiv_evaluate_edge_vertices_special( + ctx, coarse_poly, vertex_interpolation); + } +} + +/* Evaluation of inner vertices, they are coming from ptex patches. */ + +static void subdiv_evaluate_inner_vertices_regular( + SubdivMeshContext *ctx, + const MPoly *coarse_poly, + VerticesForInterpolation *vertex_interpolation) +{ + const int resolution = ctx->settings->resolution; + const float inv_resolution_1 = 1.0f / (float)(resolution - 1); + Subdiv *subdiv = ctx->subdiv; + const Mesh *coarse_mesh = ctx->coarse_mesh; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; + const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; + MVert *subdiv_vert = + &subdiv_mvert[ctx->vertices_inner_offset + start_vertex_index]; + vertex_interpolation_from_ptex(ctx, + vertex_interpolation, + coarse_poly, + 0); + for (int y = 1; y < resolution - 1; y++) { + const float v = y * inv_resolution_1; + for (int x = 1; x < resolution - 1; x++, subdiv_vert++) { + const float u = x * inv_resolution_1; + subdiv_vertex_data_interpolate(ctx, + subdiv_vert, + vertex_interpolation, + u, v); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + u, v, + subdiv_vert->co, subdiv_vert->no); + } + } +} + +static void subdiv_evaluate_inner_vertices_special( + SubdivMeshContext *ctx, + const MPoly *coarse_poly, + VerticesForInterpolation *vertex_interpolation) +{ + const int resolution = ctx->settings->resolution; + const int ptex_face_resolution = ptex_face_resolution_get( + coarse_poly, resolution); + const float inv_ptex_face_resolution_1 = + 1.0f / (float)(ptex_face_resolution - 1); + Subdiv *subdiv = ctx->subdiv; + const Mesh *coarse_mesh = ctx->coarse_mesh; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MVert *subdiv_mvert = subdiv_mesh->mvert; + const int poly_index = coarse_poly - coarse_mesh->mpoly; + int ptex_face_index = ctx->face_ptex_offset[poly_index]; + const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; + MVert *subdiv_vert = + &subdiv_mvert[ctx->vertices_inner_offset + start_vertex_index]; + vertex_interpolation_from_ptex(ctx, + vertex_interpolation, + coarse_poly, + 0); + subdiv_vertex_data_interpolate(ctx, + subdiv_vert, + vertex_interpolation, + 1.0f, 1.0f); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + 1.0f, 1.0f, + subdiv_vert->co, subdiv_vert->no); + subdiv_vert++; + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, ptex_face_index++) + { + if (corner != 0) { + vertex_interpolation_from_ptex(ctx, + vertex_interpolation, + coarse_poly, + corner); + } + for (int y = 1; y < ptex_face_resolution - 1; y++) { + const float v = y * inv_ptex_face_resolution_1; + for (int x = 1; x < ptex_face_resolution; x++, subdiv_vert++) { + const float u = x * inv_ptex_face_resolution_1; + subdiv_vertex_data_interpolate(ctx, + subdiv_vert, + vertex_interpolation, + u, v); + BKE_subdiv_eval_limit_point_and_short_normal( + subdiv, + ptex_face_index, + u, v, + subdiv_vert->co, subdiv_vert->no); } } } +} + +static void subdiv_evaluate_inner_vertices( + SubdivMeshContext *ctx, + const MPoly *coarse_poly, + VerticesForInterpolation *vertex_interpolation) +{ + if (coarse_poly->totloop == 4) { + subdiv_evaluate_inner_vertices_regular( + ctx, coarse_poly, vertex_interpolation); + } + else { + subdiv_evaluate_inner_vertices_special( + ctx, coarse_poly, vertex_interpolation); + } +} + +/* Evaluate all vertices which are emitted from given coarse polygon. */ +static void subdiv_evaluate_vertices(SubdivMeshContext *ctx, + const int poly_index) +{ + /* Base/coarse mesh information. */ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + /* Initialize vertex interpolation, it is reused by corner vertices, coarse + * edges and patch evaluation. + */ + VerticesForInterpolation vertex_interpolation; + vertex_interpolation_init(ctx, &vertex_interpolation, coarse_poly); + (void) vertex_interpolation; + subdiv_evaluate_corner_vertices(ctx, coarse_poly); + subdiv_evaluate_edge_vertices(ctx, coarse_poly, &vertex_interpolation); + subdiv_evaluate_inner_vertices(ctx, coarse_poly, &vertex_interpolation); vertex_interpolation_end(&vertex_interpolation); } @@ -700,20 +1145,17 @@ static void subdiv_copy_edge_data( coarse_edge_index, subdiv_edge_index, 1); - if (ctx->edge_origindex != NULL) { - ctx->edge_origindex[subdiv_edge_index] = coarse_edge_index; - } } static MEdge *subdiv_create_edges_row(SubdivMeshContext *ctx, MEdge *subdiv_edge, const MEdge *coarse_edge, const int start_vertex_index, - const int resolution) + const int num_edges_per_row) { int vertex_index = start_vertex_index; for (int edge_index = 0; - edge_index < resolution - 1; + edge_index < num_edges_per_row - 1; edge_index++, subdiv_edge++) { subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge); @@ -729,104 +1171,330 @@ static MEdge *subdiv_create_edges_column(SubdivMeshContext *ctx, const MEdge *coarse_start_edge, const MEdge *coarse_end_edge, const int start_vertex_index, - const int resolution) + const int num_edges_per_row) { int vertex_index = start_vertex_index; for (int edge_index = 0; - edge_index < resolution; + edge_index < num_edges_per_row; edge_index++, subdiv_edge++) { const MEdge *coarse_edge = NULL; if (edge_index == 0) { coarse_edge = coarse_start_edge; } - else if (edge_index == resolution - 1) { + else if (edge_index == num_edges_per_row - 1) { coarse_edge = coarse_end_edge; } subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge); subdiv_edge->v1 = vertex_index; - subdiv_edge->v2 = vertex_index + resolution; + subdiv_edge->v2 = vertex_index + num_edges_per_row; vertex_index += 1; } return subdiv_edge; } -static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index) +/* Create edges between inner vertices of patch, and also edges to the + * boundary. + */ + +/* Consider a subdivision of base face at level 1: + * + * y + * ^ + * | (6) ---- (7) ---- (8) + * | | | | + * | (3) ---- (4) ---- (5) + * | | | | + * | (0) ---- (1) ---- (2) + * o---------------------------> x + * + * This is illustrate which parts of geometry is created by code below. + */ + +static void subdiv_create_edges_all_patches_regular( + SubdivMeshContext *ctx, + const MPoly *coarse_poly) { - const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; - const int start_edge_index = ctx->subdiv_edge_offset[poly_index]; - /* Base/coarse mesh information. */ const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; const MPoly *coarse_mpoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_mpoly[poly_index]; - const int num_ptex_faces_per_poly = - num_ptex_faces_per_poly_get(coarse_poly); - const int ptex_face_resolution = ptex_face_resolution_get( - coarse_poly, ctx->settings->resolution); - const int ptex_face_resolution2 = - ptex_face_resolution * ptex_face_resolution; - /* Hi-poly subdivided mesh. */ + const int poly_index = coarse_poly - coarse_mpoly; + const int resolution = ctx->settings->resolution; + const int start_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[poly_index]; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; Mesh *subdiv_mesh = ctx->subdiv_mesh; MEdge *subdiv_medge = subdiv_mesh->medge; - MEdge *subdiv_edge = &subdiv_medge[start_edge_index]; - /* Consider a subdivision of base face at level 1: - * - * y - * ^ - * | (6) ---- (7) ---- (8) - * | | | | - * | (3) ---- (4) ---- (5) - * | | | | - * | (0) ---- (1) ---- (2) - * o---------------------------> x - * - * This is illustrate which parts of geometry is created by code below. - */ - for (int ptex_of_poly_index = 0; - ptex_of_poly_index < num_ptex_faces_per_poly; - ptex_of_poly_index++) - { + MEdge *subdiv_edge = &subdiv_medge[ + ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index]]; + /* Create bottom row of edges (0-1, 1-2). */ + subdiv_edge = subdiv_create_edges_row( + ctx, + subdiv_edge, + NULL, + start_vertex_index, + resolution - 2); + /* Create remaining edges. */ + for (int row = 0; row < resolution - 3; row++) { + const int start_row_vertex_index = + start_vertex_index + row * (resolution - 2); + /* Create vertical columns. + * + * At first iteration it will be edges (0-3. 1-4, 2-5), then it + * will be (3-6, 4-7, 5-8) and so on. + */ + subdiv_edge = subdiv_create_edges_column( + ctx, + subdiv_edge, + NULL, + NULL, + start_row_vertex_index, + resolution - 2); + /* Create horizontal edge row. + * + * At first iteration it will be edges (3-4, 4-5), then it will be + * (6-7, 7-8) and so on. + */ + subdiv_edge = subdiv_create_edges_row( + ctx, + subdiv_edge, + NULL, + start_row_vertex_index + resolution - 2, + resolution - 2); + } + /* Connect inner part of patch to boundary. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index = start_vertex_index; + int side_stride = 0; + /* Calculate starting veretx of corresponding inner part of ptex. */ + if (corner == 0) { + side_stride = 1; + } + else if (corner == 1) { + side_start_index += resolution - 3; + side_stride = resolution - 2; + } + else if (corner == 2) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + num_subdiv_vertices_per_coarse_edge - 1; + side_stride = -1; + } + else if (corner == 3) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + (num_subdiv_vertices_per_coarse_edge - 1); + side_stride = -(resolution - 2); + } + for (int i = 0; i < resolution - 2; i++, subdiv_edge++) { + subdiv_copy_edge_data(ctx, subdiv_edge, NULL); + if (flip) { + subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3); + } + else { + subdiv_edge->v1 = start_edge_vertex + i; + } + subdiv_edge->v2 = side_start_index + side_stride * i; + } + } +} + +static void subdiv_create_edges_all_patches_special( + SubdivMeshContext *ctx, + const MPoly *coarse_poly) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int poly_index = coarse_poly - coarse_mpoly; + const int resolution = ctx->settings->resolution; + const int ptex_face_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int ptex_face_inner_resolution = ptex_face_resolution - 2; + const int num_inner_vertices_per_ptex = + (ptex_face_resolution - 1) * (ptex_face_resolution - 2); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int center_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[poly_index]; + const int start_vertex_index = center_vertex_index + 1; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MEdge *subdiv_medge = subdiv_mesh->medge; + MEdge *subdiv_edge = &subdiv_medge[ + ctx->edge_inner_offset + ctx->subdiv_edge_offset[poly_index]]; + /* Create inner ptex edges. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { const int start_ptex_face_vertex_index = - start_vertex_index + ptex_of_poly_index * ptex_face_resolution2; - EdgesOfPtex edges_of_ptex; - edges_of_ptex_get(ctx, &edges_of_ptex, coarse_poly, ptex_of_poly_index); - /* Create bottom row of edges (0-1, 1-2). */ + start_vertex_index + corner * num_inner_vertices_per_ptex; + /* Similar steps to regular patch case. */ subdiv_edge = subdiv_create_edges_row( ctx, subdiv_edge, - edges_of_ptex.first_edge, + NULL, start_ptex_face_vertex_index, - ptex_face_resolution); - /* Create remaining edges. */ - for (int row = 0; row < ptex_face_resolution - 1; row++) { + ptex_face_inner_resolution + 1); + for (int row = 0; row < ptex_face_inner_resolution - 1; row++) { const int start_row_vertex_index = - start_ptex_face_vertex_index + row * ptex_face_resolution; - /* Create vertical columns. - * - * At first iteration it will be edges (0-3. 1-4, 2-5), then it - * will be (3-6, 4-7, 5-8) and so on. - */ + start_ptex_face_vertex_index + + row * (ptex_face_inner_resolution + 1); subdiv_edge = subdiv_create_edges_column( ctx, subdiv_edge, - edges_of_ptex.last_edge, - edges_of_ptex.second_edge, + NULL, + NULL, start_row_vertex_index, - ptex_face_resolution); - /* Create horizontal edge row. - * - * At first iteration it will be edges (3-4, 4-5), then it will be - * (6-7, 7-8) and so on. - */ + ptex_face_inner_resolution + 1); subdiv_edge = subdiv_create_edges_row( ctx, subdiv_edge, - (row == ptex_face_resolution - 2) ? edges_of_ptex.third_edge - : NULL, - start_row_vertex_index + ptex_face_resolution, - ptex_face_resolution); + NULL, + start_row_vertex_index + ptex_face_inner_resolution + 1, + ptex_face_inner_resolution + 1); } } + /* Create connections between ptex faces. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const int next_corner = (corner + 1) % coarse_poly->totloop; + int current_patch_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex + + ptex_face_inner_resolution; + int next_path_vertex_index = + start_vertex_index + next_corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - ptex_face_resolution + 1; + for (int row = 0; + row < ptex_face_inner_resolution; + row++, subdiv_edge++) + { + subdiv_copy_edge_data(ctx, subdiv_edge, NULL); + subdiv_edge->v1 = current_patch_vertex_index; + subdiv_edge->v2 = next_path_vertex_index; + current_patch_vertex_index += ptex_face_inner_resolution + 1; + next_path_vertex_index += 1; + } + } + /* Create edges from center. */ + if (ptex_face_resolution >= 3) { + for (int corner = 0; + corner < coarse_poly->totloop; + corner++, subdiv_edge++) + { + const int current_patch_end_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - 1; + subdiv_copy_edge_data(ctx, subdiv_edge, NULL); + subdiv_edge->v1 = center_vertex_index; + subdiv_edge->v2 = current_patch_end_vertex_index; + } + } + /* Connect inner path of patch to boundary. */ + const MLoop *prev_coarse_loop = + &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + { + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index; + if (ptex_face_resolution >= 3) { + side_start_index = + start_vertex_index + num_inner_vertices_per_ptex * corner; + } + else { + side_start_index = center_vertex_index; + } + for (int i = 0; i < ptex_face_resolution - 1; i++, subdiv_edge++) { + subdiv_copy_edge_data(ctx, subdiv_edge, NULL); + if (flip) { + subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3); + } else { + subdiv_edge->v1 = start_edge_vertex + i; + } + subdiv_edge->v2 = side_start_index + i; + } + } + if (ptex_face_resolution >= 3) { + const MEdge *coarse_edge = &coarse_medge[prev_coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index = + start_vertex_index + num_inner_vertices_per_ptex * corner; + for (int i = 0; i < ptex_face_resolution - 2; i++, subdiv_edge++) { + subdiv_copy_edge_data(ctx, subdiv_edge, NULL); + if (flip) { + subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3); + } else { + subdiv_edge->v1 = start_edge_vertex + i; + } + subdiv_edge->v2 = side_start_index + + (ptex_face_inner_resolution + 1) * i; + } + } + prev_coarse_loop = coarse_loop; + } +} + +static void subdiv_create_edges_all_patches( + SubdivMeshContext *ctx, + const MPoly *coarse_poly) +{ + if (coarse_poly->totloop == 4) { + subdiv_create_edges_all_patches_regular(ctx, coarse_poly); + } + else { + subdiv_create_edges_all_patches_special(ctx, coarse_poly); + } +} + +static void subdiv_create_edges(SubdivMeshContext *ctx, int poly_index) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + subdiv_create_edges_all_patches(ctx, coarse_poly); +} + +static void subdiv_create_boundary_edges( + SubdivMeshContext *ctx, + int edge_index) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MEdge *coarse_edge = &coarse_medge[edge_index]; + const int resolution = ctx->settings->resolution; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MEdge *subdiv_medge = subdiv_mesh->medge; + MEdge *subdiv_edge = &subdiv_medge[ + ctx->edge_boundary_offset + + edge_index * num_subdiv_edges_per_coarse_edge]; + int last_vertex_index = ctx->vertices_corner_offset + coarse_edge->v1; + for (int i = 0; + i < num_subdiv_edges_per_coarse_edge - 1; + i++, subdiv_edge++) + { + subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge); + subdiv_edge->v1 = last_vertex_index; + subdiv_edge->v2 = + ctx->vertices_edge_offset + + edge_index * num_subdiv_vertices_per_coarse_edge + + i; + last_vertex_index = subdiv_edge->v2; + } + subdiv_copy_edge_data(ctx, subdiv_edge, coarse_edge); + subdiv_edge->v1 = last_vertex_index; + subdiv_edge->v2 = ctx->vertices_corner_offset + coarse_edge->v2; } /* ============================================================================= @@ -857,15 +1525,13 @@ static void subdiv_eval_uv_layer(SubdivMeshContext *ctx, MLoop *subdiv_loop, const int ptex_face_index, const float u, const float v, - const float inv_resolution_1) + const float du, const float dv) { if (ctx->num_uv_layers == 0) { return; } Subdiv *subdiv = ctx->subdiv; const int mloop_index = subdiv_loop - ctx->subdiv_mesh->mloop; - const float du = inv_resolution_1; - const float dv = inv_resolution_1; for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) { MLoopUV *subdiv_loopuv = &ctx->uv_layers[layer_index][mloop_index]; BKE_subdiv_eval_face_varying(subdiv, @@ -891,24 +1557,85 @@ static void subdiv_eval_uv_layer(SubdivMeshContext *ctx, } } -static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index) +static void rotate_indices(const int rot, int *a, int *b, int *c, int *d) +{ + int values[4] = {*a, *b, *c, *d}; + *a = values[(0 - rot + 4) % 4]; + *b = values[(1 - rot + 4) % 4]; + *c = values[(2 - rot + 4) % 4]; + *d = values[(3 - rot + 4) % 4]; +} + +static void subdiv_create_loops_of_poly( + SubdivMeshContext *ctx, + LoopsForInterpolation *loop_interpolation, + MLoop *subdiv_loop_start, + const int ptex_face_index, + const int rotation, + /*const*/ int v0, /*const*/ int e0, + /*const*/ int v1, /*const*/ int e1, + /*const*/ int v2, /*const*/ int e2, + /*const*/ int v3, /*const*/ int e3, + const float u, const float v, + const float du, const float dv) +{ + rotate_indices(rotation, &v0, &v1, &v2, &v3); + rotate_indices(rotation, &e0, &e1, &e2, &e3); + subdiv_copy_loop_data(ctx, + &subdiv_loop_start[0], + loop_interpolation, + u, v); + subdiv_loop_start[0].v = v0; + subdiv_loop_start[0].e = e0; + subdiv_copy_loop_data(ctx, + &subdiv_loop_start[1], + loop_interpolation, + u + du, v); + subdiv_loop_start[1].v = v1; + subdiv_loop_start[1].e = e1; + subdiv_copy_loop_data(ctx, + &subdiv_loop_start[2], + loop_interpolation, + u + du, v + dv); + subdiv_loop_start[2].v = v2; + subdiv_loop_start[2].e = e2; + subdiv_copy_loop_data(ctx, + &subdiv_loop_start[3], + loop_interpolation, + u, v + dv); + subdiv_loop_start[3].v = v3; + subdiv_loop_start[3].e = e3; + /* Interpolate UV layers using OpenSubdiv. */ + subdiv_eval_uv_layer(ctx, + subdiv_loop_start, + ptex_face_index, + u, v, du, dv); +} + +static void subdiv_create_loops_regular(SubdivMeshContext *ctx, + const MPoly *coarse_poly) { const int resolution = ctx->settings->resolution; - const int ptex_face_index = ctx->face_ptex_offset[poly_index]; - const int start_vertex_index = ctx->subdiv_vertex_offset[poly_index]; - const int start_edge_index = ctx->subdiv_edge_offset[poly_index]; - const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; /* Base/coarse mesh information. */ const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; const MPoly *coarse_mpoly = coarse_mesh->mpoly; - const MPoly *coarse_poly = &coarse_mpoly[poly_index]; - const int num_ptex_faces_per_poly = - num_ptex_faces_per_poly_get(coarse_poly); + const int poly_index = coarse_poly - coarse_mpoly; const int ptex_resolution = ptex_face_resolution_get(coarse_poly, resolution); - const int ptex_resolution2 = ptex_resolution * ptex_resolution; + const int ptex_inner_resolution = ptex_resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; const float inv_ptex_resolution_1 = 1.0f / (float)(ptex_resolution - 1); - const int num_edges_per_ptex = num_edges_per_ptex_face_get(ptex_resolution); + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; + const int start_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[poly_index]; + const int start_edge_index = + ctx->edge_inner_offset + + ctx->subdiv_edge_offset[poly_index]; + const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; const int start_loop_index = 4 * start_poly_index; const float du = inv_ptex_resolution_1; const float dv = inv_ptex_resolution_1; @@ -918,74 +1645,526 @@ static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index) MLoop *subdiv_loop = &subdiv_loopoop[start_loop_index]; LoopsForInterpolation loop_interpolation; loop_interpolation_init(ctx, &loop_interpolation, coarse_poly); - for (int ptex_of_poly_index = 0; - ptex_of_poly_index < num_ptex_faces_per_poly; - ptex_of_poly_index++) + loop_interpolation_from_ptex(ctx, + &loop_interpolation, + coarse_poly, + 0); + /* Loops for inner part of ptex. */ + for (int y = 1; y < ptex_resolution - 2; y++) { + const float v = y * inv_ptex_resolution_1; + const int inner_y = y - 1; + for (int x = 1; x < ptex_resolution - 2; x++, subdiv_loop += 4) { + const int inner_x = x - 1; + const float u = x * inv_ptex_resolution_1; + /* Vertex indicies ordered counter-clockwise. */ + const int v0 = start_vertex_index + + (inner_y * ptex_inner_resolution + inner_x); + const int v1 = v0 + 1; + const int v2 = v0 + ptex_inner_resolution + 1; + const int v3 = v0 + ptex_inner_resolution; + /* Edge indicies ordered counter-clockwise. */ + const int e0 = start_edge_index + + (inner_y * (2 * ptex_inner_resolution - 1) + inner_x); + const int e1 = e0 + ptex_inner_resolution; + const int e2 = e0 + (2 * ptex_inner_resolution - 1); + const int e3 = e0 + ptex_inner_resolution - 1; + subdiv_create_loops_of_poly( + ctx, &loop_interpolation, subdiv_loop, ptex_face_index, 0, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + } + } + /* Loops for faces connecting inner ptex part with boundary. */ + const MLoop *prev_coarse_loop = + &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1]; + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e]; + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + int side_start_index = start_vertex_index; + int side_stride = 0; + int v0 = ctx->vertices_corner_offset + coarse_loop->v; + int v3, e3; + int e2_offset, e2_stride; + float u, v, delta_u, delta_v; + if (prev_coarse_loop->v == prev_coarse_edge->v1) { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - 1; + } + else { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge; + } + /* Calculate starting veretx of corresponding inner part of ptex. */ + if (corner == 0) { + side_stride = 1; + e2_offset = 0; + e2_stride = 1; + u = 0.0f; + v = 0.0f; + delta_u = du; + delta_v = 0.0f; + } + else if (corner == 1) { + side_start_index += resolution - 3; + side_stride = resolution - 2; + e2_offset = 2 * num_subdiv_edges_per_coarse_edge - 4; + e2_stride = 2 * num_subdiv_edges_per_coarse_edge - 3; + u = 1.0f - du; + v = 0; + delta_u = 0.0f; + delta_v = dv; + } + else if (corner == 2) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + num_subdiv_vertices_per_coarse_edge - 1; + side_stride = -1; + e2_offset = num_edges_per_ptex_face_get(resolution - 2) - 1; + e2_stride = -1; + u = 1.0f - du; + v = 1.0f - dv; + delta_u = -du; + delta_v = 0.0f; + } + else if (corner == 3) { + side_start_index += num_subdiv_vertices_per_coarse_edge * + (num_subdiv_vertices_per_coarse_edge - 1); + side_stride = -(resolution - 2); + e2_offset = num_edges_per_ptex_face_get(resolution - 2) - + (2 * num_subdiv_edges_per_coarse_edge - 3); + e2_stride = -(2 * num_subdiv_edges_per_coarse_edge - 3); + u = 0.0f; + v = 1.0f - dv; + delta_u = 0.0f; + delta_v = -dv; + } + for (int i = 0; i < resolution - 2; i++, subdiv_loop += 4) { + int v1; + if (flip) { + v1 = start_edge_vertex + (resolution - i - 3); + } + else { + v1 = start_edge_vertex + i; + } + const int v2 = side_start_index + side_stride * i; + int e0; + if (flip) { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - i - 1; + } else { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + i; + } + int e1 = start_edge_index + + num_edges_per_ptex_face_get(resolution - 2) + + corner * num_subdiv_vertices_per_coarse_edge + + i; + int e2; + if (i == 0) { + e2 = start_edge_index + + num_edges_per_ptex_face_get(resolution - 2) + + ((corner - 1 + coarse_poly->totloop) % + coarse_poly->totloop) * + num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + } + else { + e2 = start_edge_index + e2_offset + e2_stride * (i - 1); + } + subdiv_create_loops_of_poly( + ctx, &loop_interpolation, subdiv_loop, + ptex_face_index, corner, + v0, e0, v1, e1, v2, e2, v3, e3, + u + delta_u * i, v + delta_v * i, du, dv); + v0 = v1; + v3 = v2; + e3 = e1; + } + prev_coarse_loop = coarse_loop; + } + loop_interpolation_end(&loop_interpolation); +} + +static void subdiv_create_loops_special(SubdivMeshContext *ctx, + const MPoly *coarse_poly) +{ + const int resolution = ctx->settings->resolution; + /* Base/coarse mesh information. */ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MEdge *coarse_medge = coarse_mesh->medge; + const MLoop *coarse_mloop = coarse_mesh->mloop; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const int poly_index = coarse_poly - coarse_mpoly; + const int ptex_face_resolution = + ptex_face_resolution_get(coarse_poly, resolution); + const int ptex_face_inner_resolution = ptex_face_resolution - 2; + const float inv_ptex_resolution_1 = + 1.0f / (float)(ptex_face_resolution - 1); + const int num_inner_vertices_per_ptex = + (ptex_face_resolution - 1) * (ptex_face_resolution - 2); + const int num_inner_edges_per_ptex_face = + num_inner_edges_per_ptex_face_get( + ptex_face_inner_resolution + 1); + const int num_subdiv_vertices_per_coarse_edge = resolution - 2; + const int num_subdiv_edges_per_coarse_edge = resolution - 1; + const int ptex_face_index = ctx->face_ptex_offset[poly_index]; + const int center_vertex_index = + ctx->vertices_inner_offset + + ctx->subdiv_vertex_offset[poly_index]; + const int start_vertex_index = center_vertex_index + 1; + const int start_inner_vertex_index = center_vertex_index + 1; + const int start_edge_index = ctx->edge_inner_offset + + ctx->subdiv_edge_offset[poly_index]; + const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; + const int start_loop_index = 4 * start_poly_index; + const float du = inv_ptex_resolution_1; + const float dv = inv_ptex_resolution_1; + /* Hi-poly subdivided mesh. */ + Mesh *subdiv_mesh = ctx->subdiv_mesh; + MLoop *subdiv_loopoop = subdiv_mesh->mloop; + MLoop *subdiv_loop = &subdiv_loopoop[start_loop_index]; + LoopsForInterpolation loop_interpolation; + loop_interpolation_init(ctx, &loop_interpolation, coarse_poly); + for (int corner = 0; + corner < coarse_poly->totloop; + corner++) { + const int corner_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex; + const int corner_edge_index = + start_edge_index + corner * num_inner_edges_per_ptex_face; loop_interpolation_from_ptex(ctx, &loop_interpolation, coarse_poly, - ptex_of_poly_index); - const int current_ptex_face_index = - ptex_face_index + ptex_of_poly_index; - for (int y = 0; y < ptex_resolution - 1; y++) { + corner); + for (int y = 1; y < ptex_face_inner_resolution; y++) { const float v = y * inv_ptex_resolution_1; - for (int x = 0; x < ptex_resolution - 1; x++, subdiv_loop += 4) { + const int inner_y = y - 1; + for (int x = 1; + x < ptex_face_inner_resolution + 1; + x++, subdiv_loop += 4) + { + const int inner_x = x - 1; const float u = x * inv_ptex_resolution_1; /* Vertex indicies ordered counter-clockwise. */ - const int v0 = start_vertex_index + - (ptex_of_poly_index * ptex_resolution2) + - (y * ptex_resolution + x); + const int v0 = + corner_vertex_index + + (inner_y * (ptex_face_inner_resolution + 1) + inner_x); const int v1 = v0 + 1; - const int v2 = v0 + ptex_resolution + 1; - const int v3 = v0 + ptex_resolution; + const int v2 = v0 + ptex_face_inner_resolution + 2; + const int v3 = v0 + ptex_face_inner_resolution + 1; /* Edge indicies ordered counter-clockwise. */ - const int e0 = start_edge_index + - (ptex_of_poly_index * num_edges_per_ptex) + - (y * (2 * ptex_resolution - 1) + x); - const int e1 = e0 + ptex_resolution; - const int e2 = e0 + (2 * ptex_resolution - 1); - const int e3 = e0 + ptex_resolution - 1; - /* Initialize 4 loops of corresponding hi-poly poly. */ - /* TODO(sergey): For ptex boundaries we should use loops from - * coarse mesh. - */ - subdiv_copy_loop_data(ctx, - &subdiv_loop[0], - &loop_interpolation, - u, v); - subdiv_loop[0].v = v0; - subdiv_loop[0].e = e0; - subdiv_copy_loop_data(ctx, - &subdiv_loop[1], - &loop_interpolation, - u + du, v); - subdiv_loop[1].v = v1; - subdiv_loop[1].e = e1; - subdiv_copy_loop_data(ctx, - &subdiv_loop[2], - &loop_interpolation, - u + du, v + dv); - subdiv_loop[2].v = v2; - subdiv_loop[2].e = e2; - subdiv_copy_loop_data(ctx, - &subdiv_loop[3], - &loop_interpolation, - u, v + dv); - subdiv_loop[3].v = v3; - subdiv_loop[3].e = e3; - /* Interpolate UV layers using OpenSubdiv. */ - subdiv_eval_uv_layer(ctx, - subdiv_loop, - current_ptex_face_index, - u, v, - inv_ptex_resolution_1); + const int e0 = corner_edge_index + + (inner_y * (2 * ptex_face_inner_resolution + 1) + inner_x); + const int e1 = e0 + ptex_face_inner_resolution + 1; + const int e2 = e0 + (2 * ptex_face_inner_resolution + 1); + const int e3 = e0 + ptex_face_inner_resolution; + subdiv_create_loops_of_poly( + ctx, &loop_interpolation, subdiv_loop, + ptex_face_index + corner, 0, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); } } } + /* Create connections between ptex faces. */ + for (int corner = 0; corner < coarse_poly->totloop; corner++) { + const int next_corner = (corner + 1) % coarse_poly->totloop; + const int corner_edge_index = + start_edge_index + corner * num_inner_edges_per_ptex_face; + const int next_corner_edge_index = + start_edge_index + next_corner * num_inner_edges_per_ptex_face; + int current_patch_vertex_index = + start_inner_vertex_index + + corner * num_inner_vertices_per_ptex + + ptex_face_inner_resolution; + int next_path_vertex_index = + start_inner_vertex_index + + next_corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - ptex_face_resolution + 1; + int v0 = current_patch_vertex_index; + int v1 = next_path_vertex_index; + current_patch_vertex_index += ptex_face_inner_resolution + 1; + next_path_vertex_index += 1; + int e0 = start_edge_index + + coarse_poly->totloop * num_inner_edges_per_ptex_face + + corner * (ptex_face_resolution - 2); + int e1 = next_corner_edge_index + num_inner_edges_per_ptex_face - + ptex_face_resolution + 2; + int e3 = corner_edge_index + 2 * ptex_face_resolution - 4; + loop_interpolation_from_ptex(ctx, + &loop_interpolation, + coarse_poly, + next_corner); + for (int row = 1; + row < ptex_face_inner_resolution; + row++, subdiv_loop += 4) + { + const int v2 = next_path_vertex_index; + const int v3 = current_patch_vertex_index; + const int e2 = e0 + 1; + const float u = row * du; + const float v = 1.0f - dv; + subdiv_create_loops_of_poly( + ctx, &loop_interpolation, subdiv_loop, + ptex_face_index + next_corner, 3, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + current_patch_vertex_index += ptex_face_inner_resolution + 1; + next_path_vertex_index += 1; + v0 = v3; + v1 = v2; + e0 = e2; + e1 += 1; + e3 += 2 * ptex_face_resolution - 3; + } + } + /* Create loops from center. */ + if (ptex_face_resolution >= 3) { + const int start_center_edge_index = + start_edge_index + + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution) * coarse_poly->totloop; + const int start_boundary_edge = + start_edge_index + + coarse_poly->totloop * num_inner_edges_per_ptex_face + + ptex_face_inner_resolution - 1; + for (int corner = 0, prev_corner = coarse_poly->totloop - 1; + corner < coarse_poly->totloop; + prev_corner = corner, corner++, subdiv_loop += 4) + { + loop_interpolation_from_ptex(ctx, + &loop_interpolation, + coarse_poly, + corner); + const int corner_edge_index = + start_edge_index + + corner * num_inner_edges_per_ptex_face; + const int current_patch_end_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - 1; + const int prev_current_patch_end_vertex_index = + start_vertex_index + prev_corner * + num_inner_vertices_per_ptex + + num_inner_vertices_per_ptex - 1; + const int v0 = center_vertex_index; + const int v1 = prev_current_patch_end_vertex_index; + const int v2 = current_patch_end_vertex_index - 1; + const int v3 = current_patch_end_vertex_index; + const int e0 = start_center_edge_index + prev_corner; + const int e1 = start_boundary_edge + + prev_corner * (ptex_face_inner_resolution); + const int e2 = corner_edge_index + + num_inner_edges_per_ptex_face - 1; + const int e3 = start_center_edge_index + corner; + const float u = 1.0f - du; + const float v = 1.0f - dv; + subdiv_create_loops_of_poly( + ctx, &loop_interpolation, subdiv_loop, + ptex_face_index + corner, 2, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + } + } + /* Loops for faces connecting inner ptex part with boundary. */ + const MLoop *prev_coarse_loop = + &coarse_mloop[coarse_poly->loopstart + coarse_poly->totloop - 1]; + for (int prev_corner = coarse_poly->totloop - 1, corner = 0; + corner < coarse_poly->totloop; + prev_corner = corner, corner++) + { + loop_interpolation_from_ptex(ctx, + &loop_interpolation, + coarse_poly, + corner); + const MLoop *coarse_loop = + &coarse_mloop[coarse_poly->loopstart + corner]; + const MEdge *coarse_edge = &coarse_medge[coarse_loop->e]; + const MEdge *prev_coarse_edge = &coarse_medge[prev_coarse_loop->e]; + const bool flip = (coarse_edge->v2 == coarse_loop->v); + const int start_edge_vertex = ctx->vertices_edge_offset + + coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + const int corner_vertex_index = + start_vertex_index + corner * num_inner_vertices_per_ptex; + const int corner_edge_index = + start_edge_index + corner * num_inner_edges_per_ptex_face; + /* Create loops for polygons along U axis. */ + int v0 = ctx->vertices_corner_offset + coarse_loop->v; + int v3, e3; + if (prev_coarse_loop->v == prev_coarse_edge->v1) { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - 1; + } + else { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + e3 = ctx->edge_boundary_offset + + prev_coarse_loop->e * num_subdiv_edges_per_coarse_edge; + } + for (int i = 0; + i <= ptex_face_inner_resolution; + i++, subdiv_loop += 4) + { + int v1; + if (flip) { + v1 = start_edge_vertex + (resolution - i - 3); + } + else { + v1 = start_edge_vertex + i; + } + int v2; + if (ptex_face_inner_resolution >= 1) { + v2 = corner_vertex_index + i; + } + else { + v2 = center_vertex_index; + } + int e0; + if (flip) { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - i - 1; + } else { + e0 = ctx->edge_boundary_offset + + coarse_loop->e * num_subdiv_edges_per_coarse_edge + + i; + } + int e1 = start_edge_index + + corner * (2 * ptex_face_inner_resolution + 1); + if (ptex_face_resolution >= 3) { + e1 += coarse_poly->totloop * (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + i; + } + int e2 = 0; + if (i == 0 && ptex_face_resolution >= 3) { + e2 = start_edge_index + + coarse_poly->totloop * + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + corner * (2 * ptex_face_inner_resolution + 1) + + ptex_face_inner_resolution + 1; + } + else if (i == 0 && ptex_face_resolution < 3) { + e2 = start_edge_index + + prev_corner * (2 * ptex_face_inner_resolution + 1); + } + else { + e2 = corner_edge_index + i - 1; + } + const float u = du * i; + const float v = 0.0f; + subdiv_create_loops_of_poly( + ctx, &loop_interpolation, subdiv_loop, + ptex_face_index + corner, 0, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + v0 = v1; + v3 = v2; + e3 = e1; + } + /* Create loops for polygons along V axis. */ + const bool flip_prev = (prev_coarse_edge->v2 == coarse_loop->v); + v0 = corner_vertex_index; + if (prev_coarse_loop->v == prev_coarse_edge->v1) { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge + + num_subdiv_vertices_per_coarse_edge - 1; + } + else { + v3 = ctx->vertices_edge_offset + + prev_coarse_loop->e * num_subdiv_vertices_per_coarse_edge; + } + e3 = start_edge_index + + coarse_poly->totloop * + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + corner * (2 * ptex_face_inner_resolution + 1) + + ptex_face_inner_resolution + 1; + for (int i = 0; + i <= ptex_face_inner_resolution - 1; + i++, subdiv_loop += 4) + { + int v1; + int e0, e1; + if (i == ptex_face_inner_resolution - 1) { + v1 = start_vertex_index + + prev_corner * num_inner_vertices_per_ptex + + ptex_face_inner_resolution; + e1 = start_edge_index + + coarse_poly->totloop * + (num_inner_edges_per_ptex_face + + ptex_face_inner_resolution + 1) + + prev_corner * (2 * ptex_face_inner_resolution + 1) + + ptex_face_inner_resolution; + e0 = start_edge_index + + coarse_poly->totloop * num_inner_edges_per_ptex_face + + prev_corner * ptex_face_inner_resolution; + } + else { + v1 = v0 + ptex_face_inner_resolution + 1; + e0 = corner_edge_index + ptex_face_inner_resolution + + i * (2 * ptex_face_inner_resolution + 1); + e1 = e3 + 1; + } + int v2 = flip_prev ? v3 - 1 : v3 + 1; + int e2; + if (flip_prev) { + e2 = ctx->edge_boundary_offset + + prev_coarse_loop->e * + num_subdiv_edges_per_coarse_edge + + num_subdiv_edges_per_coarse_edge - 2 - i; + } + else { + e2 = ctx->edge_boundary_offset + + prev_coarse_loop->e * + num_subdiv_edges_per_coarse_edge + 1 + i; + } + const float u = 0.0f; + const float v = du * (i + 1); + subdiv_create_loops_of_poly( + ctx, &loop_interpolation, subdiv_loop, + ptex_face_index + corner, 1, + v0, e0, v1, e1, v2, e2, v3, e3, + u, v, du, dv); + v0 = v1; + v3 = v2; + e3 = e1; + } + prev_coarse_loop = coarse_loop; + } loop_interpolation_end(&loop_interpolation); } +static void subdiv_create_loops(SubdivMeshContext *ctx, int poly_index) +{ + const Mesh *coarse_mesh = ctx->coarse_mesh; + const MPoly *coarse_mpoly = coarse_mesh->mpoly; + const MPoly *coarse_poly = &coarse_mpoly[poly_index]; + if (coarse_poly->totloop == 4) { + subdiv_create_loops_regular(ctx, coarse_poly); + } + else { + subdiv_create_loops_special(ctx, coarse_poly); + } +} + /* ============================================================================= * Polygons subdivision process. */ @@ -1001,9 +2180,6 @@ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, coarse_poly_index, subdiv_poly_index, 1); - if (ctx->poly_origindex != NULL) { - // ctx->poly_origindex[subdiv_poly_index] = coarse_poly_index; - } } static void subdiv_create_polys(SubdivMeshContext *ctx, int poly_index) @@ -1051,13 +2227,22 @@ static void subdiv_eval_task( const int poly_index, const ParallelRangeTLS *__restrict UNUSED(tls)) { - SubdivMeshContext *data = userdata; + SubdivMeshContext *ctx = userdata; /* Evaluate hi-poly vertex coordinates and normals. */ - subdiv_evaluate_vertices(data, poly_index); + subdiv_evaluate_vertices(ctx, poly_index); /* Create mesh geometry for the given base poly index. */ - subdiv_create_edges(data, poly_index); - subdiv_create_loops(data, poly_index); - subdiv_create_polys(data, poly_index); + subdiv_create_edges(ctx, poly_index); + subdiv_create_loops(ctx, poly_index); + subdiv_create_polys(ctx, poly_index); +} + +static void subdiv_create_boundary_edges_task( + void *__restrict userdata, + const int edge_index, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + SubdivMeshContext *ctx = userdata; + subdiv_create_boundary_edges(ctx, edge_index); } Mesh *BKE_subdiv_to_mesh( @@ -1065,6 +2250,7 @@ Mesh *BKE_subdiv_to_mesh( const SubdivToMeshSettings *settings, const Mesh *coarse_mesh) { + // printf("================ MESH SUBDIVISION ================\n"); BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); /* Make sure evaluator is up to date with possible new topology, and that * is is refined for the new positions of coarse vertices. @@ -1086,12 +2272,19 @@ Mesh *BKE_subdiv_to_mesh( subdiv_mesh_ctx_init_result(&ctx); /* Multi-threaded evaluation. */ ParallelRangeSettings parallel_range_settings; + BKE_subdiv_stats_begin(&subdiv->stats, + SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); BLI_parallel_range_settings_defaults(¶llel_range_settings); BLI_task_parallel_range(0, coarse_mesh->totpoly, &ctx, subdiv_eval_task, ¶llel_range_settings); + BLI_task_parallel_range(0, coarse_mesh->totedge, + &ctx, + subdiv_create_boundary_edges_task, + ¶llel_range_settings); subdiv_mesh_ctx_free(&ctx); + BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); // BKE_mesh_validate(result, true, true); BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); return result; diff --git a/source/blender/blenkernel/intern/subdiv_stats.c b/source/blender/blenkernel/intern/subdiv_stats.c index 5da63fdbacb..f2219961ab7 100644 --- a/source/blender/blenkernel/intern/subdiv_stats.c +++ b/source/blender/blenkernel/intern/subdiv_stats.c @@ -37,6 +37,7 @@ void BKE_subdiv_stats_init(SubdivStats *stats) { stats->topology_refiner_creation_time = 0.0; stats->subdiv_to_mesh_time = 0.0; + stats->subdiv_to_mesh_geometry_time = 0.0; stats->evaluator_creation_time = 0.0; stats->evaluator_refine_time = 0.0; } @@ -69,6 +70,9 @@ void BKE_subdiv_stats_print(const SubdivStats *stats) STATS_PRINT_TIME(stats, subdiv_to_mesh_time, "Subdivision to mesh time"); + STATS_PRINT_TIME(stats, + subdiv_to_mesh_geometry_time, + " Geometry time"); STATS_PRINT_TIME(stats, evaluator_creation_time, "Evaluator creation time"); diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h index 82704e95fdd..bf3329f8ed5 100644 --- a/source/blender/blenlib/BLI_bitmap.h +++ b/source/blender/blenlib/BLI_bitmap.h @@ -70,6 +70,12 @@ typedef unsigned int BLI_bitmap; ((_bitmap)[(_index) >> _BITMAP_POWER] & \ (1u << ((_index) & _BITMAP_MASK)))) +#define BLI_BITMAP_TEST_AND_SET_ATOMIC(_bitmap, _index) \ + (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ + (atomic_fetch_and_or_uint8((uint8_t*)&(_bitmap)[(_index) >> _BITMAP_POWER], \ + (1u << ((_index) & _BITMAP_MASK))) & \ + (1u << ((_index) & _BITMAP_MASK)))) + #define BLI_BITMAP_TEST_BOOL(_bitmap, _index) \ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ (BLI_BITMAP_TEST(_bitmap, _index) != 0)) diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 08dc7c92693..7c605dd4f78 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -57,7 +57,7 @@ #include "intern/CCGSubSurf.h" -// #define USE_OPENSUBDIV +#define USE_OPENSUBDIV static void initData(ModifierData *md) { -- cgit v1.2.3 From fe6e751e695dbb32e4dc7ed20726ee3d266d0c7e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 31 Jul 2018 10:25:54 +0200 Subject: Workbench: Correct ifndef after recent changes Usage of matcap image uniform had different ifdef than definition of that uniform. Assuming the usage was correct, and the definition needed an update. Prevents shader from compilation failure and from aborts in debug builds. --- .../workbench/shaders/workbench_forward_transparent_accum_frag.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl index 81b6b2567a9..67a22073a4b 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl @@ -19,7 +19,7 @@ in vec3 normal_viewport; #ifdef V3D_SHADING_TEXTURE_COLOR in vec2 uv_interp; #endif -#ifdef STUDIOLIGHT_ORIENTATION_VIEWNORMAL +#ifdef V3D_LIGHTING_MATCAP uniform sampler2D matcapImage; #endif -- cgit v1.2.3 From 36389444b03ec149fb9c013b744b9d5126f85ae2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 18:42:22 +1000 Subject: Fix Shape Key retime starting at frame 10 D3571 by @alm --- source/blender/editors/object/object_shapekey.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index eec8b60cef0..e67b62ea624 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -376,8 +376,10 @@ static int shape_key_retime_exec(bContext *C, wmOperator *UNUSED(op)) if (!key || !kb) return OPERATOR_CANCELLED; - for (kb = key->block.first; kb; kb = kb->next) - kb->pos = (cfra += 0.1f); + for (kb = key->block.first; kb; kb = kb->next) { + kb->pos = cfra; + cfra += 0.1f; + } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); -- cgit v1.2.3 From 66da2f537ae80ce2b31d1eaf34ad8c03d858938d Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 10:22:19 +0200 Subject: New Grease Pencil object for 2D animation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit merge the full development done in greasepencil-object branch and include mainly the following features. - New grease pencil object. - New drawing engine. - New grease pencil modes Draw/Sculpt/Edit and Weight Paint. - New brushes for grease pencil. - New modifiers for grease pencil. - New shaders FX. - New material system (replace old palettes and colors). - Split of annotations (old grease pencil) and new grease pencil object. - UI adapted to blender 2.8. You can get more info here: https://code.blender.org/2017/12/drawing-2d-animation-in-blender-2-8/ https://code.blender.org/2018/07/grease-pencil-status-update/ This is the result of nearly two years of development and I want thanks firstly the other members of the grease pencil team: Daniel M. Lara, Matias Mendiola and Joshua Leung for their support, ideas and to keep working in the project all the time, without them this project had been impossible. Also, I want thanks other Blender developers for their help, advices and to be there always to help me, and specially to Clément Foucault, Dalai Felinto, Pablo Vázquez and Campbell Barton. --- source/blender/CMakeLists.txt | 4 + source/blender/blenkernel/BKE_brush.h | 8 +- source/blender/blenkernel/BKE_context.h | 12 +- source/blender/blenkernel/BKE_gpencil.h | 103 +- source/blender/blenkernel/BKE_gpencil_modifier.h | 256 +++ source/blender/blenkernel/BKE_icons.h | 7 + source/blender/blenkernel/BKE_lattice.h | 1 - source/blender/blenkernel/BKE_material.h | 4 + source/blender/blenkernel/BKE_object.h | 12 + source/blender/blenkernel/BKE_paint.h | 3 +- source/blender/blenkernel/BKE_shader_fx.h | 180 ++ source/blender/blenkernel/CMakeLists.txt | 6 + source/blender/blenkernel/intern/anim_sys.c | 7 + source/blender/blenkernel/intern/brush.c | 380 +++- source/blender/blenkernel/intern/colortools.c | 19 + source/blender/blenkernel/intern/context.c | 20 +- source/blender/blenkernel/intern/deform.c | 4 +- source/blender/blenkernel/intern/gpencil.c | 1383 +++++++----- .../blender/blenkernel/intern/gpencil_modifier.c | 679 ++++++ source/blender/blenkernel/intern/icons.c | 44 +- source/blender/blenkernel/intern/library.c | 1 + source/blender/blenkernel/intern/library_query.c | 25 +- source/blender/blenkernel/intern/material.c | 76 +- source/blender/blenkernel/intern/object.c | 194 +- source/blender/blenkernel/intern/object_deform.c | 16 +- source/blender/blenkernel/intern/object_update.c | 4 + source/blender/blenkernel/intern/paint.c | 13 +- source/blender/blenkernel/intern/scene.c | 81 +- source/blender/blenkernel/intern/shader_fx.c | 245 ++ source/blender/blenlib/BLI_math_vector.h | 3 + source/blender/blenlib/BLI_rand.h | 3 + source/blender/blenlib/intern/listbase.c | 3 + source/blender/blenlib/intern/math_vector_inline.c | 13 + source/blender/blenlib/intern/rand.c | 12 + source/blender/blenloader/intern/readfile.c | 246 +- source/blender/blenloader/intern/versioning_260.c | 4 +- source/blender/blenloader/intern/versioning_270.c | 85 +- source/blender/blenloader/intern/versioning_280.c | 199 +- .../blenloader/intern/versioning_defaults.c | 50 +- source/blender/blenloader/intern/writefile.c | 105 +- source/blender/collada/SceneExporter.cpp | 2 + .../depsgraph/intern/builder/deg_builder_nodes.cc | 34 +- .../intern/builder/deg_builder_nodes_view_layer.cc | 4 - .../intern/builder/deg_builder_relations.cc | 124 +- .../builder/deg_builder_relations_view_layer.cc | 4 - source/blender/depsgraph/intern/depsgraph_tag.cc | 9 +- source/blender/draw/CMakeLists.txt | 34 + source/blender/draw/DRW_engine.h | 3 + .../draw/engines/gpencil/gpencil_cache_utils.c | 296 +++ .../draw/engines/gpencil/gpencil_draw_cache_impl.c | 739 ++++++ .../draw/engines/gpencil/gpencil_draw_utils.c | 1336 +++++++++++ .../blender/draw/engines/gpencil/gpencil_engine.c | 794 +++++++ .../blender/draw/engines/gpencil/gpencil_engine.h | 355 +++ .../blender/draw/engines/gpencil/gpencil_render.c | 353 +++ .../draw/engines/gpencil/gpencil_shader_fx.c | 848 +++++++ .../gpencil/shaders/fx/gpencil_fx_blur_frag.glsl | 60 + .../shaders/fx/gpencil_fx_colorize_frag.glsl | 86 + .../gpencil/shaders/fx/gpencil_fx_flip_frag.glsl | 37 + .../gpencil/shaders/fx/gpencil_fx_light_frag.glsl | 70 + .../gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl | 50 + .../shaders/fx/gpencil_fx_rim_prepare_frag.glsl | 64 + .../shaders/fx/gpencil_fx_rim_resolve_frag.glsl | 101 + .../gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl | 70 + .../gpencil/shaders/fx/gpencil_fx_wave_frag.glsl | 40 + .../gpencil/shaders/gpencil_background_frag.glsl | 12 + .../gpencil/shaders/gpencil_edit_point_frag.glsl | 17 + .../gpencil/shaders/gpencil_edit_point_geom.glsl | 48 + .../gpencil/shaders/gpencil_edit_point_vert.glsl | 15 + .../engines/gpencil/shaders/gpencil_fill_frag.glsl | 140 ++ .../engines/gpencil/shaders/gpencil_fill_vert.glsl | 14 + .../gpencil/shaders/gpencil_paper_frag.glsl | 9 + .../gpencil/shaders/gpencil_point_frag.glsl | 49 + .../gpencil/shaders/gpencil_point_geom.glsl | 82 + .../gpencil/shaders/gpencil_point_vert.glsl | 37 + .../gpencil/shaders/gpencil_simple_mix_frag.glsl | 15 + .../gpencil/shaders/gpencil_stroke_frag.glsl | 46 + .../gpencil/shaders/gpencil_stroke_geom.glsl | 208 ++ .../gpencil/shaders/gpencil_stroke_vert.glsl | 37 + .../gpencil/shaders/gpencil_zdepth_mix_frag.glsl | 45 + source/blender/draw/intern/DRW_render.h | 1 + source/blender/draw/intern/draw_cache.c | 60 +- source/blender/draw/intern/draw_cache.h | 3 + source/blender/draw/intern/draw_cache_impl.h | 4 + source/blender/draw/intern/draw_manager.c | 145 +- source/blender/draw/modes/draw_mode_engines.h | 1 + source/blender/draw/modes/object_mode.c | 18 + .../editors/animation/anim_channels_defines.c | 15 +- .../blender/editors/animation/anim_channels_edit.c | 3 +- source/blender/editors/animation/anim_deps.c | 10 + source/blender/editors/animation/anim_draw.c | 4 +- source/blender/editors/animation/anim_filter.c | 13 +- source/blender/editors/animation/keyframes_draw.c | 9 +- source/blender/editors/datafiles/CMakeLists.txt | 52 + source/blender/editors/gpencil/CMakeLists.txt | 6 + source/blender/editors/gpencil/annotate_draw.c | 1065 +++++++++ source/blender/editors/gpencil/annotate_paint.c | 2382 ++++++++++++++++++++ source/blender/editors/gpencil/drawgpencil.c | 989 ++++---- .../blender/editors/gpencil/editaction_gpencil.c | 2 + .../blender/editors/gpencil/gpencil_add_monkey.c | 1567 +++++++++++++ source/blender/editors/gpencil/gpencil_brush.c | 695 ++++-- source/blender/editors/gpencil/gpencil_convert.c | 70 +- source/blender/editors/gpencil/gpencil_data.c | 1809 +++++++++------ source/blender/editors/gpencil/gpencil_edit.c | 1635 +++++++++++--- source/blender/editors/gpencil/gpencil_fill.c | 1246 ++++++++++ source/blender/editors/gpencil/gpencil_intern.h | 271 ++- .../blender/editors/gpencil/gpencil_interpolate.c | 71 +- source/blender/editors/gpencil/gpencil_old.c | 219 ++ source/blender/editors/gpencil/gpencil_ops.c | 547 ++++- source/blender/editors/gpencil/gpencil_paint.c | 1337 +++++++---- source/blender/editors/gpencil/gpencil_primitive.c | 712 ++++++ source/blender/editors/gpencil/gpencil_select.c | 293 ++- source/blender/editors/gpencil/gpencil_undo.c | 6 + source/blender/editors/gpencil/gpencil_utils.c | 1262 ++++++++--- source/blender/editors/include/ED_anim_api.h | 5 + source/blender/editors/include/ED_datafiles.h | 63 + source/blender/editors/include/ED_gpencil.h | 188 +- source/blender/editors/include/ED_keyframes_draw.h | 5 +- source/blender/editors/include/ED_object.h | 35 + source/blender/editors/include/UI_icons.h | 24 + source/blender/editors/include/UI_interface.h | 9 +- source/blender/editors/interface/interface_icons.c | 100 +- .../blender/editors/interface/interface_layout.c | 8 + .../editors/interface/interface_templates.c | 308 ++- source/blender/editors/interface/resources.c | 20 +- source/blender/editors/object/CMakeLists.txt | 4 + source/blender/editors/object/object_add.c | 131 +- source/blender/editors/object/object_edit.c | 42 +- .../editors/object/object_gpencil_modifier.c | 637 ++++++ source/blender/editors/object/object_intern.h | 15 + source/blender/editors/object/object_modes.c | 18 +- source/blender/editors/object/object_modifier.c | 238 +- source/blender/editors/object/object_ops.c | 15 + source/blender/editors/object/object_relations.c | 23 +- source/blender/editors/object/object_select.c | 5 +- source/blender/editors/object/object_shader_fx.c | 469 ++++ source/blender/editors/object/object_transform.c | 103 +- source/blender/editors/render/render_opengl.c | 94 +- source/blender/editors/render/render_preview.c | 38 +- source/blender/editors/render/render_shading.c | 8 +- source/blender/editors/screen/area.c | 28 +- source/blender/editors/screen/screen_context.c | 84 +- source/blender/editors/screen/screen_ops.c | 7 +- source/blender/editors/sculpt_paint/paint_ops.c | 46 +- .../blender/editors/space_action/action_select.c | 69 +- .../editors/space_buttons/buttons_context.c | 44 +- .../editors/space_buttons/buttons_texture.c | 17 + .../blender/editors/space_buttons/space_buttons.c | 41 +- source/blender/editors/space_clip/clip_buttons.c | 2 +- source/blender/editors/space_clip/space_clip.c | 6 +- source/blender/editors/space_image/image_buttons.c | 2 +- source/blender/editors/space_info/info_stats.c | 32 + source/blender/editors/space_nla/nla_buttons.c | 3 +- source/blender/editors/space_nla/nla_channels.c | 1 + source/blender/editors/space_node/drawnode.c | 30 +- .../blender/editors/space_outliner/outliner_draw.c | 415 ++-- .../editors/space_outliner/outliner_select.c | 30 + .../blender/editors/space_outliner/outliner_tree.c | 2 - source/blender/editors/space_topbar/space_topbar.c | 4 + source/blender/editors/space_view3d/drawobject.c | 1 + source/blender/editors/space_view3d/space_view3d.c | 13 +- source/blender/editors/space_view3d/view3d_draw.c | 2 +- .../editors/space_view3d/view3d_draw_legacy.c | 2 +- source/blender/editors/space_view3d/view3d_edit.c | 8 +- .../editors/space_view3d/view3d_gizmo_ruler.c | 33 +- source/blender/editors/space_view3d/view3d_ruler.c | 33 +- .../blender/editors/space_view3d/view3d_select.c | 24 + source/blender/editors/transform/transform.c | 69 +- .../editors/transform/transform_conversions.c | 330 +-- .../blender/editors/transform/transform_generics.c | 22 +- .../blender/editors/transform/transform_gizmo_3d.c | 9 +- .../editors/transform/transform_snap_object.c | 7 +- source/blender/editors/undo/ed_undo.c | 27 + source/blender/gpencil_modifiers/CMakeLists.txt | 70 + .../gpencil_modifiers/MOD_gpencil_modifiertypes.h | 53 + .../gpencil_modifiers/intern/MOD_gpencil_util.c | 142 ++ .../gpencil_modifiers/intern/MOD_gpencil_util.h | 47 + .../gpencil_modifiers/intern/MOD_gpencilbuild.c | 558 +++++ .../gpencil_modifiers/intern/MOD_gpencilcolor.c | 178 ++ .../gpencil_modifiers/intern/MOD_gpencilhook.c | 355 +++ .../gpencil_modifiers/intern/MOD_gpencilinstance.c | 360 +++ .../gpencil_modifiers/intern/MOD_gpencillattice.c | 213 ++ .../gpencil_modifiers/intern/MOD_gpencilmirror.c | 239 ++ .../gpencil_modifiers/intern/MOD_gpencilnoise.c | 285 +++ .../gpencil_modifiers/intern/MOD_gpenciloffset.c | 143 ++ .../gpencil_modifiers/intern/MOD_gpencilopacity.c | 171 ++ .../gpencil_modifiers/intern/MOD_gpencilsimplify.c | 123 + .../gpencil_modifiers/intern/MOD_gpencilsmooth.c | 152 ++ .../gpencil_modifiers/intern/MOD_gpencilsubdiv.c | 193 ++ .../gpencil_modifiers/intern/MOD_gpencilthick.c | 171 ++ .../gpencil_modifiers/intern/MOD_gpenciltint.c | 186 ++ source/blender/gpu/CMakeLists.txt | 8 + source/blender/gpu/GPU_shader.h | 5 +- source/blender/gpu/intern/gpu_shader.c | 14 + .../gpu/shaders/gpu_shader_gpencil_fill_frag.glsl | 166 ++ .../gpu/shaders/gpu_shader_gpencil_fill_vert.glsl | 11 + .../shaders/gpu_shader_gpencil_stroke_frag.glsl | 20 + .../shaders/gpu_shader_gpencil_stroke_geom.glsl | 196 ++ .../shaders/gpu_shader_gpencil_stroke_vert.glsl | 33 + source/blender/makesdna/DNA_ID.h | 2 +- source/blender/makesdna/DNA_brush_types.h | 109 +- source/blender/makesdna/DNA_color_types.h | 1 + .../blender/makesdna/DNA_gpencil_modifier_types.h | 404 ++++ source/blender/makesdna/DNA_gpencil_types.h | 319 ++- source/blender/makesdna/DNA_material_types.h | 76 + source/blender/makesdna/DNA_object_enums.h | 5 +- source/blender/makesdna/DNA_object_types.h | 19 +- source/blender/makesdna/DNA_scene_types.h | 105 +- source/blender/makesdna/DNA_shader_fx_types.h | 196 ++ source/blender/makesdna/DNA_space_types.h | 3 +- source/blender/makesdna/DNA_userdef_types.h | 6 +- source/blender/makesdna/DNA_view3d_types.h | 29 +- source/blender/makesdna/intern/makesdna.c | 4 + source/blender/makesrna/RNA_access.h | 28 +- source/blender/makesrna/RNA_enum_types.h | 4 + source/blender/makesrna/intern/CMakeLists.txt | 2 + source/blender/makesrna/intern/makesrna.c | 2 + source/blender/makesrna/intern/rna_brush.c | 441 ++++ source/blender/makesrna/intern/rna_context.c | 4 + source/blender/makesrna/intern/rna_gpencil.c | 1003 +++------ .../blender/makesrna/intern/rna_gpencil_modifier.c | 1314 +++++++++++ source/blender/makesrna/intern/rna_internal.h | 7 + source/blender/makesrna/intern/rna_main_api.c | 13 + source/blender/makesrna/intern/rna_material.c | 337 +++ source/blender/makesrna/intern/rna_movieclip.c | 1 + source/blender/makesrna/intern/rna_nodetree.c | 1 + source/blender/makesrna/intern/rna_object.c | 212 +- source/blender/makesrna/intern/rna_palette.c | 4 +- source/blender/makesrna/intern/rna_scene.c | 425 +--- source/blender/makesrna/intern/rna_sculpt_paint.c | 149 +- source/blender/makesrna/intern/rna_shader_fx.c | 538 +++++ source/blender/makesrna/intern/rna_space.c | 151 +- source/blender/makesrna/intern/rna_tracking.c | 1 + source/blender/makesrna/intern/rna_ui_api.c | 26 + source/blender/makesrna/intern/rna_userdef.c | 8 + .../blender/render/intern/source/external_engine.c | 3 + source/blender/shader_fx/CMakeLists.txt | 64 + source/blender/shader_fx/FX_shader_types.h | 47 + source/blender/shader_fx/intern/FX_shader_blur.c | 66 + .../blender/shader_fx/intern/FX_shader_colorize.c | 69 + source/blender/shader_fx/intern/FX_shader_flip.c | 69 + source/blender/shader_fx/intern/FX_shader_light.c | 104 + source/blender/shader_fx/intern/FX_shader_pixel.c | 66 + source/blender/shader_fx/intern/FX_shader_rim.c | 70 + source/blender/shader_fx/intern/FX_shader_swirl.c | 103 + source/blender/shader_fx/intern/FX_shader_util.c | 56 + source/blender/shader_fx/intern/FX_shader_util.h | 36 + source/blender/shader_fx/intern/FX_shader_wave.c | 71 + source/blender/windowmanager/intern/wm_operators.c | 2 +- source/creator/creator.c | 4 + 249 files changed, 36614 insertions(+), 5624 deletions(-) create mode 100644 source/blender/blenkernel/BKE_gpencil_modifier.h create mode 100644 source/blender/blenkernel/BKE_shader_fx.h create mode 100644 source/blender/blenkernel/intern/gpencil_modifier.c create mode 100644 source/blender/blenkernel/intern/shader_fx.c create mode 100644 source/blender/draw/engines/gpencil/gpencil_cache_utils.c create mode 100644 source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c create mode 100644 source/blender/draw/engines/gpencil/gpencil_draw_utils.c create mode 100644 source/blender/draw/engines/gpencil/gpencil_engine.c create mode 100644 source/blender/draw/engines/gpencil/gpencil_engine.h create mode 100644 source/blender/draw/engines/gpencil/gpencil_render.c create mode 100644 source/blender/draw/engines/gpencil/gpencil_shader_fx.c create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl create mode 100644 source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl create mode 100644 source/blender/editors/gpencil/annotate_draw.c create mode 100644 source/blender/editors/gpencil/annotate_paint.c create mode 100644 source/blender/editors/gpencil/gpencil_add_monkey.c create mode 100644 source/blender/editors/gpencil/gpencil_fill.c create mode 100644 source/blender/editors/gpencil/gpencil_old.c create mode 100644 source/blender/editors/gpencil/gpencil_primitive.c create mode 100644 source/blender/editors/object/object_gpencil_modifier.c create mode 100644 source/blender/editors/object/object_shader_fx.c create mode 100644 source/blender/gpencil_modifiers/CMakeLists.txt create mode 100644 source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c create mode 100644 source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl create mode 100644 source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl create mode 100644 source/blender/makesdna/DNA_gpencil_modifier_types.h create mode 100644 source/blender/makesdna/DNA_shader_fx_types.h create mode 100644 source/blender/makesrna/intern/rna_gpencil_modifier.c create mode 100644 source/blender/makesrna/intern/rna_shader_fx.c create mode 100644 source/blender/shader_fx/CMakeLists.txt create mode 100644 source/blender/shader_fx/FX_shader_types.h create mode 100644 source/blender/shader_fx/intern/FX_shader_blur.c create mode 100644 source/blender/shader_fx/intern/FX_shader_colorize.c create mode 100644 source/blender/shader_fx/intern/FX_shader_flip.c create mode 100644 source/blender/shader_fx/intern/FX_shader_light.c create mode 100644 source/blender/shader_fx/intern/FX_shader_pixel.c create mode 100644 source/blender/shader_fx/intern/FX_shader_rim.c create mode 100644 source/blender/shader_fx/intern/FX_shader_swirl.c create mode 100644 source/blender/shader_fx/intern/FX_shader_util.c create mode 100644 source/blender/shader_fx/intern/FX_shader_util.h create mode 100644 source/blender/shader_fx/intern/FX_shader_wave.c (limited to 'source') diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 5709ac723f4..2c9b1efe2f4 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -44,7 +44,9 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fileglobal_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_freestyle_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_genfile.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_group_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h @@ -112,6 +114,8 @@ add_subdirectory(gpu) add_subdirectory(imbuf) add_subdirectory(nodes) add_subdirectory(modifiers) +add_subdirectory(gpencil_modifiers) +add_subdirectory(shader_fx) add_subdirectory(makesdna) add_subdirectory(makesrna) diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index eda1c51bbc2..489746cbfd9 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -28,11 +28,14 @@ */ enum eCurveMappingPreset; +struct bContext; struct Brush; +struct Paint; struct ImBuf; struct ImagePool; struct Main; struct Scene; +struct ToolSettings; struct UnifiedPaintSettings; // enum eCurveMappingPreset; @@ -45,14 +48,17 @@ void BKE_brush_system_exit(void); /* datablock functions */ void BKE_brush_init(struct Brush *brush); struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode); +struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name); struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode); void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag); struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush); void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local); -void BKE_brush_unlink(struct Main *bmain, struct Brush *brush); void BKE_brush_free(struct Brush *brush); void BKE_brush_sculpt_reset(struct Brush *brush); +void BKE_brush_gpencil_presets(struct bContext *C); +struct Brush *BKE_brush_getactive_gpencil(struct ToolSettings *ts); +struct Paint *BKE_brush_get_gpencil_paint(struct ToolSettings *ts); /* image icon function */ struct ImBuf *get_brush_icon(struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 9f57859d318..28dcf9cb127 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -65,9 +65,7 @@ struct bPoseChannel; struct bGPdata; struct bGPDlayer; struct bGPDframe; -struct bGPDpalette; -struct bGPDpalettecolor; -struct bGPDbrush; +struct Brush; struct wmWindow; struct wmWindowManager; struct RenderEngineType; @@ -120,6 +118,10 @@ enum { CTX_MODE_PAINT_TEXTURE, CTX_MODE_PARTICLE, CTX_MODE_OBJECT, + CTX_MODE_GPENCIL_PAINT, + CTX_MODE_GPENCIL_EDIT, + CTX_MODE_GPENCIL_SCULPT, + CTX_MODE_GPENCIL_WEIGHT, CTX_MODE_NUM /* must be last */ }; @@ -313,9 +315,7 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list); struct bGPdata *CTX_data_gpencil_data(const bContext *C); struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C); struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C); -struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C); -struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C); -struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C); +struct Brush *CTX_data_active_gpencil_brush(const bContext *C); int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list); int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 3a951b7860d..887a7f4f67b 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -31,25 +31,45 @@ * \author Joshua Leung */ +struct CurveMapping; +struct Depsgraph; +struct GpencilModifierData; struct ToolSettings; struct ListBase; struct bGPdata; struct bGPDlayer; struct bGPDframe; +struct bGPDspoint; struct bGPDstroke; +struct Material; struct bGPDpalette; struct bGPDpalettecolor; struct Main; +struct BoundBox; +struct Brush; +struct Object; +struct bDeformGroup; +struct SimplifyGpencilModifierData; +struct InstanceGpencilModifierData; +struct LatticeGpencilModifierData; + +struct MDeformVert; +struct MDeformWeight; /* ------------ Grease-Pencil API ------------------ */ +void BKE_gpencil_free_point_weights(struct MDeformVert *dvert); +void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps); void BKE_gpencil_free_stroke(struct bGPDstroke *gps); bool BKE_gpencil_free_strokes(struct bGPDframe *gpf); void BKE_gpencil_free_frames(struct bGPDlayer *gpl); void BKE_gpencil_free_layers(struct ListBase *list); -void BKE_gpencil_free_brushes(struct ListBase *list); -void BKE_gpencil_free_palettes(struct ListBase *list); -void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes); +bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf); +void BKE_gpencil_free_derived_frames(struct bGPdata *gpd); +void BKE_gpencil_free(struct bGPdata *gpd, bool free_all); + +void BKE_gpencil_batch_cache_dirty(struct bGPdata *gpd); +void BKE_gpencil_batch_cache_free(struct bGPdata *gpd); void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps); @@ -60,21 +80,36 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[]) struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src); struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src); +void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst); +struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src); + void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag); +struct bGPdata *BKE_gpencil_copy(struct Main *bmain, const struct bGPdata *gpd); struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy); void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local); void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); -struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive); -struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src); -struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive); +/* materials */ +void BKE_gpencil_material_index_remove(struct bGPdata *gpd, int index); +void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len); -struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive); -struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src); -void BKE_gpencil_brush_init_presets(struct ToolSettings *ts); +/* statistics functions */ +void BKE_gpencil_stats_update(struct bGPdata *gpd); +/* Utilities for creating and populating GP strokes */ +/* - Number of values defining each point in the built-in data + * buffers for primitives (e.g. 2D Monkey) + */ +#define GP_PRIM_DATABUF_SIZE 5 + +void BKE_gpencil_stroke_add_points( + struct bGPDstroke *gps, + const float *array, const int totpoints, + const float mat[4][4]); + +struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness); /* Stroke and Fill - Alpha Visibility Threshold */ #define GPENCIL_ALPHA_OPACITY_THRESH 0.001f @@ -103,20 +138,40 @@ struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd); void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active); void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl); -struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts); -void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active); -void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush); - -struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd); -void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active); -void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette); -void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd); - -struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette); -void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active); -void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor); -struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name); -void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname); -void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name); +struct Material *BKE_gpencil_get_material_from_brush(struct Brush *brush); +struct Material *BKE_gpencil_material_ensure(struct Main *bmain, struct Object *ob); + +/* object boundbox */ +bool BKE_gpencil_stroke_minmax( + const struct bGPDstroke *gps, const bool use_select, + float r_min[3], float r_max[3]); + +struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob); +void BKE_gpencil_centroid_3D(struct bGPdata *gpd, float r_centroid[3]); + +/* vertex groups */ +float BKE_gpencil_vgroup_use_index(struct MDeformVert *dvert, int index); +void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup); +struct MDeformWeight *BKE_gpencil_vgroup_add_point_weight(struct MDeformVert *dvert, int index, float weight); +bool BKE_gpencil_vgroup_remove_point_weight(struct MDeformVert *dvert, int index); +void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst); + +/* GPencil geometry evaluation */ +void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd); + +/* stroke geometry utilities */ +void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]); +void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor); +void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps); + +void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]); + +bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf); +bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence); + +void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe); +float BKE_gpencil_multiframe_falloff_calc(struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff); #endif /* __BKE_GPENCIL_H__ */ diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h new file mode 100644 index 00000000000..cd6b6540012 --- /dev/null +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -0,0 +1,256 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_GPENCIL_MODIFIER_H__ +#define __BKE_GPENCIL_MODIFIER_H__ + +/** \file BKE_greasepencil_modifier.h + * \ingroup bke + */ + +#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */ +#include "BLI_compiler_attrs.h" +#include "BKE_customdata.h" + +struct ID; +struct Depsgraph; +struct DerivedMesh; +struct bContext; /* NOTE: bakeModifier() - called from UI - needs to create new datablocks, hence the need for this */ +struct Mesh; +struct Object; +struct Scene; +struct ViewLayer; +struct ListBase; +struct bArmature; +struct Main; +struct GpencilModifierData; +struct BMEditMesh; +struct DepsNodeHandle; +struct bGPDlayer; +struct bGPDframe; +struct bGPDstroke; +struct ModifierUpdateDepsgraphContext; + +#define GPENCIL_MODIFIER_ACTIVE(_md, _is_render) (((_md->mode & eGpencilModifierMode_Realtime) && (_is_render == false)) || \ + ((_md->mode & eGpencilModifierMode_Render) && (_is_render == true))) +#define GPENCIL_MODIFIER_EDIT(_md, _is_edit) (((_md->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit)) + +typedef enum { + /* Should not be used, only for None modifier type */ + eGpencilModifierTypeType_None, + + /* grease pencil modifiers */ + eGpencilModifierTypeType_Gpencil, +} GpencilModifierTypeType; + +typedef enum { + eGpencilModifierTypeFlag_SupportsMapping = (1 << 0), + eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1), + + /* For modifiers that support editmode this determines if the + * modifier should be enabled by default in editmode. This should + * only be used by modifiers that are relatively speedy and + * also generally used in editmode, otherwise let the user enable + * it by hand. + */ + eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2), + + /* For modifiers that require original data and so cannot + * be placed after any non-deformative modifier. + */ + eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3), + + /* max one per type */ + eGpencilModifierTypeFlag_Single = (1 << 4), + + /* can't be added manually by user */ + eGpencilModifierTypeFlag_NoUserAdd = (1 << 5), +} GpencilModifierTypeFlag; + +/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */ +typedef void(*GreasePencilObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag); +typedef void(*GreasePencilIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag); +typedef void(*GreasePencilTexWalkFunc)(void *userData, struct Object *ob, struct GpencilModifierData *md, const char *propname); + +typedef struct GpencilModifierTypeInfo { + /* The user visible name for this modifier */ + char name[32]; + + /* The DNA struct name for the modifier data type, used to + * write the DNA data out. + */ + char struct_name[32]; + + /* The size of the modifier data type, used by allocation. */ + int struct_size; + + GpencilModifierType type; + GpencilModifierTypeFlag flags; + + + /********************* Non-optional functions *********************/ + + /* Copy instance data for this modifier type. Should copy all user + * level settings to the target modifier. + */ + void (*copyData)(const struct GpencilModifierData *md, struct GpencilModifierData *target); + + /* Callback for GP "stroke" modifiers that operate on the + * shape and parameters of the provided strokes (e.g. Thickness, Noise, etc.) + * + * The gpl parameter contains the GP layer that the strokes come from. + * While access is provided to this data, you should not directly access + * the gpl->frames data from the modifier. Instead, use the gpf parameter + * instead. + * + * The gps parameter contains the GP stroke to operate on. This is usually a copy + * of the original (unmodified and saved to files) stroke data. + */ + void (*deformStroke)(struct GpencilModifierData *md, struct Depsgraph *depsgraph, + struct Object *ob, struct bGPDlayer *gpl, struct bGPDstroke *gps); + + /* Callback for GP "geometry" modifiers that create extra geometry + * in the frame (e.g. Array) + * + * The gpf parameter contains the GP frame/strokes to operate on. This is + * usually a copy of the original (unmodified and saved to files) stroke data. + * Modifiers should only add any generated strokes to this frame (and not one accessed + * via the gpl parameter). + * + * The modifier_index parameter indicates where the modifier is + * in the modifier stack in relation to other modifiers. + */ + void (*generateStrokes)(struct GpencilModifierData *md, struct Depsgraph *depsgraph, + struct Object *ob, struct bGPDlayer *gpl, struct bGPDframe *gpf); + + /* Bake-down GP modifier's effects into the GP datablock. + * + * This gets called when the user clicks the "Apply" button in the UI. + * As such, this callback needs to go through all layers/frames in the + * datablock, mutating the geometry and/or creating new datablocks/objects + */ + void (*bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph, + struct GpencilModifierData *md, struct Object *ob); + + /********************* Optional functions *********************/ + + /* Initialize new instance data for this modifier type, this function + * should set modifier variables to their default values. + * + * This function is optional. + */ + void (*initData)(struct GpencilModifierData *md); + + /* Free internal modifier data variables, this function should + * not free the md variable itself. + * + * This function is optional. + */ + void (*freeData)(struct GpencilModifierData *md); + + /* Return a boolean value indicating if this modifier is able to be + * calculated based on the modifier data. This is *not* regarding the + * md->flag, that is tested by the system, this is just if the data + * validates (for example, a lattice will return false if the lattice + * object is not defined). + * + * This function is optional (assumes never disabled if not present). + */ + bool (*isDisabled)(struct GpencilModifierData *md, int userRenderParams); + + /* Add the appropriate relations to the dependency graph. + * + * This function is optional. + */ + void (*updateDepsgraph)(struct GpencilModifierData *md, + const struct ModifierUpdateDepsgraphContext *ctx); + + /* Should return true if the modifier needs to be recalculated on time + * changes. + * + * This function is optional (assumes false if not present). + */ + bool (*dependsOnTime)(struct GpencilModifierData *md); + + + /* Should call the given walk function on with a pointer to each Object + * pointer that the modifier data stores. This is used for linking on file + * load and for unlinking objects or forwarding object references. + * + * This function is optional. + */ + void (*foreachObjectLink)(struct GpencilModifierData *md, struct Object *ob, + GreasePencilObjectWalkFunc walk, void *userData); + + /* Should call the given walk function with a pointer to each ID + * pointer (i.e. each datablock pointer) that the modifier data + * stores. This is used for linking on file load and for + * unlinking datablocks or forwarding datablock references. + * + * This function is optional. If it is not present, foreachObjectLink + * will be used. + */ + void (*foreachIDLink)(struct GpencilModifierData *md, struct Object *ob, + GreasePencilIDWalkFunc walk, void *userData); + + /* Should call the given walk function for each texture that the + * modifier data stores. This is used for finding all textures in + * the context for the UI. + * + * This function is optional. If it is not present, it will be + * assumed the modifier has no textures. + */ + void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob, + GreasePencilTexWalkFunc walk, void *userData); +} GpencilModifierTypeInfo; + +void BKE_gpencil_instance_modifier_instance_tfm(struct InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4]); + +/* Initialize modifier's global data (type info and some common global storages). */ +void BKE_gpencil_modifier_init(void); + +const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type); +struct GpencilModifierData *BKE_gpencil_modifier_new(int type); +void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag); +void BKE_gpencil_modifier_free(struct GpencilModifierData *md); +bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd); +bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md); +struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob, GpencilModifierType type); +struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name); +void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst); +void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md, struct GpencilModifierData *target); +void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag); +void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData); +void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); + +bool BKE_gpencil_has_geometry_modifiers(struct Object *ob); + +void BKE_gpencil_stroke_modifiers( + struct Depsgraph *depsgraph, struct Object *ob, + struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps, bool is_render); +void BKE_gpencil_geometry_modifiers( + struct Depsgraph *depsgraph, struct Object *ob, + struct bGPDlayer *gpl, struct bGPDframe *gpf, bool is_render); + +void BKE_gpencil_lattice_init(struct Object *ob); +void BKE_gpencil_lattice_clear(struct Object *ob); + +#endif /* __BKE_GPENCIL_MODIFIER_H__ */ diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 22897d2ea80..7a5262e0a14 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -43,7 +43,10 @@ enum { ICON_DATA_PREVIEW, /** 2D triangles: obj is #Icon_Geom */ ICON_DATA_GEOM, + /** Studiolight */ ICON_DATA_STUDIOLIGHT, + /** GPencil Layer color preview (annotations): obj is #bGPDlayer */ + ICON_DATA_GPLAYER, }; struct Icon { @@ -79,6 +82,7 @@ struct ImBuf; struct PreviewImage; struct ID; struct StudioLight; +struct bGPDlayer; enum eIconSizes; @@ -87,6 +91,9 @@ void BKE_icons_init(int first_dyn_id); /* return icon id for library object or create new icon if not found */ int BKE_icon_id_ensure(struct ID *id); +/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */ +int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl); + int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview); /* retrieve icon for id */ diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index c2ac5e98f76..67e6a32edfd 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -54,7 +54,6 @@ void BKE_lattice_free(struct Lattice *lt); void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); -struct LatticeDeformData; struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) ATTR_WARN_UNUSED_RESULT; void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight); void end_latt_deform(struct LatticeDeformData *lattice_deform_data); diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index c85017a2216..1ca8928c61d 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -54,11 +54,13 @@ void BKE_material_init(struct Material *ma); void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst); struct Material *BKE_material_add(struct Main *bmain, const char *name); +struct Material *BKE_material_add_gpencil(struct Main *bmain, const char *name); void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag); struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma); struct Material *BKE_material_localize(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local); +void BKE_material_init_gpencil_settings(struct Material *ma); /* UNUSED */ // void automatname(struct Material *); @@ -87,6 +89,8 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob); bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob); +struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act); + void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma); void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 79e4f1d448a..7d795c25a04 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -37,8 +37,11 @@ extern "C" { struct Base; struct Depsgraph; +struct GpencilModifierData; struct Scene; +struct ShaderFxData; struct ViewLayer; +struct ID; struct Object; struct BoundBox; struct View3D; @@ -49,6 +52,7 @@ struct Mesh; struct RigidBodyWorld; struct HookModifierData; struct ModifierData; +struct HookGpencilModifierData; #include "DNA_object_enums.h" @@ -69,11 +73,16 @@ void BKE_object_free_derived_mesh_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd); +void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd); +bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md); + +bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md); bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type); void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src); void BKE_object_free_modifiers(struct Object *ob, const int flag); +void BKE_object_free_shaderfx(struct Object *ob, const int flag); void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob); void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); @@ -108,6 +117,9 @@ struct Object *BKE_object_add_from( struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, int type, const char *name, struct Object *ob_src) ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL; +struct Object *BKE_object_add_for_data( + struct Main *bmain, struct ViewLayer *view_layer, + int type, const char *name, struct ID *data, bool do_id_user) ATTR_RETURNS_NONNULL; void *BKE_object_obdata_add_from_type( struct Main *bmain, int type, const char *name) diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 6ade14b275c..c440a634c9f 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -77,7 +77,8 @@ typedef enum ePaintMode { ePaintTextureProjective = 3, ePaintTexture2D = 4, ePaintSculptUV = 5, - ePaintInvalid = 6 + ePaintInvalid = 6, + ePaintGpencil = 7 } ePaintMode; /* overlay invalidation */ diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h new file mode 100644 index 00000000000..11c5983106a --- /dev/null +++ b/source/blender/blenkernel/BKE_shader_fx.h @@ -0,0 +1,180 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef __BKE_SHADER_FX_H__ +#define __BKE_SHADER_FX_H__ + +/** \file BKE_shader_fx.h + * \ingroup bke + */ + +#include "DNA_shader_fx_types.h" /* needed for all enum typdefs */ +#include "BLI_compiler_attrs.h" +#include "BKE_customdata.h" + +struct ID; +struct Depsgraph; +struct DerivedMesh; +struct Mesh; +struct Object; +struct Scene; +struct ViewLayer; +struct ListBase; +struct bArmature; +struct Main; +struct ShaderFxData; +struct DepsNodeHandle; +struct bGPDlayer; +struct bGPDframe; +struct bGPDstroke; +struct ModifierUpdateDepsgraphContext; + +#define SHADER_FX_ACTIVE(_fx, _is_render) (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \ + ((_fx->mode & eShaderFxMode_Render) && (_is_render == true))) +#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit)) + +typedef enum { + /* Should not be used, only for None type */ + eShaderFxType_NoneType, + + /* grease pencil effects */ + eShaderFxType_GpencilType, +} ShaderFxTypeType; + +typedef enum { + eShaderFxTypeFlag_SupportsEditmode = (1 << 0), + + /* For effects that support editmode this determines if the + * effect should be enabled by default in editmode. + */ + eShaderFxTypeFlag_EnableInEditmode = (1 << 2), + + /* max one per type */ + eShaderFxTypeFlag_Single = (1 << 4), + + /* can't be added manually by user */ + eShaderFxTypeFlag_NoUserAdd = (1 << 5), +} ShaderFxTypeFlag; + +/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */ +typedef void(*ShaderFxObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag); +typedef void(*ShaderFxIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag); +typedef void(*ShaderFxTexWalkFunc)(void *userData, struct Object *ob, struct ShaderFxData *fx, const char *propname); + +typedef struct ShaderFxTypeInfo { + /* The user visible name for this effect */ + char name[32]; + + /* The DNA struct name for the effect data type, used to + * write the DNA data out. + */ + char struct_name[32]; + + /* The size of the effect data type, used by allocation. */ + int struct_size; + + ShaderFxTypeType type; + ShaderFxTypeFlag flags; + + /* Copy instance data for this effect type. Should copy all user + * level settings to the target effect. + */ + void(*copyData)(const struct ShaderFxData *fx, struct ShaderFxData *target); + + /* Initialize new instance data for this effect type, this function + * should set effect variables to their default values. + * + * This function is optional. + */ + void (*initData)(struct ShaderFxData *fx); + + /* Free internal effect data variables, this function should + * not free the fx variable itself. + * + * This function is optional. + */ + void (*freeData)(struct ShaderFxData *fx); + + /* Return a boolean value indicating if this effect is able to be + * calculated based on the effect data. This is *not* regarding the + * fx->flag, that is tested by the system, this is just if the data + * validates (for example, a lattice will return false if the lattice + * object is not defined). + * + * This function is optional (assumes never disabled if not present). + */ + bool (*isDisabled)(struct ShaderFxData *fx, int userRenderParams); + + /* Add the appropriate relations to the dependency graph. + * + * This function is optional. + */ + void (*updateDepsgraph)(struct ShaderFxData *fx, + const struct ModifierUpdateDepsgraphContext *ctx); + + /* Should return true if the effect needs to be recalculated on time + * changes. + * + * This function is optional (assumes false if not present). + */ + bool (*dependsOnTime)(struct ShaderFxData *fx); + + + /* Should call the given walk function on with a pointer to each Object + * pointer that the effect data stores. This is used for linking on file + * load and for unlinking objects or forwarding object references. + * + * This function is optional. + */ + void (*foreachObjectLink)(struct ShaderFxData *fx, struct Object *ob, + ShaderFxObjectWalkFunc walk, void *userData); + + /* Should call the given walk function with a pointer to each ID + * pointer (i.e. each datablock pointer) that the effect data + * stores. This is used for linking on file load and for + * unlinking datablocks or forwarding datablock references. + * + * This function is optional. If it is not present, foreachObjectLink + * will be used. + */ + void (*foreachIDLink)(struct ShaderFxData *fx, struct Object *ob, + ShaderFxIDWalkFunc walk, void *userData); +} ShaderFxTypeInfo; + +/* Initialize global data (type info and some common global storages). */ +void BKE_shaderfx_init(void); + +const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type); +struct ShaderFxData *BKE_shaderfx_new(int type); +void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag); +void BKE_shaderfx_free(struct ShaderFxData *fx); +bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx); +bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx); +struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type); +struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name); +void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst); +void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target); +void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag); +void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData); + +bool BKE_shaderfx_has_gpencil(struct Object *ob); + +#endif /* __BKE_SHADER_FX_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 01910bffdb0..7169597f100 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -38,6 +38,8 @@ set(INC ../makesrna ../bmesh ../modifiers + ../gpencil_modifiers + ../shader_fx ../nodes ../physics ../render/extern/include @@ -115,6 +117,7 @@ set(SRC intern/font.c intern/freestyle.c intern/gpencil.c + intern/gpencil_modifier.c intern/icons.c intern/icons_rasterize.c intern/idcode.c @@ -180,6 +183,7 @@ set(SRC intern/seqeffects.c intern/seqmodifier.c intern/sequencer.c + intern/shader_fx.c intern/shrinkwrap.c intern/smoke.c intern/softbody.c @@ -259,6 +263,7 @@ set(SRC BKE_freestyle.h BKE_global.h BKE_gpencil.h + BKE_gpencil_modifier.h BKE_icons.h BKE_idcode.h BKE_idprop.h @@ -306,6 +311,7 @@ set(SRC BKE_scene.h BKE_screen.h BKE_sequencer.h + BKE_shader_fx.h BKE_shrinkwrap.h BKE_smoke.h BKE_softbody.h diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index fd7497f9ba1..7dfedfe6c06 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -104,6 +104,7 @@ bool id_type_can_have_animdata(const short id_type) case ID_MSK: case ID_GD: case ID_CF: + case ID_PAL: return true; /* no AnimData */ @@ -1150,6 +1151,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use /* grease pencil */ ANIMDATA_IDS_CB(bmain->gpencil.first); + /* palettes */ + ANIMDATA_IDS_CB(bmain->palettes.first); + /* cache files */ ANIMDATA_IDS_CB(bmain->cachefiles.first); } @@ -2925,6 +2929,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene /* grease pencil */ EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM); + /* palettes */ + EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM); + /* cache files */ EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 42cd7968321..598eb9b5b54 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -29,6 +29,7 @@ #include "DNA_brush_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "DNA_gpencil_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -36,6 +37,7 @@ #include "BKE_brush.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -129,6 +131,7 @@ static void brush_defaults(Brush *brush) brush->stencil_dimension[0] = 256; brush->stencil_dimension[1] = 256; + } /* Datablock add/copy/free/make_local */ @@ -164,6 +167,368 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode) return brush; } +/* add a new gp-brush */ +Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name) +{ + Brush *brush; + Paint *paint = BKE_brush_get_gpencil_paint(ts); + brush = BKE_brush_add(bmain, name, OB_MODE_GPENCIL_PAINT); + + BKE_paint_brush_set(paint, brush); + id_us_min(&brush->id); + + /* grease pencil basic settings */ + brush->size = 3; + + brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings"); + + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->flag = 0; + brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; + brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; + + /* curves */ + brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + + /* return brush */ + return brush; +} + +Paint *BKE_brush_get_gpencil_paint(ToolSettings *ts) +{ + /* alloc paint session */ + if (ts->gp_paint == NULL) { + ts->gp_paint = MEM_callocN(sizeof(GpPaint), "GpPaint"); + } + + return &ts->gp_paint->paint; +} + +/* grease pencil cumapping->preset */ +typedef enum eGPCurveMappingPreset { + GPCURVE_PRESET_PENCIL = 0, + GPCURVE_PRESET_INK = 1, + GPCURVE_PRESET_INKNOISE = 2, +} eGPCurveMappingPreset; + +static void brush_gpencil_curvemap_reset(CurveMap *cuma, int preset) +{ + if (cuma->curve) + MEM_freeN(cuma->curve); + + cuma->totpoint = 3; + cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__); + + switch (preset) { + case GPCURVE_PRESET_PENCIL: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.75115f; + cuma->curve[1].y = 0.25f; + cuma->curve[2].x = 1.0f; + cuma->curve[2].y = 1.0f; + break; + case GPCURVE_PRESET_INK: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.63448f; + cuma->curve[1].y = 0.375f; + cuma->curve[2].x = 1.0f; + cuma->curve[2].y = 1.0f; + break; + case GPCURVE_PRESET_INKNOISE: + cuma->curve[0].x = 0.0f; + cuma->curve[0].y = 0.0f; + cuma->curve[1].x = 0.63134f; + cuma->curve[1].y = 0.3625f; + cuma->curve[2].x = 1.0f; + cuma->curve[2].y = 1.0f; + break; + } + + if (cuma->table) { + MEM_freeN(cuma->table); + cuma->table = NULL; + } +} + +/* create a set of grease pencil presets */ +void BKE_brush_gpencil_presets(bContext *C) +{ +#define SMOOTH_STROKE_RADIUS 40 +#define SMOOTH_STROKE_FACTOR 0.9f + + ToolSettings *ts = CTX_data_tool_settings(C); + Paint *paint = BKE_brush_get_gpencil_paint(ts); + Main *bmain = CTX_data_main(C); + + Brush *brush, *deft; + CurveMapping *custom_curve; + + /* Pencil brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil"); + brush->size = 25.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 0.6f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->draw_random_press = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Pen brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen"); + deft = brush; /* save default brush */ + brush->size = 30.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->draw_random_press = 0.0f; + brush->gpencil_settings->draw_random_strength = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Ink brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink"); + brush->size = 60.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.6f; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->draw_random_press = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Curve */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INK); + + /* Ink Noise brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise"); + brush->size = 60.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.7f; + brush->gpencil_settings->draw_random_strength = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 1.0f; + brush->gpencil_settings->draw_smoothlvl = 2; + brush->gpencil_settings->thick_smoothfac = 0.5f; + brush->gpencil_settings->thick_smoothlvl = 2; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Curve */ + custom_curve = brush->gpencil_settings->curve_sensitivity; + curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f); + curvemapping_initialize(custom_curve); + brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INKNOISE); + + /* Block Basic brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block"); + brush->size = 150.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 0.7f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->gpencil_settings->draw_random_press = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = 0.0f; + brush->gpencil_settings->draw_angle_factor = 0.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.0f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 0; + brush->gpencil_settings->draw_random_sub = 0; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Marker brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker"); + brush->size = 80.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR); + brush->gpencil_settings->draw_sensitivity = 1.0f; + + brush->gpencil_settings->draw_strength = 1.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM; + brush->gpencil_settings->draw_random_press = 0.374f; + brush->gpencil_settings->draw_random_strength = 0.0f; + + brush->gpencil_settings->draw_jitter = 0.0f; + brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + + brush->gpencil_settings->draw_angle = M_PI_4; /* 45 degrees */ + brush->gpencil_settings->draw_angle_factor = 1.0f; + + brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; + brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + brush->gpencil_settings->draw_random_sub = 0.0f; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + /* Fill brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area"); + brush->size = 1.0f; + brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->draw_sensitivity = 1.0f; + brush->gpencil_settings->fill_leak = 3; + brush->gpencil_settings->fill_threshold = 0.1f; + brush->gpencil_settings->fill_simplylvl = 1; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_FILL; + + brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothlvl = 1; + brush->gpencil_settings->thick_smoothfac = 1.0f; + brush->gpencil_settings->thick_smoothlvl = 3; + brush->gpencil_settings->draw_subdivide = 1; + + brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; + brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + + brush->gpencil_settings->draw_strength = 1.0f; + + /* Soft Eraser brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft"); + brush->size = 30.0f; + brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; + + /* Hard Eraser brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard"); + brush->size = 30.0f; + brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD; + + /* Stroke Eraser brush */ + brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke"); + brush->size = 30.0f; + brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR; + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; + brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE; + brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE; + + /* set defaut brush */ + BKE_paint_brush_set(paint, deft); + +} + +/* get the active gp-brush for editing */ +Brush *BKE_brush_getactive_gpencil(ToolSettings *ts) +{ + /* error checking */ + if (ELEM(NULL, ts, ts->gp_paint)) { + return NULL; + } + Paint *paint = &ts->gp_paint->paint; + + return paint->brush; +} + struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode) { Brush *brush; @@ -197,6 +562,12 @@ void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *bru } brush_dst->curve = curvemapping_copy(brush_src->curve); + if (brush_src->gpencil_settings != NULL) { + brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings); + brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity); + brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength); + brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter); + } /* enable fake user by default */ id_fake_user_set(&brush_dst->id); @@ -215,11 +586,18 @@ void BKE_brush_free(Brush *brush) if (brush->icon_imbuf) { IMB_freeImBuf(brush->icon_imbuf); } - curvemapping_free(brush->curve); + if (brush->gpencil_settings != NULL) { + curvemapping_free(brush->gpencil_settings->curve_sensitivity); + curvemapping_free(brush->gpencil_settings->curve_strength); + curvemapping_free(brush->gpencil_settings->curve_jitter); + MEM_SAFE_FREE(brush->gpencil_settings); + } + MEM_SAFE_FREE(brush->gradient); + BKE_previewimg_free(&(brush->preview)); } diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index ff4795afe87..d18572a57f6 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -282,6 +282,7 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) case CURVE_PRESET_MID9: cuma->totpoint = 9; break; case CURVE_PRESET_ROUND: cuma->totpoint = 4; break; case CURVE_PRESET_ROOT: cuma->totpoint = 4; break; + case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break; } cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points"); @@ -352,6 +353,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope) cuma->curve[3].x = 1; cuma->curve[3].y = 0; break; + case CURVE_PRESET_GAUSS: + cuma->curve[0].x = 0; + cuma->curve[0].y = 0.025f; + cuma->curve[1].x = 0.16f; + cuma->curve[1].y = 0.135f; + cuma->curve[2].x = 0.298f; + cuma->curve[2].y = 0.36f; + + cuma->curve[3].x = 0.50f; + cuma->curve[3].y = 1.0f; + + cuma->curve[4].x = 0.70f; + cuma->curve[4].y = 0.36f; + cuma->curve[5].x = 0.84f; + cuma->curve[5].y = 0.135f; + cuma->curve[6].x = 1.0f; + cuma->curve[6].y = 0.025f; + break; } /* mirror curve in x direction to have positive slope diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 3dfe9732062..84ca143dc55 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -1014,6 +1014,10 @@ int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectM else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX; else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE; else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE; + else if (object_mode & OB_MODE_GPENCIL_PAINT) return CTX_MODE_GPENCIL_PAINT; + else if (object_mode & OB_MODE_GPENCIL_EDIT) return CTX_MODE_GPENCIL_EDIT; + else if (object_mode & OB_MODE_GPENCIL_SCULPT) return CTX_MODE_GPENCIL_SCULPT; + else if (object_mode & OB_MODE_GPENCIL_WEIGHT) return CTX_MODE_GPENCIL_WEIGHT; } } @@ -1044,6 +1048,10 @@ static const char *data_mode_strings[] = { "imagepaint", "particlemode", "objectmode", + "greasepencil_paint", + "greasepencil_edit", + "greasepencil_sculpt", + "greasepencil_weight", NULL }; BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode") @@ -1212,17 +1220,7 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C) return ctx_data_pointer_get(C, "active_gpencil_layer"); } -bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C) -{ - return ctx_data_pointer_get(C, "active_gpencil_palette"); -} - -bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C) -{ - return ctx_data_pointer_get(C, "active_gpencil_palettecolor"); -} - -bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C) +Brush *CTX_data_active_gpencil_brush(const bContext *C) { return ctx_data_pointer_get(C, "active_gpencil_brush"); } diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index d08e3643ca7..ddf9840a32e 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -74,7 +74,9 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name) BLI_addtail(&ob->defbase, defgroup); defgroup_unique_name(defgroup, ob); - BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + if (ob->type != OB_GPENCIL) { + BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + } return defgroup; } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index e89508fd6c0..de3f891f9f9 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -39,26 +39,83 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_math_color.h" #include "BLI_string_utils.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" #include "BLT_translation.h" +#include "DNA_anim_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_material_types.h" #include "DNA_gpencil_types.h" #include "DNA_userdef_types.h" #include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "BKE_context.h" +#include "BKE_action.h" #include "BKE_animsys.h" #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_colortools.h" +#include "BKE_icons.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_material.h" +#include "DEG_depsgraph.h" /* ************************************************** */ -/* GENERAL STUFF */ +/* Draw Engine */ -/* --------- Memory Management ------------ */ +void(*BKE_gpencil_batch_cache_dirty_cb)(bGPdata *gpd) = NULL; +void(*BKE_gpencil_batch_cache_free_cb)(bGPdata *gpd) = NULL; + +void BKE_gpencil_batch_cache_dirty(bGPdata *gpd) +{ + if (gpd) { + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + BKE_gpencil_batch_cache_dirty_cb(gpd); + } +} + +void BKE_gpencil_batch_cache_free(bGPdata *gpd) +{ + if (gpd) { + BKE_gpencil_batch_cache_free_cb(gpd); + } +} + +/* ************************************************** */ +/* Memory Management */ + +/* clean vertex groups weights */ +void BKE_gpencil_free_point_weights(MDeformVert *dvert) +{ + if (dvert == NULL) { + return; + } + MEM_SAFE_FREE(dvert->dw); +} + +void BKE_gpencil_free_stroke_weights(bGPDstroke *gps) +{ + if (gps == NULL) { + return; + } + + if (gps->dvert == NULL) { + return; + } + + for (int i = 0; i < gps->totpoints; i++) { + MDeformVert *dvert = &gps->dvert[i]; + BKE_gpencil_free_point_weights(dvert); + } +} /* free stroke, doesn't unlink from any listbase */ void BKE_gpencil_free_stroke(bGPDstroke *gps) @@ -66,10 +123,14 @@ void BKE_gpencil_free_stroke(bGPDstroke *gps) if (gps == NULL) { return; } - /* free stroke memory arrays, then stroke itself */ - if (gps->points) + if (gps->points) { MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } if (gps->triangles) MEM_freeN(gps->triangles); @@ -92,6 +153,26 @@ bool BKE_gpencil_free_strokes(bGPDframe *gpf) return changed; } +/* Free strokes and colors belonging to a gp-frame */ +bool BKE_gpencil_free_frame_runtime_data(bGPDframe *derived_gpf) +{ + bGPDstroke *gps_next; + if (!derived_gpf) { + return false; + } + + /* free strokes */ + for (bGPDstroke *gps = derived_gpf->strokes.first; gps; gps = gps_next) { + gps_next = gps->next; + BKE_gpencil_free_stroke(gps); + } + BLI_listbase_clear(&derived_gpf->strokes); + + MEM_SAFE_FREE(derived_gpf); + + return true; +} + /* Free all of a gp-layer's frames */ void BKE_gpencil_free_frames(bGPDlayer *gpl) { @@ -111,101 +192,101 @@ void BKE_gpencil_free_frames(bGPDlayer *gpl) gpl->actframe = NULL; } -/* Free all of a gp-colors */ -static void free_gpencil_colors(bGPDpalette *palette) -{ - /* error checking */ - if (palette == NULL) { - return; - } - /* free colors */ - BLI_freelistN(&palette->colors); -} -/* Free all of the gp-palettes and colors */ -void BKE_gpencil_free_palettes(ListBase *list) +/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ +void BKE_gpencil_free_layers(ListBase *list) { - bGPDpalette *palette_next; + bGPDlayer *gpl_next; /* error checking */ - if (list == NULL) { - return; - } + if (list == NULL) return; - /* delete palettes */ - for (bGPDpalette *palette = list->first; palette; palette = palette_next) { - palette_next = palette->next; - /* free palette colors */ - free_gpencil_colors(palette); + /* delete layers */ + for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) { + gpl_next = gpl->next; - MEM_freeN(palette); + /* free layers and their data */ + BKE_gpencil_free_frames(gpl); + BLI_freelinkN(list, gpl); } - BLI_listbase_clear(list); } -/* Free all of the gp-brushes for a viewport (list should be &gpd->brushes or so) */ -void BKE_gpencil_free_brushes(ListBase *list) +/* clear all runtime derived data */ +static void BKE_gpencil_clear_derived(bGPDlayer *gpl) { - bGPDbrush *brush_next; + GHashIterator gh_iter; - /* error checking */ - if (list == NULL) { + if (gpl->runtime.derived_data == NULL) { return; } - /* delete brushes */ - for (bGPDbrush *brush = list->first; brush; brush = brush_next) { - brush_next = brush->next; - /* free curves */ - if (brush->cur_sensitivity) { - curvemapping_free(brush->cur_sensitivity); - } - if (brush->cur_strength) { - curvemapping_free(brush->cur_strength); + GHASH_ITER(gh_iter, gpl->runtime.derived_data) { + bGPDframe *gpf = (bGPDframe *)BLI_ghashIterator_getValue(&gh_iter); + if (gpf) { + BKE_gpencil_free_frame_runtime_data(gpf); } - if (brush->cur_jitter) { - curvemapping_free(brush->cur_jitter); - } - - MEM_freeN(brush); } - BLI_listbase_clear(list); } -/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */ -void BKE_gpencil_free_layers(ListBase *list) +/* Free all of the gp-layers temp data*/ +static void BKE_gpencil_free_layers_temp_data(ListBase *list) { bGPDlayer *gpl_next; /* error checking */ if (list == NULL) return; - /* delete layers */ for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) { gpl_next = gpl->next; + BKE_gpencil_clear_derived(gpl); - /* free layers and their data */ - BKE_gpencil_free_frames(gpl); - BLI_freelinkN(list, gpl); + if (gpl->runtime.derived_data) { + BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL); + gpl->runtime.derived_data = NULL; + } + } +} + +/* Free temp gpf derived frames */ +void BKE_gpencil_free_derived_frames(bGPdata *gpd) +{ + /* error checking */ + if (gpd == NULL) return; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + BKE_gpencil_clear_derived(gpl); + + if (gpl->runtime.derived_data) { + BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL); + gpl->runtime.derived_data = NULL; + } } } /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ -void BKE_gpencil_free(bGPdata *gpd, bool free_palettes) +void BKE_gpencil_free(bGPdata *gpd, bool free_all) { + /* clear animation data */ BKE_animdata_free(&gpd->id, false); /* free layers */ + if (free_all) { + BKE_gpencil_free_layers_temp_data(&gpd->layers); + } BKE_gpencil_free_layers(&gpd->layers); - /* free palettes */ - if (free_palettes) { - BKE_gpencil_free_palettes(&gpd->palettes); + /* materials */ + MEM_SAFE_FREE(gpd->mat); + + /* free all data */ + if (free_all) { + /* clear cache */ + BKE_gpencil_batch_cache_free(gpd); } } -/* -------- Container Creation ---------- */ +/* ************************************************** */ +/* Container Creation */ /* add a new gp-frame to the given layer */ bGPDframe *BKE_gpencil_frame_addnew(bGPDlayer *gpl, int cframe) @@ -329,28 +410,31 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti /* add to datablock */ BLI_addtail(&gpd->layers, gpl); - /* set basic settings */ - copy_v4_v4(gpl->color, U.gpencil_new_layer_col); - /* Since GPv2 thickness must be 0 */ - gpl->thickness = 0; - - gpl->opacity = 1.0f; + /* annotation vs GP Object behaviour is slightly different */ + if (gpd->flag & GP_DATA_ANNOTATIONS) { + /* set default color of new strokes for this layer */ + copy_v4_v4(gpl->color, U.gpencil_new_layer_col); + gpl->opacity = 1.0f; - /* onion-skinning settings */ - if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) - gpl->flag |= GP_LAYER_ONIONSKIN; + /* set default thickness of new strokes for this layer */ + gpl->thickness = 3; - gpl->flag |= (GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL); - - ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */ - ARRAY_SET_ITEMS(gpl->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */ - - /* high quality fill by default */ - gpl->flag |= GP_LAYER_HQ_FILL; + /* onion-skinning settings */ + gpl->onion_flag |= GP_LAYER_ONIONSKIN; + } + else { + /* thickness parameter represents "thickness change", not absolute thickness */ + gpl->thickness = 0; + gpl->opacity = 1.0f; + } /* auto-name */ BLI_strncpy(gpl->info, name, sizeof(gpl->info)); - BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); + BLI_uniquename(&gpd->layers, gpl, + (gpd->flag & GP_DATA_ANNOTATIONS) ? DATA_("Note") : DATA_("GP_Layer"), + '.', + offsetof(bGPDlayer, info), + sizeof(gpl->info)); /* make this one the active one */ if (setactive) @@ -360,292 +444,153 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti return gpl; } -/* add a new gp-palette and make it the active */ -bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool setactive) -{ - bGPDpalette *palette; - - /* check that list is ok */ - if (gpd == NULL) { - return NULL; - } - - /* allocate memory and add to end of list */ - palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette"); - - /* add to datablock */ - BLI_addtail(&gpd->palettes, palette); - - /* set basic settings */ - /* auto-name */ - BLI_strncpy(palette->info, name, sizeof(palette->info)); - BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info), - sizeof(palette->info)); - - /* make this one the active one */ - /* NOTE: Always make this active if there's nothing else yet (T50123) */ - if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) { - BKE_gpencil_palette_setactive(gpd, palette); - } - - /* return palette */ - return palette; -} - -/* create a set of default drawing brushes with predefined presets */ -void BKE_gpencil_brush_init_presets(ToolSettings *ts) +/* add a new gp-datablock */ +bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) { - bGPDbrush *brush; - /* Basic brush */ - brush = BKE_gpencil_brush_addnew(ts, "Basic", true); - brush->thickness = 3.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.0f; - brush->flag |= GP_BRUSH_USE_PRESSURE; - - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag |= ~GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->draw_random_press = 0.0f; - - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; - - brush->draw_smoothfac = 0.0f; - brush->draw_smoothlvl = 1; - brush->sublevel = 0; - brush->draw_random_sub = 0.0f; - - /* Pencil brush */ - brush = BKE_gpencil_brush_addnew(ts, "Pencil", false); - brush->thickness = 7.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.0f; - brush->flag |= GP_BRUSH_USE_PRESSURE; - - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 0.7f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->draw_random_press = 0.0f; - - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; - - brush->draw_smoothfac = 1.0f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; - - /* Ink brush */ - brush = BKE_gpencil_brush_addnew(ts, "Ink", false); - brush->thickness = 7.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.6f; - brush->flag |= GP_BRUSH_USE_PRESSURE; - - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE; - - brush->draw_random_press = 0.0f; - - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; + bGPdata *gpd; - brush->draw_smoothfac = 1.1f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; + /* allocate memory for a new block */ + gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0); - /* Ink Noise brush */ - brush = BKE_gpencil_brush_addnew(ts, "Ink noise", false); - brush->thickness = 6.0f; - brush->flag |= GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 1.611f; - brush->flag |= GP_BRUSH_USE_PRESSURE; + /* initial settings */ + gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND); - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + /* general flags */ + gpd->flag |= GP_DATA_VIEWALIGN; - brush->draw_random_press = 1.0f; + /* GP object specific settings */ + ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f); - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + gpd->xray_mode = GP_XRAY_3DSPACE; + gpd->runtime.batch_cache_data = NULL; + gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; + /* onion-skinning settings (datablock level) */ + gpd->onion_flag |= (GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL); + gpd->onion_flag |= GP_ONION_FADE; + gpd->onion_mode = GP_ONION_MODE_RELATIVE; + gpd->onion_factor = 0.5f; + ARRAY_SET_ITEMS(gpd->gcolor_prev, 0.145098f, 0.419608f, 0.137255f); /* green */ + ARRAY_SET_ITEMS(gpd->gcolor_next, 0.125490f, 0.082353f, 0.529412f); /* blue */ + gpd->gstep = 1; + gpd->gstep_next = 1; - brush->draw_smoothfac = 1.1f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; + return gpd; +} - /* Marker brush */ - brush = BKE_gpencil_brush_addnew(ts, "Marker", false); - brush->thickness = 10.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 2.0f; - brush->flag &= ~GP_BRUSH_USE_PRESSURE; - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 1.0f; - brush->flag &= ~GP_BRUSH_USE_STENGTH_PRESSURE; +/* ************************************************** */ +/* Primitive Creation */ +/* Utilities for easier bulk-creation of geometry */ - brush->draw_random_press = 0.0f; +/** + * Populate stroke with point data from data buffers + * + * \param array Flat array of point data values. Each entry has GP_PRIM_DATABUF_SIZE values + * \param mat 4x4 transform matrix to transform points into the right coordinate space + */ +void BKE_gpencil_stroke_add_points(bGPDstroke *gps, const float *array, const int totpoints, const float mat[4][4]) +{ + for (int i = 0; i < totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + const int x = GP_PRIM_DATABUF_SIZE * i; - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + pt->x = array[x]; + pt->y = array[x + 1]; + pt->z = array[x + 2]; + mul_m4_v3(mat, &pt->x); - brush->draw_angle = M_PI_4; /* 45 degrees */ - brush->draw_angle_factor = 1.0f; + pt->pressure = array[x + 3]; + pt->strength = array[x + 4]; + } +} - brush->draw_smoothfac = 1.0f; - brush->draw_smoothlvl = 2; - brush->sublevel = 2; - brush->draw_random_sub = 0.0f; +/* Create a new stroke, with pre-allocated data buffers */ +bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness) +{ + /* allocate memory for a new stroke */ + bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); - /* Crayon brush */ - brush = BKE_gpencil_brush_addnew(ts, "Crayon", false); - brush->thickness = 10.0f; - brush->flag &= ~GP_BRUSH_USE_RANDOM_PRESSURE; - brush->draw_sensitivity = 3.0f; - brush->flag &= ~GP_BRUSH_USE_PRESSURE; + gps->thickness = thickness * 25; + gps->inittime = 0; - brush->flag &= ~GP_BRUSH_USE_RANDOM_STRENGTH; - brush->draw_strength = 0.140f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + /* enable recalculation flag by default */ + gps->flag = GP_STROKE_RECALC_CACHES | GP_STROKE_3DSPACE; - brush->draw_random_press = 0.0f; + gps->totpoints = totpoints; + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; + /* initialize triangle memory to dummy data */ + gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation"); + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; - brush->draw_angle = 0.0f; - brush->draw_angle_factor = 0.0f; + gps->mat_nr = mat_idx; - brush->draw_smoothfac = 0.0f; - brush->draw_smoothlvl = 1; - brush->sublevel = 2; - brush->draw_random_sub = 0.5f; + /* add to frame */ + BLI_addtail(&gpf->strokes, gps); + return gps; } -/* add a new gp-brush and make it the active */ -bGPDbrush *BKE_gpencil_brush_addnew(ToolSettings *ts, const char *name, bool setactive) -{ - bGPDbrush *brush; - - /* check that list is ok */ - if (ts == NULL) { - return NULL; - } - - /* allocate memory and add to end of list */ - brush = MEM_callocN(sizeof(bGPDbrush), "bGPDbrush"); - /* add to datablock */ - BLI_addtail(&ts->gp_brushes, brush); - - /* set basic settings */ - brush->thickness = 3; - brush->draw_smoothlvl = 1; - brush->flag |= GP_BRUSH_USE_PRESSURE; - brush->draw_sensitivity = 1.0f; - brush->draw_strength = 1.0f; - brush->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->draw_jitter = 0.0f; - brush->flag |= GP_BRUSH_USE_JITTER_PRESSURE; - - /* curves */ - brush->cur_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - brush->cur_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - brush->cur_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - - /* auto-name */ - BLI_strncpy(brush->info, name, sizeof(brush->info)); - BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info)); - - /* make this one the active one */ - if (setactive) { - BKE_gpencil_brush_setactive(ts, brush); - } - - /* return brush */ - return brush; -} +/* ************************************************** */ +/* Data Duplication */ -/* add a new gp-palettecolor and make it the active */ -bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name, bool setactive) +/* make a copy of a given gpencil weights */ +void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_dst) { - bGPDpalettecolor *palcolor; - - /* check that list is ok */ - if (palette == NULL) { - return NULL; + if (gps_src == NULL) { + return; } + BLI_assert(gps_src->totpoints == gps_dst->totpoints); - /* allocate memory and add to end of list */ - palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor"); - - /* add to datablock */ - BLI_addtail(&palette->colors, palcolor); - - /* set basic settings */ - palcolor->flag |= PC_COLOR_HQ_FILL; - copy_v4_v4(palcolor->color, U.gpencil_new_layer_col); - ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f); + if ((gps_src->dvert == NULL) || (gps_dst->dvert == NULL)){ + return; + } - /* auto-name */ - BLI_strncpy(palcolor->info, name, sizeof(palcolor->info)); - BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info), - sizeof(palcolor->info)); + for (int i = 0; i < gps_src->totpoints; i++) { + MDeformVert *dvert_src = &gps_src->dvert[i]; + MDeformVert *dvert_dst = &gps_dst->dvert[i]; + if (dvert_src->totweight > 0) { + dvert_dst->dw = MEM_dupallocN(dvert_src->dw); + } + else { + dvert_dst->dw = NULL; + } - /* make this one the active one */ - if (setactive) { - BKE_gpencil_palettecolor_setactive(palette, palcolor); } - - /* return palette color */ - return palcolor; } -/* add a new gp-datablock */ -bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) +/* make a copy of a given gpencil stroke */ +bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src) { - bGPdata *gpd; + bGPDstroke *gps_dst = NULL; - /* allocate memory for a new block */ - gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0); + gps_dst = MEM_dupallocN(gps_src); + gps_dst->prev = gps_dst->next = NULL; - /* initial settings */ - gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND); + gps_dst->points = MEM_dupallocN(gps_src->points); - /* for now, stick to view is also enabled by default - * since this is more useful... + gps_dst->dvert = MEM_dupallocN(gps_src->dvert); + BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); + + /* Don't clear triangles, so that modifier evaluation can just use + * this without extra work first. Most places that need to force + * this data to get recalculated will destroy the data anyway though. */ - gpd->flag |= GP_DATA_VIEWALIGN; + gps_dst->triangles = MEM_dupallocN(gps_dst->triangles); + /* gps_dst->flag |= GP_STROKE_RECALC_CACHES; */ - return gpd; + /* return new stroke */ + return gps_dst; } -/* -------- Data Duplication ---------- */ - /* make a copy of a given gpencil frame */ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) { - bGPDstroke *gps_dst; + bGPDstroke *gps_dst = NULL; bGPDframe *gpf_dst; /* error checking */ @@ -660,11 +605,8 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) /* copy strokes */ BLI_listbase_clear(&gpf_dst->strokes); for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { - /* make copy of source stroke, then adjust pointer to points too */ - gps_dst = MEM_dupallocN(gps_src); - gps_dst->points = MEM_dupallocN(gps_src->points); - gps_dst->triangles = MEM_dupallocN(gps_src->triangles); - gps_dst->flag |= GP_STROKE_RECALC_CACHES; + /* make copy of source stroke */ + gps_dst = BKE_gpencil_stroke_duplicate(gps_src); BLI_addtail(&gpf_dst->strokes, gps_dst); } @@ -672,55 +614,24 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) return gpf_dst; } -/* make a copy of a given gpencil brush */ -bGPDbrush *BKE_gpencil_brush_duplicate(const bGPDbrush *brush_src) +/* make a copy of strokes between gpencil frames */ +void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_dst) { - bGPDbrush *brush_dst; - + bGPDstroke *gps_dst = NULL; /* error checking */ - if (brush_src == NULL) { - return NULL; - } - - /* make a copy of source brush */ - brush_dst = MEM_dupallocN(brush_src); - brush_dst->prev = brush_dst->next = NULL; - /* make a copy of curves */ - brush_dst->cur_sensitivity = curvemapping_copy(brush_src->cur_sensitivity); - brush_dst->cur_strength = curvemapping_copy(brush_src->cur_strength); - brush_dst->cur_jitter = curvemapping_copy(brush_src->cur_jitter); - - /* return new brush */ - return brush_dst; -} - -/* make a copy of a given gpencil palette */ -bGPDpalette *BKE_gpencil_palette_duplicate(const bGPDpalette *palette_src) -{ - bGPDpalette *palette_dst; - const bGPDpalettecolor *palcolor_src; - bGPDpalettecolor *palcolord_dst; - - /* error checking */ - if (palette_src == NULL) { - return NULL; + if ((gpf_src == NULL) || (gpf_dst == NULL)) { + return; } - /* make a copy of source palette */ - palette_dst = MEM_dupallocN(palette_src); - palette_dst->prev = palette_dst->next = NULL; - - /* copy colors */ - BLI_listbase_clear(&palette_dst->colors); - for (palcolor_src = palette_src->colors.first; palcolor_src; palcolor_src = palcolor_src->next) { - /* make a copy of source */ - palcolord_dst = MEM_dupallocN(palcolor_src); - BLI_addtail(&palette_dst->colors, palcolord_dst); + /* copy strokes */ + BLI_listbase_clear(&gpf_dst->strokes); + for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { + /* make copy of source stroke */ + gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + BLI_addtail(&gpf_dst->strokes, gps_dst); } - - /* return new palette */ - return palette_dst; } + /* make a copy of a given gpencil layer */ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) { @@ -736,6 +647,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) /* make a copy of source layer */ gpl_dst = MEM_dupallocN(gpl_src); gpl_dst->prev = gpl_dst->next = NULL; + gpl_dst->runtime.derived_data = NULL; /* copy frames */ BLI_listbase_clear(&gpl_dst->frames); @@ -755,7 +667,7 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) /** * Only copy internal data of GreasePencil ID from source to already allocated/initialized destination. - * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. + * You probably never want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. * * WARNING! This function will not handle ID user count! * @@ -763,6 +675,14 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) */ void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata *gpd_src, const int UNUSED(flag)) { + /* cache data is not duplicated */ + gpd_dst->runtime.batch_cache_data = NULL; + + /* duplicate material array */ + if (gpd_src->mat) { + gpd_dst->mat = MEM_dupallocN(gpd_src->mat); + } + /* copy layers */ BLI_listbase_clear(&gpd_dst->layers); for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { @@ -771,45 +691,46 @@ void BKE_gpencil_copy_data(Main *UNUSED(bmain), bGPdata *gpd_dst, const bGPdata BLI_addtail(&gpd_dst->layers, gpl_dst); } - /* copy palettes */ - BLI_listbase_clear(&gpd_dst->palettes); - for (const bGPDpalette *palette_src = gpd_src->palettes.first; palette_src; palette_src = palette_src->next) { - bGPDpalette *palette_dst = BKE_gpencil_palette_duplicate(palette_src); /* TODO here too could add unused flags... */ - BLI_addtail(&gpd_dst->palettes, palette_dst); - } +} + +/* Standard API to make a copy of GP datablock, separate from copying its data */ +bGPdata *BKE_gpencil_copy(Main *bmain, const bGPdata *gpd) +{ + bGPdata *gpd_copy; + BKE_id_copy_ex(bmain, &gpd->id, (ID **)&gpd_copy, 0, false); + return gpd_copy; } /* make a copy of a given gpencil datablock */ +// XXX: Should this be deprecated? bGPdata *BKE_gpencil_data_duplicate(Main *bmain, const bGPdata *gpd_src, bool internal_copy) { + bGPdata *gpd_dst; + /* Yuck and super-uber-hyper yuck!!! * Should be replaceable with a no-main copy (LIB_ID_COPY_NO_MAIN etc.), but not sure about it, * so for now keep old code for that one. */ - if (internal_copy) { - const bGPDlayer *gpl_src; - bGPDlayer *gpl_dst; - bGPdata *gpd_dst; + /* error checking */ + if (gpd_src == NULL) { + return NULL; + } + + if (internal_copy) { /* make a straight copy for undo buffers used during stroke drawing */ gpd_dst = MEM_dupallocN(gpd_src); - - /* copy layers */ - BLI_listbase_clear(&gpd_dst->layers); - for (gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { - /* make a copy of source layer and its data */ - gpl_dst = BKE_gpencil_layer_duplicate(gpl_src); - BLI_addtail(&gpd_dst->layers, gpl_dst); - } - - /* return new */ - return gpd_dst; } else { BLI_assert(bmain != NULL); - bGPdata *gpd_copy; - BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_copy, 0, false); - return gpd_copy; + BKE_id_copy_ex(bmain, &gpd_src->id, (ID **)&gpd_dst, 0, false); + gpd_dst->runtime.batch_cache_data = NULL; } + + /* Copy internal data (layers, etc.) */ + BKE_gpencil_copy_data(bmain, gpd_dst, gpd_src, 0); + + /* return new */ + return gpd_dst; } void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) @@ -817,7 +738,8 @@ void BKE_gpencil_make_local(Main *bmain, bGPdata *gpd, const bool lib_local) BKE_id_make_local_generic(bmain, &gpd->id, true, lib_local); } -/* -------- GP-Stroke API --------- */ +/* ************************************************** */ +/* GP Stroke API */ /* ensure selection status of stroke is in sync with its points */ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps) @@ -842,7 +764,8 @@ void BKE_gpencil_stroke_sync_selection(bGPDstroke *gps) } } -/* -------- GP-Frame API ---------- */ +/* ************************************************** */ +/* GP Frame API */ /* delete the last stroke of the given frame */ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) @@ -855,7 +778,13 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) return; /* free the stroke and its data */ - MEM_freeN(gps->points); + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } MEM_freeN(gps->triangles); BLI_freelinkN(&gpf->strokes, gps); @@ -866,7 +795,8 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) } } -/* -------- GP-Layer API ---------- */ +/* ************************************************** */ +/* GP Layer API */ /* Check if the given layer is able to be edited or not */ bool gpencil_layer_is_editable(const bGPDlayer *gpl) @@ -1048,8 +978,6 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) */ if (gpl->actframe == gpf) gpl->actframe = gpf->prev; - else - gpl->actframe = NULL; /* free the frame and its data */ changed = BKE_gpencil_free_strokes(gpf); @@ -1103,255 +1031,602 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl) /* free layer */ BKE_gpencil_free_frames(gpl); + + /* free icon providing preview of icon color */ + BKE_icon_delete(gpl->runtime.icon_id); + + /* free derived data */ + BKE_gpencil_clear_derived(gpl); + if (gpl->runtime.derived_data) { + BLI_ghash_free(gpl->runtime.derived_data, NULL, NULL); + gpl->runtime.derived_data = NULL; + } + BLI_freelinkN(&gpd->layers, gpl); } -/* ************************************************** */ -/* get the active gp-brush for editing */ -bGPDbrush *BKE_gpencil_brush_getactive(ToolSettings *ts) +Material *BKE_gpencil_get_material_from_brush(Brush *brush) { - bGPDbrush *brush; + Material *ma = NULL; - /* error checking */ - if (ELEM(NULL, ts, ts->gp_brushes.first)) { - return NULL; + if ((brush != NULL) && (brush->gpencil_settings != NULL) && + (brush->gpencil_settings->material != NULL)) + { + ma = brush->gpencil_settings->material; } - /* loop over brushes until found (assume only one active) */ - for (brush = ts->gp_brushes.first; brush; brush = brush->next) { - if (brush->flag & GP_BRUSH_ACTIVE) { - return brush; + return ma; +} + +/* Get active color, and add all default settings if we don't find anything */ +Material *BKE_gpencil_material_ensure(Main *bmain, Object *ob) +{ + Material *ma = NULL; + + /* sanity checks */ + if (ELEM(NULL, bmain, ob)) + return NULL; + + ma = give_current_material(ob, ob->actcol); + if (ma == NULL) { + if (ob->totcol == 0) { + BKE_object_material_slot_add(bmain, ob); } + ma = BKE_material_add_gpencil(bmain, DATA_("Material")); + assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING); + } + else if (ma->gp_style == NULL) { + BKE_material_init_gpencil_settings(ma); } - /* no active brush found */ - return NULL; + return ma; } -/* set the active gp-brush */ -void BKE_gpencil_brush_setactive(ToolSettings *ts, bGPDbrush *active) +/* ************************************************** */ +/* GP Object - Boundbox Support */ + +/** + * Get min/max coordinate bounds for single stroke + * \return Returns whether we found any selected points + */ +bool BKE_gpencil_stroke_minmax( + const bGPDstroke *gps, const bool use_select, + float r_min[3], float r_max[3]) { - bGPDbrush *brush; + const bGPDspoint *pt; + int i; + bool changed = false; - /* error checking */ - if (ELEM(NULL, ts, ts->gp_brushes.first, active)) { - return; - } + if (ELEM(NULL, gps, r_min, r_max)) + return false; - /* loop over brushes deactivating all */ - for (brush = ts->gp_brushes.first; brush; brush = brush->next) { - brush->flag &= ~GP_BRUSH_ACTIVE; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) { + minmax_v3v3_v3(r_min, r_max, &pt->x); + changed = true; + } } - - /* set as active one */ - active->flag |= GP_BRUSH_ACTIVE; + return changed; } -/* delete the active gp-brush */ -void BKE_gpencil_brush_delete(ToolSettings *ts, bGPDbrush *brush) +/* get min/max bounds of all strokes in GP datablock */ +static void gpencil_minmax(bGPdata *gpd, float r_min[3], float r_max[3]) { - /* error checking */ - if (ELEM(NULL, ts, brush)) { + INIT_MINMAX(r_min, r_max); + + if (gpd == NULL) return; - } - /* free curves */ - if (brush->cur_sensitivity) { - curvemapping_free(brush->cur_sensitivity); - } - if (brush->cur_strength) { - curvemapping_free(brush->cur_strength); + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + bGPDframe *gpf = gpl->actframe; + + if (gpf != NULL) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); + } + } } - if (brush->cur_jitter) { - curvemapping_free(brush->cur_jitter); +} + +/* compute center of bounding box */ +void BKE_gpencil_centroid_3D(bGPdata *gpd, float r_centroid[3]) +{ + float min[3], max[3], tot[3]; + + gpencil_minmax(gpd, min, max); + + add_v3_v3v3(tot, min, max); + mul_v3_v3fl(r_centroid, tot, 0.5f); +} + + +/* create bounding box values */ +static void boundbox_gpencil(Object *ob) +{ + BoundBox *bb; + bGPdata *gpd; + float min[3], max[3]; + + if (ob->bb == NULL) { + ob->bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); } - /* free */ - BLI_freelinkN(&ts->gp_brushes, brush); + bb = ob->bb; + gpd = ob->data; + + gpencil_minmax(gpd, min, max); + BKE_boundbox_init_from_minmax(bb, min, max); + + bb->flag &= ~BOUNDBOX_DIRTY; } -/* ************************************************** */ -/* get the active gp-palette for editing */ -bGPDpalette *BKE_gpencil_palette_getactive(bGPdata *gpd) +/* get bounding box */ +BoundBox *BKE_gpencil_boundbox_get(Object *ob) { - bGPDpalette *palette; + bGPdata *gpd; - /* error checking */ - if (ELEM(NULL, gpd, gpd->palettes.first)) { + if (ELEM(NULL, ob, ob->data)) return NULL; - } - /* loop over palettes until found (assume only one active) */ - for (palette = gpd->palettes.first; palette; palette = palette->next) { - if (palette->flag & PL_PALETTE_ACTIVE) - return palette; + gpd = ob->data; + if ((ob->bb) && ((ob->bb->flag & BOUNDBOX_DIRTY) == 0) && + ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0)) + { + return ob->bb; } - /* no active palette found */ - return NULL; + boundbox_gpencil(ob); + + return ob->bb; } -/* set the active gp-palette */ -void BKE_gpencil_palette_setactive(bGPdata *gpd, bGPDpalette *active) -{ - bGPDpalette *palette; +/* ************************************************** */ +/* Apply Transforms */ - /* error checking */ - if (ELEM(NULL, gpd, gpd->palettes.first, active)) { +void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) +{ + if (gpd == NULL) return; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* FIXME: For now, we just skip parented layers. + * Otherwise, we have to update each frame to find + * the current parent position/effects. + */ + if (gpl->parent) { + continue; + } + + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *pt; + int i; + + for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) { + mul_m4_v3(mat, &pt->x); + } + + /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */ + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + } + } } - /* loop over palettes deactivating all */ - for (palette = gpd->palettes.first; palette; palette = palette->next) { - palette->flag &= ~PL_PALETTE_ACTIVE; +} + +/* ************************************************** */ +/* GP Object - Vertex Groups */ + +/* remove a vertex group */ +void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *defgroup) +{ + bGPdata *gpd = ob->data; + MDeformVert *dvert = NULL; + MDeformWeight *gpw = NULL; + const int def_nr = BLI_findindex(&ob->defbase, defgroup); + + /* Remove points data */ + if (gpd) { + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + for (int i = 0; i < gps->totpoints; i++) { + dvert = &gps->dvert[i]; + for (int i2 = 0; i2 < dvert->totweight; i2++) { + gpw = &dvert->dw[i2]; + if (gpw->def_nr == def_nr) { + BKE_gpencil_vgroup_remove_point_weight(dvert, def_nr); + } + /* if index is greater, must be moved one back */ + if (gpw->def_nr > def_nr) { + gpw->def_nr--; + } + } + } + } + } + } } - /* set as active one */ - active->flag |= PL_PALETTE_ACTIVE; - /* force color recalc */ - BKE_gpencil_palette_change_strokes(gpd); + /* Remove the group */ + BLI_freelinkN(&ob->defbase, defgroup); } -/* delete the active gp-palette */ -void BKE_gpencil_palette_delete(bGPdata *gpd, bGPDpalette *palette) +/* add a new weight */ +MDeformWeight *BKE_gpencil_vgroup_add_point_weight(MDeformVert *dvert, int index, float weight) { - /* error checking */ - if (ELEM(NULL, gpd, palette)) { - return; + MDeformWeight *new_gpw = NULL; + MDeformWeight *tmp_gpw; + + /* need to verify if was used before to update */ + for (int i = 0; i < dvert->totweight; i++) { + tmp_gpw = &dvert->dw[i]; + if (tmp_gpw->def_nr == index) { + tmp_gpw->weight = weight; + return tmp_gpw; + } + } + + dvert->totweight++; + if (dvert->totweight == 1) { + dvert->dw = MEM_callocN(sizeof(MDeformWeight), "gp_weight"); + } + else { + dvert->dw = MEM_reallocN(dvert->dw, sizeof(MDeformWeight) * dvert->totweight); } + new_gpw = &dvert->dw[dvert->totweight - 1]; + new_gpw->def_nr = index; + new_gpw->weight = weight; - /* free colors */ - free_gpencil_colors(palette); - BLI_freelinkN(&gpd->palettes, palette); - /* force color recalc */ - BKE_gpencil_palette_change_strokes(gpd); + return new_gpw; } -/* Set all strokes to recalc the palette color */ -void BKE_gpencil_palette_change_strokes(bGPdata *gpd) +/* return the weight if use index or -1*/ +float BKE_gpencil_vgroup_use_index(MDeformVert *dvert, int index) { - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps; + MDeformWeight *gpw; + for (int i = 0; i < dvert->totweight; i++) { + gpw = &dvert->dw[i]; + if (gpw->def_nr == index) { + return gpw->weight; + } + } + return -1.0f; +} - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (gps = gpf->strokes.first; gps; gps = gps->next) { - gps->flag |= GP_STROKE_RECALC_COLOR; - } +/* add a new weight */ +bool BKE_gpencil_vgroup_remove_point_weight(MDeformVert *dvert, int index) +{ + int e = 0; + + if (BKE_gpencil_vgroup_use_index(dvert, index) < 0.0f) { + return false; + } + + /* if the array get empty, exit */ + if (dvert->totweight == 1) { + dvert->totweight = 0; + MEM_SAFE_FREE(dvert->dw); + return true; + } + + /* realloc weights */ + MDeformWeight *tmp = MEM_dupallocN(dvert->dw); + MEM_SAFE_FREE(dvert->dw); + dvert->dw = MEM_callocN(sizeof(MDeformWeight) * dvert->totweight - 1, "gp_weights"); + + for (int x = 0; x < dvert->totweight; x++) { + MDeformWeight *gpw = &tmp[e]; + MDeformWeight *final_gpw = &dvert->dw[e]; + if (gpw->def_nr != index) { + final_gpw->def_nr = gpw->def_nr; + final_gpw->weight = gpw->weight; + e++; } } + MEM_SAFE_FREE(tmp); + dvert->totweight--; + + return true; } -/* get the active gp-palettecolor for editing */ -bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(bGPDpalette *palette) +/* ************************************************** */ + +/** + * Apply smooth to stroke point + * \param gps Stroke to smooth + * \param i Point index + * \param inf Amount of smoothing to apply + */ +bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf) { - bGPDpalettecolor *palcolor; + bGPDspoint *pt = &gps->points[i]; + // float pressure = 0.0f; + float sco[3] = { 0.0f }; - /* error checking */ - if (ELEM(NULL, palette, palette->colors.first)) { - return NULL; + /* Do nothing if not enough points to smooth out */ + if (gps->totpoints <= 2) { + return false; + } + + /* Only affect endpoints by a fraction of the normal strength, + * to prevent the stroke from shrinking too much + */ + if ((i == 0) || (i == gps->totpoints - 1)) { + inf *= 0.1f; } - /* loop over colors until found (assume only one active) */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - if (palcolor->flag & PC_COLOR_ACTIVE) { - return palcolor; + /* Compute smoothed coordinate by taking the ones nearby */ + /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */ + { + // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total) + const int steps = 2; + const float average_fac = 1.0f / (float)(steps * 2 + 1); + int step; + + /* add the point itself */ + madd_v3_v3fl(sco, &pt->x, average_fac); + + /* n-steps before/after current point */ + // XXX: review how the endpoints are treated by this algorithm + // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight + for (step = 1; step <= steps; step++) { + bGPDspoint *pt1, *pt2; + int before = i - step; + int after = i + step; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pt1 = &gps->points[before]; + pt2 = &gps->points[after]; + + /* add both these points to the average-sum (s += p[i]/n) */ + madd_v3_v3fl(sco, &pt1->x, average_fac); + madd_v3_v3fl(sco, &pt2->x, average_fac); + } } - /* no active color found */ - return NULL; + /* Based on influence factor, blend between original and optimal smoothed coordinate */ + interp_v3_v3v3(&pt->x, &pt->x, sco, inf); + + return true; } -/* get the gp-palettecolor looking for name */ -bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(bGPDpalette *palette, char *name) + +/** + * Apply smooth for strength to stroke point */ +bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence) { - /* error checking */ - if (ELEM(NULL, palette, name)) { - return NULL; + bGPDspoint *ptb = &gps->points[point_index]; + + /* Do nothing if not enough points */ + if (gps->totpoints <= 2) { + return false; } - return BLI_findstring(&palette->colors, name, offsetof(bGPDpalettecolor, info)); + /* Compute theoretical optimal value using distances */ + bGPDspoint *pta, *ptc; + int before = point_index - 1; + int after = point_index + 1; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pta = &gps->points[before]; + ptc = &gps->points[after]; + + /* the optimal value is the corresponding to the interpolation of the strength + * at the distance of point b + */ + const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); + const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength; + + /* Based on influence factor, blend between original and optimal */ + ptb->strength = (1.0f - influence) * ptb->strength + influence * optimal; + + return true; } -/* Change color name in all strokes */ -void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char *newname) +/** + * Apply smooth for thickness to stroke point (use pressure) */ +bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence) { - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps; + bGPDspoint *ptb = &gps->points[point_index]; - /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */ - if (ELEM(NULL, gpd, oldname, newname)) - return; + /* Do nothing if not enough points */ + if (gps->totpoints <= 2) { + return false; + } - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (gps = gpf->strokes.first; gps; gps = gps->next) { - if (STREQ(gps->colorname, oldname)) { - BLI_strncpy(gps->colorname, newname, sizeof(gps->colorname)); - } + /* Compute theoretical optimal value using distances */ + bGPDspoint *pta, *ptc; + int before = point_index - 1; + int after = point_index + 1; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pta = &gps->points[before]; + ptc = &gps->points[after]; + + /* the optimal value is the corresponding to the interpolation of the pressure + * at the distance of point b + */ + float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); + float optimal = interpf(ptc->pressure, pta->pressure, fac); + + /* Based on influence factor, blend between original and optimal */ + ptb->pressure = interpf(optimal, ptb->pressure, influence); + + return true; +} + +/** +* Apply smooth for UV rotation to stroke point (use pressure) */ +bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence) +{ + bGPDspoint *ptb = &gps->points[point_index]; + + /* Do nothing if not enough points */ + if (gps->totpoints <= 2) { + return false; + } + + /* Compute theoretical optimal value */ + bGPDspoint *pta, *ptc; + int before = point_index - 1; + int after = point_index + 1; + + CLAMP_MIN(before, 0); + CLAMP_MAX(after, gps->totpoints - 1); + + pta = &gps->points[before]; + ptc = &gps->points[after]; + + /* the optimal value is the corresponding to the interpolation of the pressure + * at the distance of point b + */ + float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); + float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac); + + /* Based on influence factor, blend between original and optimal */ + ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence); + CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2); + + return true; +} + +/** + * Get range of selected frames in layer. + * Always the active frame is considered as selected, so if no more selected the range + * will be equal to the current active frame. + * \param gpl Layer + * \param r_initframe Number of first selected frame + * \param r_endframe Number of last selected frame + */ +void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_endframe) +{ + *r_initframe = gpl->actframe->framenum; + *r_endframe = gpl->actframe->framenum; + + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if (gpf->flag & GP_FRAME_SELECT) { + if (gpf->framenum < *r_initframe) { + *r_initframe = gpf->framenum; + } + if (gpf->framenum > *r_endframe) { + *r_endframe = gpf->framenum; } } } +} + +/** + * Get Falloff factor base on frame range + * \param gpf Frame + * \param actnum Number of active frame in layer + * \param f_init Number of first selected frame + * \param f_end Number of last selected frame + * \param cur_falloff Curve with falloff factors + */ +float BKE_gpencil_multiframe_falloff_calc(bGPDframe *gpf, int actnum, int f_init, int f_end, CurveMapping *cur_falloff) +{ + float fnum = 0.5f; /* default mid curve */ + float value; + + /* frames to the right of the active frame */ + if (gpf->framenum < actnum) { + fnum = (float)(gpf->framenum - f_init) / (actnum - f_init); + fnum *= 0.5f; + value = curvemapping_evaluateF(cur_falloff, 0, fnum); + } + /* frames to the left of the active frame */ + else if (gpf->framenum > actnum) { + fnum = (float)(gpf->framenum - actnum) / (f_end - actnum); + fnum *= 0.5f; + value = curvemapping_evaluateF(cur_falloff, 0, fnum + 0.5f); + } + else { + value = 1.0f; + } + return value; } -/* Delete all strokes of the color */ -void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name) +/* remove strokes using a material */ +void BKE_gpencil_material_index_remove(bGPdata *gpd, int index) { - bGPDlayer *gpl; - bGPDframe *gpf; bGPDstroke *gps, *gpsn; - /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */ - if (ELEM(NULL, gpd, name)) - return; - - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (gps = gpf->strokes.first; gps; gps = gpsn) { - gpsn = gps->next; - - if (STREQ(gps->colorname, name)) { - if (gps->points) MEM_freeN(gps->points); - if (gps->triangles) MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + if (gps->mat_nr == index) { + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + if (gps->triangles) MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + } + else { + /* reassign strokes */ + if (gps->mat_nr > index) { + gps->mat_nr--; + } + } } } } - } - } -/* set the active gp-palettecolor */ -void BKE_gpencil_palettecolor_setactive(bGPDpalette *palette, bGPDpalettecolor *active) +void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len) { - bGPDpalettecolor *palcolor; - - /* error checking */ - if (ELEM(NULL, palette, palette->colors.first, active)) { - return; + const short remap_len_short = (short)remap_len; + +#define MAT_NR_REMAP(n) \ + if (n < remap_len_short) { \ + BLI_assert(n >= 0 && remap[n] < remap_len_short); \ + n = remap[n]; \ + } ((void)0) + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* reassign strokes */ + MAT_NR_REMAP(gps->mat_nr); + } + } } - /* loop over colors deactivating all */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag &= ~PC_COLOR_ACTIVE; - } +#undef MAT_NR_REMAP - /* set as active one */ - active->flag |= PC_COLOR_ACTIVE; } -/* delete the active gp-palettecolor */ -void BKE_gpencil_palettecolor_delete(bGPDpalette *palette, bGPDpalettecolor *palcolor) +/* statistics functions */ +void BKE_gpencil_stats_update(bGPdata *gpd) { - /* error checking */ - if (ELEM(NULL, palette, palcolor)) { - return; + gpd->totlayer = 0; + gpd->totframe = 0; + gpd->totstroke = 0; + gpd->totpoint = 0; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + gpd->totlayer++; + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + gpd->totframe++; + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + gpd->totstroke++; + gpd->totpoint += gps->totpoints; + } + } } - /* free */ - BLI_freelinkN(&palette->colors, palcolor); } diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c new file mode 100644 index 00000000000..2ba738902a0 --- /dev/null +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -0,0 +1,679 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/gpencil_modifier.c + * \ingroup bke + */ + + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_string_utils.h" + +#include "BLT_translation.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_gpencil.h" +#include "BKE_lattice.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_object.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "MOD_gpencil_modifiertypes.h" + +static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL }; + +/* *************************************************** */ +/* Geometry Utilities */ + +/* calculate stroke normal using some points */ +void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3]) +{ + if (gps->totpoints < 3) { + zero_v3(r_normal); + return; + } + + bGPDspoint *points = gps->points; + int totpoints = gps->totpoints; + + const bGPDspoint *pt0 = &points[0]; + const bGPDspoint *pt1 = &points[1]; + const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; + + float vec1[3]; + float vec2[3]; + + /* initial vector (p0 -> p1) */ + sub_v3_v3v3(vec1, &pt1->x, &pt0->x); + + /* point vector at 3/4 */ + sub_v3_v3v3(vec2, &pt3->x, &pt0->x); + + /* vector orthogonal to polygon plane */ + cross_v3_v3v3(r_normal, vec1, vec2); + + /* Normalize vector */ + normalize_v3(r_normal); +} + +/* Get points of stroke always flat to view not affected by camera view or view position */ +static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d) +{ + const bGPDspoint *pt0 = &points[0]; + const bGPDspoint *pt1 = &points[1]; + const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; + + float locx[3]; + float locy[3]; + float loc3[3]; + float normal[3]; + + /* local X axis (p0 -> p1) */ + sub_v3_v3v3(locx, &pt1->x, &pt0->x); + + /* point vector at 3/4 */ + sub_v3_v3v3(loc3, &pt3->x, &pt0->x); + + /* vector orthogonal to polygon plane */ + cross_v3_v3v3(normal, locx, loc3); + + /* local Y axis (cross to normal/x axis) */ + cross_v3_v3v3(locy, normal, locx); + + /* Normalize vectors */ + normalize_v3(locx); + normalize_v3(locy); + + /* Get all points in local space */ + for (int i = 0; i < totpoints; i++) { + const bGPDspoint *pt = &points[i]; + float loc[3]; + + /* Get local space using first point as origin */ + sub_v3_v3v3(loc, &pt->x, &pt0->x); + + vec2f *point = &points2d[i]; + point->x = dot_v3v3(loc, locx); + point->y = dot_v3v3(loc, locy); + } + +} + +/* Stroke Simplify ------------------------------------- */ + +/* Reduce a series of points to a simplified version, but + * maintains the general shape of the series + * + * Ramer - Douglas - Peucker algorithm + * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm + */ +static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon) +{ + vec2f *old_points2d = points2d; + int totpoints = gps->totpoints; + char *marked = NULL; + char work; + + int start = 1; + int end = gps->totpoints - 2; + + marked = MEM_callocN(totpoints, "GP marked array"); + marked[start] = 1; + marked[end] = 1; + + work = 1; + int totmarked = 0; + /* while still reducing */ + while (work) { + int ls, le; + work = 0; + + ls = start; + le = start + 1; + + /* while not over interval */ + while (ls < end) { + int max_i = 0; + float v1[2]; + /* divided to get more control */ + float max_dist = epsilon / 10.0f; + + /* find the next marked point */ + while (marked[le] == 0) { + le++; + } + + /* perpendicular vector to ls-le */ + v1[1] = old_points2d[le].x - old_points2d[ls].x; + v1[0] = old_points2d[ls].y - old_points2d[le].y; + + for (int i = ls + 1; i < le; i++) { + float mul; + float dist; + float v2[2]; + + v2[0] = old_points2d[i].x - old_points2d[ls].x; + v2[1] = old_points2d[i].y - old_points2d[ls].y; + + if (v2[0] == 0 && v2[1] == 0) { + continue; + } + + mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]); + + dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]); + + if (dist > max_dist) { + max_dist = dist; + max_i = i; + } + } + + if (max_i != 0) { + work = 1; + marked[max_i] = 1; + totmarked++; + } + + ls = le; + le = ls + 1; + } + } + + /* adding points marked */ + bGPDspoint *old_points = MEM_dupallocN(gps->points); + MDeformVert *old_dvert = MEM_dupallocN(gps->dvert); + + /* resize gps */ + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + + int j = 0; + for (int i = 0; i < totpoints; i++) { + bGPDspoint *pt_src = &old_points[i]; + bGPDspoint *pt = &gps->points[j]; + + MDeformVert *dvert_src = &old_dvert[i]; + MDeformVert *dvert = &gps->dvert[j]; + + if ((marked[i]) || (i == 0) || (i == totpoints - 1)) { + memcpy(pt, pt_src, sizeof(bGPDspoint)); + memcpy(dvert, dvert_src, sizeof(MDeformVert)); + j++; + } + else { + BKE_gpencil_free_point_weights(dvert_src); + } + } + + gps->totpoints = j; + + MEM_SAFE_FREE(old_points); + MEM_SAFE_FREE(old_dvert); + MEM_SAFE_FREE(marked); +} + +/* Simplify stroke using Ramer-Douglas-Peucker algorithm */ +void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor) +{ + /* first create temp data and convert points to 2D */ + vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points"); + + gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d); + + gpencil_rdp_stroke(gps, points2d, factor); + + MEM_SAFE_FREE(points2d); +} + +/* Simplify alternate vertex of stroke except extrems */ +void BKE_gpencil_simplify_fixed(bGPDstroke *gps) +{ + if (gps->totpoints < 5) { + return; + } + + /* save points */ + bGPDspoint *old_points = MEM_dupallocN(gps->points); + MDeformVert *old_dvert = MEM_dupallocN(gps->dvert); + + /* resize gps */ + int newtot = (gps->totpoints - 2) / 2; + if (((gps->totpoints - 2) % 2) > 0) { + newtot++; + } + newtot += 2; + + gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot); + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + + int j = 0; + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt_src = &old_points[i]; + bGPDspoint *pt = &gps->points[j]; + + MDeformVert *dvert_src = &old_dvert[i]; + MDeformVert *dvert = &gps->dvert[j]; + + if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) { + memcpy(pt, pt_src, sizeof(bGPDspoint)); + memcpy(dvert, dvert_src, sizeof(MDeformVert)); + j++; + } + else { + BKE_gpencil_free_point_weights(dvert_src); + } + } + + gps->totpoints = j; + + MEM_SAFE_FREE(old_points); + MEM_SAFE_FREE(old_dvert); +} + +/* *************************************************** */ +/* Modifier Utilities */ + +/* Lattice Modifier ---------------------------------- */ +/* Usually, evaluation of the lattice modifier is self-contained. + * However, since GP's modifiers operate on a per-stroke basis, + * we need to these two extra functions that called before/after + * each loop over all the geometry being evaluated. + */ + +/* init lattice deform data */ +void BKE_gpencil_lattice_init(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (md->type == eGpencilModifierType_Lattice) { + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + Object *latob = NULL; + + latob = mmd->object; + if ((!latob) || (latob->type != OB_LATTICE)) { + return; + } + if (mmd->cache_data) { + end_latt_deform((struct LatticeDeformData *)mmd->cache_data); + } + + /* init deform data */ + mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob); + } + } +} + +/* clear lattice deform data */ +void BKE_gpencil_lattice_clear(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (md->type == eGpencilModifierType_Lattice) { + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + if ((mmd) && (mmd->cache_data)) { + end_latt_deform((struct LatticeDeformData *)mmd->cache_data); + mmd->cache_data = NULL; + } + } + } +} + +/* *************************************************** */ +/* Modifier Methods - Evaluation Loops, etc. */ + +/* check if exist geometry modifiers */ +bool BKE_gpencil_has_geometry_modifiers(Object *ob) +{ + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti && mti->generateStrokes) { + return true; + } + } + return false; +} + +/* apply stroke modifiers */ +void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render) +{ + GpencilModifierData *md; + bGPdata *gpd = ob->data; + const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); + + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) + { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (GPENCIL_MODIFIER_EDIT(md, is_edit)) { + continue; + } + + if (mti && mti->deformStroke) { + mti->deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +/* apply stroke geometry modifiers */ +void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render) +{ + GpencilModifierData *md; + bGPdata *gpd = ob->data; + const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); + + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) + { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (GPENCIL_MODIFIER_EDIT(md, is_edit)) { + continue; + } + + if (mti->generateStrokes) { + mti->generateStrokes(md, depsgraph, ob, gpl, gpf); + } + } + } +} + +/* *************************************************** */ + +void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, + bGPdata *gpd) +{ + DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd); + int ctime = (int)DEG_get_ctime(depsgraph); + + /* update active frame */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV); + } + + /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()? + * This would be better than inventing our own logic for this stuff... + */ + + /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node) + * later when there's more happening here. For now, let's just keep this in here to avoid + * needing to have one more node slowing down evaluation... + */ + if (DEG_is_active(depsgraph)) { + bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id); + + /* sync "actframe" changes back to main-db too, + * so that editing tools work with copy-on-write + * when the current frame changes + */ + for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) { + gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV); + } + } +} + +void BKE_gpencil_modifier_init(void) +{ + /* Initialize modifier types */ + gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */ +} + +GpencilModifierData *BKE_gpencil_modifier_new(int type) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type); + GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name); + + /* note, this name must be made unique later */ + BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name)); + + md->type = type; + md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded; + md->flag = eGpencilModifierFlag_StaticOverride_Local; + + if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode) + md->mode |= eGpencilModifierMode_Editmode; + + if (mti->initData) mti->initData(md); + + return md; +} + +static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_min(id); + } +} + +void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL); + } + } + + if (mti->freeData) mti->freeData(md); + if (md->error) MEM_freeN(md->error); + + MEM_freeN(md); +} + +void BKE_gpencil_modifier_free(GpencilModifierData *md) +{ + BKE_gpencil_modifier_free_ex(md, 0); +} + +/* check unique name */ +bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd) +{ + if (modifiers && gmd) { + const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type); + return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name)); + } + return false; +} + +bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + return mti->dependsOnTime && mti->dependsOnTime(md); +} + +const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type) +{ + /* type unsigned, no need to check < 0 */ + if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') { + return modifier_gpencil_types[type]; + } + else { + return NULL; + } +} + +void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type); + + /* md_dst may have alredy be fully initialized with some extra allocated data, + * we need to free it now to avoid memleak. */ + if (mti->freeData) { + mti->freeData(md_dst); + } + + const size_t data_size = sizeof(GpencilModifierData); + const char *md_src_data = ((const char *)md_src) + data_size; + char *md_dst_data = ((char *)md_dst) + data_size; + BLI_assert(data_size <= (size_t)mti->struct_size); + memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size); +} + +static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(id); + } +} + +void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + target->mode = md->mode; + target->flag = md->flag; + + if (mti->copyData) { + mti->copyData(md, target); + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (mti->foreachIDLink) { + mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL); + } + else if (mti->foreachObjectLink) { + mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL); + } + } +} + +void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_ex(md, target, 0); +} + +GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + + for (; md; md = md->next) + if (md->type == type) + break; + + return md; +} + +void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + + for (; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData); + else if (mti->foreachObjectLink) { + /* each Object can masquerade as an ID, so this should be OK */ + GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk; + mti->foreachObjectLink(md, ob, fp, userData); + } + } +} + +void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + + for (; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti->foreachTexLink) + mti->foreachTexLink(md, ob, walk, userData); + } +} + +GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name) +{ + return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name)); +} + +/* helper function for per-instance positioning */ +void BKE_gpencil_instance_modifier_instance_tfm(InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4]) +{ + float offset[3], rot[3], scale[3]; + int ri = mmd->rnd[0]; + float factor; + + offset[0] = mmd->offset[0] * elem_idx[0]; + offset[1] = mmd->offset[1] * elem_idx[1]; + offset[2] = mmd->offset[2] * elem_idx[2]; + + /* rotation */ + if (mmd->flag & GP_INSTANCE_RANDOM_ROT) { + factor = mmd->rnd_rot * mmd->rnd[ri]; + mul_v3_v3fl(rot, mmd->rot, factor); + add_v3_v3(rot, mmd->rot); + } + else { + copy_v3_v3(rot, mmd->rot); + } + + /* scale */ + if (mmd->flag & GP_INSTANCE_RANDOM_SIZE) { + factor = mmd->rnd_size * mmd->rnd[ri]; + mul_v3_v3fl(scale, mmd->scale, factor); + add_v3_v3(scale, mmd->scale); + } + else { + copy_v3_v3(scale, mmd->scale); + } + + /* advance random index */ + mmd->rnd[0]++; + if (mmd->rnd[0] > 19) { + mmd->rnd[0] = 1; + } + + /* calculate matrix */ + loc_eul_size_to_mat4(r_mat, offset, rot, scale); +} diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 1c2575dfa52..3a4bf53e22d 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -37,6 +37,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_brush_types.h" +#include "DNA_gpencil_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" @@ -45,7 +47,6 @@ #include "DNA_screen_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" -#include "DNA_brush_types.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -127,6 +128,9 @@ static void icon_free_data(int icon_id, Icon *icon) else if (icon->obj_type == ICON_DATA_PREVIEW) { ((PreviewImage *)(icon->obj))->icon_id = 0; } + else if (icon->obj_type == ICON_DATA_GPLAYER) { + ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0; + } else if (icon->obj_type == ICON_DATA_GEOM) { ((struct Icon_Geom *)(icon->obj))->icon_id = 0; } @@ -598,6 +602,44 @@ int BKE_icon_id_ensure(struct ID *id) return icon_id_ensure_create_icon(id); } + +static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl) +{ + BLI_assert(BLI_thread_is_main()); + + /* NOTE: The color previews for GP Layers don't really need + * to be "rendered" to image per se (as it will just be a plain + * colored rectangle), we need to define icon data here so that + * we can store a pointer to the layer data in icon->obj. + */ + Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl); + icon->flag = ICON_FLAG_MANAGED; + + return gpl->runtime.icon_id; +} + +int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl) +{ + /* Never handle icons in non-main thread! */ + BLI_assert(BLI_thread_is_main()); + + if (!gpl || G.background) { + return 0; + } + + if (gpl->runtime.icon_id) + return gpl->runtime.icon_id; + + gpl->runtime.icon_id = get_next_free_id(); + + if (!gpl->runtime.icon_id) { + printf("%s: Internal error - not enough IDs\n", __func__); + return 0; + } + + return icon_gplayer_color_ensure_create_icon(gpl); +} + /** * Return icon id of given preview, or create new icon if not found. */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 351214ed72b..1d70d9db1e9 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1073,6 +1073,7 @@ int set_listbasepointers(Main *main, ListBase **lb) lb[INDEX_ID_IP] = &(main->ipo); lb[INDEX_ID_AC] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */ lb[INDEX_ID_KE] = &(main->key); + lb[INDEX_ID_PAL] = &(main->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */ lb[INDEX_ID_GD] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */ lb[INDEX_ID_NT] = &(main->nodetree); lb[INDEX_ID_IM] = &(main->image); diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 93fdd3349bf..473dd787a69 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -417,7 +417,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call SEQ_END } - CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) { CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER); @@ -478,6 +477,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call if (toolsett->uvsculpt) { library_foreach_paint(&data, &toolsett->uvsculpt->paint); } + if (toolsett->gp_paint) { + library_foreach_paint(&data, &toolsett->gp_paint->paint); + } } if (scene->rigidbody_world) { @@ -641,6 +643,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call if (material->texpaintslot != NULL) { CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP); } + if (material->gp_style != NULL) { + CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER); + CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER); + } break; } @@ -758,6 +764,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP); CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP); CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER); + if (brush->gpencil_settings) { + CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER); + } library_foreach_mtex(&data, &brush->mtex); library_foreach_mtex(&data, &brush->mask_mtex); break; @@ -941,10 +950,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call case ID_GD: { bGPdata *gpencil = (bGPdata *) id; + /* materials */ + for (i = 0; i < gpencil->totcol; i++) { + CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER); + } - for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) { - CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP); + for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) { + CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP); } + break; } @@ -1072,7 +1086,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) return true; #endif case ID_BR: - return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE); + return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA); case ID_PA: return ELEM(id_type_used, ID_OB, ID_GR, ID_TE); case ID_MC: @@ -1083,6 +1097,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) return (ELEM(id_type_used, ID_TE, ID_OB)); case ID_LP: return ELEM(id_type_used, ID_IM); + case ID_GD: + return ELEM(id_type_used, ID_MA); case ID_WS: return ELEM(id_type_used, ID_SCR, ID_SCE); case ID_IM: @@ -1091,7 +1107,6 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) case ID_SO: case ID_AR: case ID_AC: - case ID_GD: case ID_WM: case ID_PAL: case ID_PC: diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 28d75811185..03ec26c07d0 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -43,6 +43,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_customdata_types.h" +#include "DNA_gpencil_types.h" #include "DNA_ID.h" #include "DNA_meta_types.h" #include "DNA_node_types.h" @@ -58,6 +59,7 @@ #include "BKE_animsys.h" #include "BKE_displist.h" #include "BKE_global.h" +#include "BKE_gpencil.h" #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_library.h" @@ -103,10 +105,30 @@ void BKE_material_free(Material *ma) MEM_SAFE_FREE(ma->texpaintslot); + MEM_SAFE_FREE(ma->gp_style); + BKE_icon_id_delete((ID *)ma); BKE_previewimg_free(&ma->preview); } +void BKE_material_init_gpencil_settings(Material *ma) +{ + if ((ma) && (ma->gp_style == NULL)) { + ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings"); + + MaterialGPencilStyle *gp_style = ma->gp_style; + /* set basic settings */ + gp_style->stroke_rgba[3] = 1.0f; + gp_style->pattern_gridsize = 0.1f; + gp_style->gradient_radius = 0.5f; + ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f); + ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f); + ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f); + gp_style->texture_opacity = 1.0f; + gp_style->texture_pixsize = 100.0f; + } +} + void BKE_material_init(Material *ma) { BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id)); @@ -124,6 +146,7 @@ void BKE_material_init(Material *ma) ma->preview = NULL; ma->alpha_threshold = 0.5f; + } Material *BKE_material_add(Main *bmain, const char *name) @@ -137,6 +160,19 @@ Material *BKE_material_add(Main *bmain, const char *name) return ma; } +Material *BKE_material_add_gpencil(Main *bmain, const char *name) +{ + Material *ma; + + ma = BKE_material_add(bmain, name); + + /* grease pencil settings */ + BKE_material_init_gpencil_settings(ma); + + return ma; +} + + /** * Only copy internal data of Material ID from source to already allocated/initialized destination. * You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs. @@ -164,6 +200,10 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot); } + if (ma_src->gp_style != NULL) { + ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style); + } + BLI_listbase_clear(&ma_dst->gpumaterial); /* TODO Duplicate Engine Settings and set runtime to NULL */ @@ -199,6 +239,7 @@ Material *BKE_material_localize(Material *ma) man->texpaintslot = NULL; man->preview = NULL; + /* man->gp_style = NULL; */ /* XXX: We probably don't want to clear here, or else we may get problems with COW later? */ BLI_listbase_clear(&man->gpumaterial); /* TODO Duplicate Engine Settings and set runtime to NULL */ @@ -218,6 +259,7 @@ Material ***give_matarar(Object *ob) Mesh *me; Curve *cu; MetaBall *mb; + bGPdata *gpd; if (ob->type == OB_MESH) { me = ob->data; @@ -231,6 +273,10 @@ Material ***give_matarar(Object *ob) mb = ob->data; return &(mb->mat); } + else if (ob->type == OB_GPENCIL) { + gpd = ob->data; + return &(gpd->mat); + } return NULL; } @@ -239,6 +285,7 @@ short *give_totcolp(Object *ob) Mesh *me; Curve *cu; MetaBall *mb; + bGPdata *gpd; if (ob->type == OB_MESH) { me = ob->data; @@ -252,6 +299,10 @@ short *give_totcolp(Object *ob) mb = ob->data; return &(mb->totcol); } + else if (ob->type == OB_GPENCIL) { + gpd = ob->data; + return &(gpd->totcol); + } return NULL; } @@ -286,6 +337,8 @@ short *give_totcolp_id(ID *id) return &(((Curve *)id)->totcol); case ID_MB: return &(((MetaBall *)id)->totcol); + case ID_GD: + return &(((bGPdata *)id)->totcol); default: break; } @@ -307,6 +360,9 @@ static void material_data_index_remove_id(ID *id, short index) case ID_MB: /* meta-elems don't have materials atm */ break; + case ID_GD: + BKE_gpencil_material_index_remove((bGPdata *)id, index); + break; default: break; } @@ -487,6 +543,21 @@ Material *give_current_material(Object *ob, short act) return ma; } +MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act) +{ + Material *ma = give_current_material(ob, act); + if (ma != NULL) { + if (ma->gp_style == NULL) { + BKE_material_init_gpencil_settings(ma); + } + + return ma->gp_style; + } + else { + return NULL; + } +} + Material *give_node_material(Material *ma) { if (ma && ma->use_nodes && ma->nodetree) { @@ -727,6 +798,9 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap) else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) { BKE_curve_material_remap(ob->data, remap, ob->totcol); } + if (ob->type == OB_GPENCIL) { + BKE_gpencil_material_remap(ob->data, remap, ob->totcol); + } else { /* add support for this object data! */ BLI_assert(matar == NULL); @@ -924,7 +998,7 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob) } /* check indices from mesh */ - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) { material_data_index_remove_id((ID *)ob->data, actcol - 1); if (ob->runtime.curve_cache) { BKE_displist_free(&ob->runtime.curve_cache->disp); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 21b5bb89f19..c88de006eba 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -41,6 +41,7 @@ #include "DNA_camera_types.h" #include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_group_types.h" #include "DNA_key_types.h" #include "DNA_lamp_types.h" @@ -53,6 +54,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_smoke_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" @@ -86,6 +88,7 @@ #include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_fcurve.h" +#include "BKE_gpencil_modifier.h" #include "BKE_icons.h" #include "BKE_key.h" #include "BKE_lamp.h" @@ -110,12 +113,14 @@ #include "BKE_rigidbody.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_shader_fx.h" #include "BKE_speaker.h" #include "BKE_softbody.h" #include "BKE_subsurf.h" #include "BKE_material.h" #include "BKE_camera.h" #include "BKE_image.h" +#include "BKE_gpencil.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -185,11 +190,15 @@ void BKE_object_free_curve_cache(Object *ob) void BKE_object_free_modifiers(Object *ob, const int flag) { ModifierData *md; + GpencilModifierData *gp_md; while ((md = BLI_pophead(&ob->modifiers))) { modifier_free_ex(md, flag); } + while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) { + BKE_gpencil_modifier_free_ex(gp_md, flag); + } /* particle modifiers were freed, so free the particlesystems as well */ BKE_object_free_particlesystems(ob); @@ -200,6 +209,15 @@ void BKE_object_free_modifiers(Object *ob, const int flag) BKE_object_free_derived_caches(ob); } +void BKE_object_free_shaderfx(Object *ob, const int flag) +{ + ShaderFxData *fx; + + while ((fx = BLI_pophead(&ob->shader_fx))) { + BKE_shaderfx_free_ex(fx, flag); + } +} + void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) { /* reset functionality */ @@ -222,6 +240,29 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd) } } +void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd) +{ + if (hmd->object == NULL) { + return; + } + /* reset functionality */ + bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget); + + if (hmd->subtarget[0] && pchan) { + float imat[4][4], mat[4][4]; + + /* calculate the world-space matrix for the pose-channel target first, then carry on as usual */ + mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat); + + invert_m4_m4(imat, mat); + mul_m4_m4m4(hmd->parentinv, imat, ob->obmat); + } + else { + invert_m4_m4(hmd->object->imat, hmd->object->obmat); + mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat); + } +} + bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type) { const ModifierTypeInfo *mti; @@ -428,6 +469,7 @@ void BKE_object_free(Object *ob) /* BKE__free shall never touch to ID->us. Never ever. */ BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT); + BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT); MEM_SAFE_FREE(ob->mat); MEM_SAFE_FREE(ob->matbits); @@ -653,6 +695,7 @@ static const char *get_obdata_defname(int type) case OB_ARMATURE: return DATA_("Armature"); case OB_SPEAKER: return DATA_("Speaker"); case OB_EMPTY: return DATA_("Empty"); + case OB_GPENCIL: return DATA_("GPencil"); default: printf("get_obdata_defname: Internal error, bad type: %d\n", type); return DATA_("Empty"); @@ -677,6 +720,7 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) case OB_ARMATURE: return BKE_armature_add(bmain, name); case OB_SPEAKER: return BKE_speaker_add(bmain, name); case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name); + case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name); case OB_EMPTY: return NULL; default: printf("%s: Internal error, bad type: %d\n", __func__, type); @@ -810,7 +854,7 @@ Object *BKE_object_add( /** * Add a new object, using another one as a reference * - * /param ob_src object to use to determine the collections of the new object. + * \param ob_src object to use to determine the collections of the new object. */ Object *BKE_object_add_from( Main *bmain, Scene *scene, ViewLayer *view_layer, @@ -828,6 +872,41 @@ Object *BKE_object_add_from( return ob; } +/** + * Add a new object, but assign the given datablock as the ob->data + * for the newly created object. + * + * \param data The datablock to assign as ob->data for the new object. + * This is assumed to be of the correct type. + * \param do_id_user If true, id_us_plus() will be called on data when + * assigning it to the object. + */ +Object *BKE_object_add_for_data( + Main *bmain, ViewLayer *view_layer, + int type, const char *name, ID *data, bool do_id_user) +{ + Object *ob; + Base *base; + LayerCollection *layer_collection; + + /* same as object_add_common, except we don't create new ob->data */ + ob = BKE_object_add_only_object(bmain, type, name); + ob->data = data; + if (do_id_user) id_us_plus(data); + + BKE_view_layer_base_deselect_all(view_layer); + DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + + layer_collection = BKE_layer_collection_get_active(view_layer); + BKE_collection_object_add(bmain, layer_collection->collection, ob); + + base = BKE_view_layer_base_find(view_layer, ob); + BKE_view_layer_base_select(view_layer, base); + + return ob; +} + + void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag) { SoftBody *sb = ob_src->soft; @@ -1153,6 +1232,8 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src) void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag) { ModifierData *md; + GpencilModifierData *gmd; + ShaderFxData *fx; /* Do not copy runtime data. */ BKE_object_runtime_reset(ob_dst); @@ -1179,6 +1260,24 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con BLI_addtail(&ob_dst->modifiers, nmd); } + BLI_listbase_clear(&ob_dst->greasepencil_modifiers); + + for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) { + GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type); + BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name)); + BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata); + BLI_addtail(&ob_dst->greasepencil_modifiers, nmd); + } + + BLI_listbase_clear(&ob_dst->shader_fx); + + for (fx = ob_src->shader_fx.first; fx; fx = fx->next) { + ShaderFxData *nfx = BKE_shaderfx_new(fx->type); + BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name)); + BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata); + BLI_addtail(&ob_dst->shader_fx, nfx); + } + if (ob_src->pose) { copy_object_pose(ob_dst, ob_src, flag_subdata); /* backwards compat... non-armatures can get poses in older files? */ @@ -1210,6 +1309,10 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con BLI_listbase_clear((ListBase *)&ob_dst->drawdata); BLI_listbase_clear(&ob_dst->pc_ids); + /* grease pencil: clean derived data */ + if (ob_dst->type == OB_GPENCIL) + BKE_gpencil_free_derived_frames(ob_dst->data); + ob_dst->avs = ob_src->avs; ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath); @@ -1469,6 +1572,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size) ob->empty_drawsize *= size; break; } + case OB_GPENCIL: + { + ob->empty_drawsize *= size; + break; + } case OB_FONT: { Curve *cu = ob->data; @@ -2452,7 +2560,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us float size[3]; copy_v3_v3(size, ob->size); - if (ob->type == OB_EMPTY) { + if ((ob->type == OB_EMPTY) || (ob->type == OB_GPENCIL)) { mul_v3_fl(size, ob->empty_drawsize); } @@ -3694,6 +3802,88 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md) return false; } +bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md) +{ + if (BKE_gpencil_modifier_dependsOnTime(md)) { + return true; + } + + /* Check whether modifier is animated. */ + /* TODO (Aligorith): this should be handled as part of build_animdata() */ + if (ob->adt) { + AnimData *adt = ob->adt; + FCurve *fcu; + + char pattern[MAX_NAME + 32]; + BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name); + + /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */ + if (adt->action) { + for (fcu = (FCurve *)adt->action->curves.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + /* This here allows modifier properties to get driven and still update properly + * + */ + for (fcu = (FCurve *)adt->drivers.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + return false; +} + +bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx) +{ + if (BKE_shaderfx_dependsOnTime(fx)) { + return true; + } + + /* Check whether effect is animated. */ + /* TODO (Aligorith): this should be handled as part of build_animdata() */ + if (ob->adt) { + AnimData *adt = ob->adt; + FCurve *fcu; + + char pattern[MAX_NAME + 32]; + BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name); + + /* action - check for F-Curves with paths containing string[' */ + if (adt->action) { + for (fcu = (FCurve *)adt->action->curves.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + /* This here allows properties to get driven and still update properly + * + */ + for (fcu = (FCurve *)adt->drivers.first; + fcu != NULL; + fcu = (FCurve *)fcu->next) + { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + return true; + } + } + + return false; +} + /* set "ignore cache" flag for all caches on this object */ static void object_cacheIgnoreClear(Object *ob, int state) { diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 5c9e53aaa56..a6b0e57e55c 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -53,6 +53,7 @@ #include "BKE_object.h" #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_gpencil.h" /** \name Misc helpers * \{ */ @@ -402,12 +403,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg) */ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) { - if (BKE_object_is_in_editmode_vgroup(ob)) - object_defgroup_remove_edit_mode(ob, defgroup); - else - object_defgroup_remove_object_mode(ob, defgroup); + if ((ob) && (ob->type == OB_GPENCIL)) { + BKE_gpencil_vgroup_remove(ob, defgroup); + } + else { + if (BKE_object_is_in_editmode_vgroup(ob)) + object_defgroup_remove_edit_mode(ob, defgroup); + else + object_defgroup_remove_object_mode(ob, defgroup); - BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + } } /** diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 3e72de3909f..3641df26496 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -62,6 +62,7 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_scene.h" +#include "BKE_gpencil.h" #include "MEM_guardedalloc.h" @@ -324,6 +325,9 @@ void BKE_object_eval_uber_data(Depsgraph *depsgraph, case OB_MBALL: BKE_mball_batch_cache_dirty(ob->data, BKE_MBALL_BATCH_DIRTY_ALL); break; + case OB_GPENCIL: + BKE_gpencil_batch_cache_dirty(ob->data); + break; } } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 07aa21f44ff..cb26f7e9f3e 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -41,13 +41,19 @@ #include "DNA_scene_types.h" #include "DNA_brush_types.h" #include "DNA_space_types.h" +#include "DNA_gpencil_types.h" #include "DNA_workspace_types.h" #include "BLI_bitmap.h" +#include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_string_utils.h" #include "BLI_math_vector.h" #include "BLI_listbase.h" +#include "BLT_translation.h" + +#include "BKE_animsys.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_deform.h" @@ -55,6 +61,7 @@ #include "BKE_context.h" #include "BKE_crazyspace.h" #include "BKE_global.h" +#include "BKE_gpencil.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_library.h" @@ -151,6 +158,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode) return &ts->imapaint.paint; case ePaintSculptUV: return &ts->uvsculpt->paint; + case ePaintGpencil: + return &ts->gp_paint->paint; case ePaintInvalid: return NULL; default: @@ -176,6 +185,8 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) return &ts->wpaint->paint; case OB_MODE_TEXTURE_PAINT: return &ts->imapaint.paint; + case OB_MODE_GPENCIL_PAINT: + return &ts->gp_paint->paint; case OB_MODE_EDIT: if (ts->use_uv_sculpt) return &ts->uvsculpt->paint; @@ -430,13 +441,11 @@ PaletteColor *BKE_palette_color_add(Palette *palette) return color; } - bool BKE_palette_is_empty(const struct Palette *palette) { return BLI_listbase_is_empty(&palette->colors); } - /* are we in vertex paint or weight pain face select mode? */ bool BKE_paint_select_face_test(Object *ob) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index b50dc37af81..7085b515ec1 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -173,6 +173,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) ts->uvsculpt = MEM_dupallocN(ts->uvsculpt); BKE_paint_copy(&ts->uvsculpt->paint, &ts->uvsculpt->paint, flag); } + if (ts->gp_paint) { + ts->gp_paint = MEM_dupallocN(ts->gp_paint); + BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag); + } BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag); ts->imapaint.paintcursor = NULL; @@ -180,15 +184,10 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) ts->particle.scene = NULL; ts->particle.object = NULL; - /* duplicate Grease Pencil Drawing Brushes */ - BLI_listbase_clear(&ts->gp_brushes); - for (bGPDbrush *brush = toolsettings->gp_brushes.first; brush; brush = brush->next) { - bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); - BLI_addtail(&ts->gp_brushes, newbrush); - } - /* duplicate Grease Pencil interpolation curve */ ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); + /* duplicate Grease Pencil multiframe fallof */ + ts->gp_sculpt.cur_falloff = curvemapping_copy(ts->gp_sculpt.cur_falloff); return ts; } @@ -213,16 +212,20 @@ void BKE_toolsettings_free(ToolSettings *toolsettings) BKE_paint_free(&toolsettings->uvsculpt->paint); MEM_freeN(toolsettings->uvsculpt); } + if (toolsettings->gp_paint) { + BKE_paint_free(&toolsettings->gp_paint->paint); + MEM_freeN(toolsettings->gp_paint); + } BKE_paint_free(&toolsettings->imapaint.paint); - /* free Grease Pencil Drawing Brushes */ - BKE_gpencil_free_brushes(&toolsettings->gp_brushes); - BLI_freelistN(&toolsettings->gp_brushes); - /* free Grease Pencil interpolation curve */ if (toolsettings->gp_interpolate.custom_ipo) { curvemapping_free(toolsettings->gp_interpolate.custom_ipo); } + /* free Grease Pencil multiframe falloff curve */ + if (toolsettings->gp_sculpt.cur_falloff) { + curvemapping_free(toolsettings->gp_sculpt.cur_falloff); + } MEM_freeN(toolsettings); } @@ -428,9 +431,9 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) } /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations - * are done outside of blenkernel with ED_objects_single_users! */ + * are done outside of blenkernel with ED_object_single_users! */ - /* camera */ + /* camera */ if (ELEM(type, SCE_COPY_LINK_DATA, SCE_COPY_FULL)) { ID_NEW_REMAP(sce_copy->camera); } @@ -683,6 +686,19 @@ void BKE_scene_init(Scene *sce) sce->toolsettings->imapaint.normal_angle = 80; sce->toolsettings->imapaint.seam_bleed = 2; + /* alloc grease pencil drawing brushes */ + sce->toolsettings->gp_paint = MEM_callocN(sizeof(GpPaint), "GpPaint"); + + /* grease pencil multiframe falloff curve */ + sce->toolsettings->gp_sculpt.cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + CurveMapping *gp_falloff_curve = sce->toolsettings->gp_sculpt.cur_falloff; + curvemapping_set_defaults(gp_falloff_curve, 1, 0.0f, 0.0f, 1.0f, 1.0f); + curvemapping_initialize(gp_falloff_curve); + curvemap_reset(gp_falloff_curve->cm, + &gp_falloff_curve->clipr, + CURVE_PRESET_GAUSS, + CURVEMAP_SLOPE_POSITIVE); + sce->physics_settings.gravity[0] = 0.0f; sce->physics_settings.gravity[1] = 0.0f; sce->physics_settings.gravity[2] = -9.81f; @@ -760,46 +776,65 @@ void BKE_scene_init(Scene *sce) { GP_BrushEdit_Settings *gset = &sce->toolsettings->gp_sculpt; GP_EditBrush_Data *gp_brush; + float curcolor_add[3], curcolor_sub[3]; + ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f); + ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH]; gp_brush->size = 25; gp_brush->strength = 0.3f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS]; gp_brush->size = 25; gp_brush->strength = 0.5f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH]; gp_brush->size = 25; gp_brush->strength = 0.5f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB]; gp_brush->size = 50; gp_brush->strength = 0.3f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH]; gp_brush->size = 25; gp_brush->strength = 0.3f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST]; gp_brush->size = 50; gp_brush->strength = 0.3f; // XXX? - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH]; gp_brush->size = 50; gp_brush->strength = 0.5f; // XXX? - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); gp_brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE]; gp_brush->size = 25; gp_brush->strength = 0.5f; - gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + gp_brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); } /* GP Stroke Placement */ @@ -808,6 +843,10 @@ void BKE_scene_init(Scene *sce) sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE; + /* Annotations */ + sce->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR; + sce->toolsettings->annotate_thickness = 3; + sce->orientation_index_custom = -1; /* Master Collection */ diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c new file mode 100644 index 00000000000..c028c2184fd --- /dev/null +++ b/source/blender/blenkernel/intern/shader_fx.c @@ -0,0 +1,245 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/shader_fx.c + * \ingroup bke + */ + + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_string_utils.h" + +#include "BLT_translation.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_shader_fx_types.h" + +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_gpencil.h" +#include "BKE_shader_fx.h" +#include "BKE_object.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "FX_shader_types.h" + +static ShaderFxTypeInfo *shader_fx_types[NUM_SHADER_FX_TYPES] = { NULL }; + +/* *************************************************** */ +/* Methods - Evaluation Loops, etc. */ + +/* check if exist grease pencil effects */ +bool BKE_shaderfx_has_gpencil(Object *ob) +{ + ShaderFxData *fx; + for (fx = ob->shader_fx.first; fx; fx = fx->next) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + if (fxi->type == eShaderFxType_GpencilType) { + return true; + } + } + return false; +} + +void BKE_shaderfx_init(void) +{ + /* Initialize shaders */ + shaderfx_type_init(shader_fx_types); /* FX_shader_util.c */ +} + +ShaderFxData *BKE_shaderfx_new(int type) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type); + ShaderFxData *fx = MEM_callocN(fxi->struct_size, fxi->struct_name); + + /* note, this name must be made unique later */ + BLI_strncpy(fx->name, DATA_(fxi->name), sizeof(fx->name)); + + fx->type = type; + fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render | eShaderFxMode_Expanded; + fx->flag = eShaderFxFlag_StaticOverride_Local; + + if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode) + fx->mode |= eShaderFxMode_Editmode; + + if (fxi->initData) fxi->initData(fx); + + return fx; +} + +static void shaderfx_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_min(id); + } +} + +void BKE_shaderfx_free_ex(ShaderFxData *fx, const int flag) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (fxi->foreachIDLink) { + fxi->foreachIDLink(fx, NULL, shaderfx_free_data_id_us_cb, NULL); + } + else if (fxi->foreachObjectLink) { + fxi->foreachObjectLink(fx, NULL, (ShaderFxObjectWalkFunc)shaderfx_free_data_id_us_cb, NULL); + } + } + + if (fxi->freeData) fxi->freeData(fx); + if (fx->error) MEM_freeN(fx->error); + + MEM_freeN(fx); +} + +void BKE_shaderfx_free(ShaderFxData *fx) +{ + BKE_shaderfx_free_ex(fx, 0); +} + +/* check unique name */ +bool BKE_shaderfx_unique_name(ListBase *shaders, ShaderFxData *fx) +{ + if (shaders && fx) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + return BLI_uniquename(shaders, fx, DATA_(fxi->name), '.', offsetof(ShaderFxData, name), sizeof(fx->name)); + } + return false; +} + +bool BKE_shaderfx_dependsOnTime(ShaderFxData *fx) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + return fxi->dependsOnTime && fxi->dependsOnTime(fx); +} + +const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type) +{ + /* type unsigned, no need to check < 0 */ + if (type < NUM_SHADER_FX_TYPES && shader_fx_types[type]->name[0] != '\0') { + return shader_fx_types[type]; + } + else { + return NULL; + } +} + +void BKE_shaderfx_copyData_generic(const ShaderFxData *fx_src, ShaderFxData *fx_dst) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx_src->type); + + /* fx_dst may have alredy be fully initialized with some extra allocated data, + * we need to free it now to avoid memleak. */ + if (fxi->freeData) { + fxi->freeData(fx_dst); + } + + const size_t data_size = sizeof(ShaderFxData); + const char *fx_src_data = ((const char *)fx_src) + data_size; + char *fx_dst_data = ((char *)fx_dst) + data_size; + BLI_assert(data_size <= (size_t)fxi->struct_size); + memcpy(fx_dst_data, fx_src_data, (size_t)fxi->struct_size - data_size); +} + +static void shaderfx_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag) +{ + ID *id = *idpoin; + if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(id); + } +} + +void BKE_shaderfx_copyData_ex(ShaderFxData *fx, ShaderFxData *target, const int flag) +{ + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + target->mode = fx->mode; + target->flag = fx->flag; + + if (fxi->copyData) { + fxi->copyData(fx, target); + } + + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + if (fxi->foreachIDLink) { + fxi->foreachIDLink(target, NULL, shaderfx_copy_data_id_us_cb, NULL); + } + else if (fxi->foreachObjectLink) { + fxi->foreachObjectLink(target, NULL, (ShaderFxObjectWalkFunc)shaderfx_copy_data_id_us_cb, NULL); + } + } +} + +void BKE_shaderfx_copyData(ShaderFxData *fx, ShaderFxData *target) +{ + BKE_shaderfx_copyData_ex(fx, target, 0); +} + +ShaderFxData *BKE_shaderfx_findByType(Object *ob, ShaderFxType type) +{ + ShaderFxData *fx = ob->shader_fx.first; + + for (; fx; fx = fx->next) + if (fx->type == type) + break; + + return fx; +} + +void BKE_shaderfx_foreachIDLink(Object *ob, ShaderFxIDWalkFunc walk, void *userData) +{ + ShaderFxData *fx = ob->shader_fx.first; + + for (; fx; fx = fx->next) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + + if (fxi->foreachIDLink) fxi->foreachIDLink(fx, ob, walk, userData); + else if (fxi->foreachObjectLink) { + /* each Object can masquerade as an ID, so this should be OK */ + ShaderFxObjectWalkFunc fp = (ShaderFxObjectWalkFunc)walk; + fxi->foreachObjectLink(fx, ob, fp, userData); + } + } +} + +ShaderFxData *BKE_shaderfx_findByName(Object *ob, const char *name) +{ + return BLI_findstring(&(ob->shader_fx), name, offsetof(ShaderFxData, name)); +} diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index ec16a6854c4..ef2ff10b5c6 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -78,6 +78,9 @@ MINLINE void zero_v3_int(int r[3]); MINLINE void copy_v2_v2_int(int r[2], const int a[2]); MINLINE void copy_v3_v3_int(int r[3], const int a[3]); MINLINE void copy_v4_v4_int(int r[4], const int a[4]); +/* int <-> float */ +MINLINE void copy_v2fl_v2i(float r[2], const int a[2]); +MINLINE void round_v2i_v2fl(int r[2], const float a[2]); /* double -> float */ MINLINE void copy_v2fl_v2db(float r[2], const double a[2]); MINLINE void copy_v3fl_v3db(float r[3], const double a[3]); diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h index 612151b7ea2..f7dea562393 100644 --- a/source/blender/blenlib/BLI_rand.h +++ b/source/blender/blenlib/BLI_rand.h @@ -64,6 +64,9 @@ void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem /** Note that skipping is as slow as generating n numbers! */ void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1); +/* fill an array with random numbers */ +void BLI_array_frand(float *ar, int count, unsigned int seed); + /** Return a pseudo-random (hash) float from an integer value */ float BLI_hash_frand(unsigned int seed) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index 568448327bd..80b8a8d041c 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -578,6 +578,9 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset) Link *link = NULL; const char *id_iter; + if (id == NULL) + return NULL; + for (link = listbase->first; link; link = link->next) { id_iter = ((const char *)link) + offset; diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index 189b94a6f13..c4535eacefa 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -192,6 +192,19 @@ MINLINE void copy_v4_v4_int(int r[4], const int a[4]) r[3] = a[3]; } +/* int <-> float */ +MINLINE void round_v2i_v2fl(int r[2], const float a[2]) +{ + r[0] = (int)roundf(a[0]); + r[1] = (int)roundf(a[1]); +} + +MINLINE void copy_v2fl_v2i(float r[2], const int a[2]) +{ + r[0] = (float)a[0]; + r[1] = (float)a[1]; +} + /* double -> float */ MINLINE void copy_v2fl_v2db(float r[2], const double a[2]) { diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c index 9e56ce6b2cf..8613a0ea6dd 100644 --- a/source/blender/blenlib/intern/rand.c +++ b/source/blender/blenlib/intern/rand.c @@ -265,6 +265,18 @@ void BLI_rng_skip(RNG *rng, int n) /***/ +/* fill an array with random numbers */ +void BLI_array_frand(float *ar, int count, unsigned int seed) +{ + RNG rng; + + BLI_rng_srandom(&rng, seed); + + for (int i = 0; i < count; i++) { + ar[i] = BLI_rng_get_float(&rng); + } +} + float BLI_hash_frand(unsigned int seed) { RNG rng; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 816a527d829..293114c4b79 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -72,6 +72,8 @@ #include "DNA_genfile.h" #include "DNA_group_types.h" #include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_ipo_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" @@ -130,6 +132,8 @@ #include "BKE_effect.h" #include "BKE_fcurve.h" #include "BKE_global.h" // for G +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" #include "BKE_layer.h" #include "BKE_library.h" // for which_libbase #include "BKE_library_idmap.h" @@ -153,6 +157,7 @@ #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_sequencer.h" +#include "BKE_shader_fx.h" #include "BKE_outliner_treehash.h" #include "BKE_sound.h" #include "BKE_colortools.h" @@ -266,6 +271,8 @@ static BHead *find_bhead_from_idname(FileData *fd, const char *idname); #ifdef USE_COLLECTION_COMPAT_28 static void expand_scene_collection(FileData *fd, Main *mainvar, SceneCollection *sc); #endif +static void direct_link_animdata(FileData *fd, AnimData *adt); +static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt); /* this function ensures that reports are printed, * in the case of libraray linking errors this is important! @@ -2368,6 +2375,7 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap) } /* ************ READ Brush *************** */ + /* library brush linking after fileread */ static void lib_link_brush(FileData *fd, Main *main) { @@ -2383,6 +2391,11 @@ static void lib_link_brush(FileData *fd, Main *main) brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush); brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve); + /* link default grease pencil palette */ + if (brush->gpencil_settings != NULL) { + brush->gpencil_settings->material = newlibadr_us(fd, brush->id.lib, brush->gpencil_settings->material); + } + brush->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -2394,6 +2407,7 @@ static void direct_link_brush(FileData *fd, Brush *brush) /* fallof curve */ brush->curve = newdataadr(fd, brush->curve); + brush->gradient = newdataadr(fd, brush->gradient); if (brush->curve) @@ -2401,11 +2415,29 @@ static void direct_link_brush(FileData *fd, Brush *brush) else BKE_brush_curve_preset(brush, CURVE_PRESET_SHARP); + /* grease pencil */ + brush->gpencil_settings = newdataadr(fd, brush->gpencil_settings); + if (brush->gpencil_settings != NULL) { + brush->gpencil_settings->curve_sensitivity = newdataadr(fd, brush->gpencil_settings->curve_sensitivity); + brush->gpencil_settings->curve_strength = newdataadr(fd, brush->gpencil_settings->curve_strength); + brush->gpencil_settings->curve_jitter = newdataadr(fd, brush->gpencil_settings->curve_jitter); + + if (brush->gpencil_settings->curve_sensitivity) + direct_link_curvemapping(fd, brush->gpencil_settings->curve_sensitivity); + + if (brush->gpencil_settings->curve_strength) + direct_link_curvemapping(fd, brush->gpencil_settings->curve_strength); + + if (brush->gpencil_settings->curve_jitter) + direct_link_curvemapping(fd, brush->gpencil_settings->curve_jitter); + } + brush->preview = NULL; brush->icon_imbuf = NULL; } /* ************ READ Palette *************** */ + static void lib_link_palette(FileData *fd, Main *main) { /* only link ID pointers */ @@ -2420,6 +2452,7 @@ static void lib_link_palette(FileData *fd, Main *main) static void direct_link_palette(FileData *fd, Palette *palette) { + /* palette itself has been read */ link_list(fd, &palette->colors); } @@ -4147,6 +4180,17 @@ static void lib_link_material(FileData *fd, Main *main) ma->nodetree->id.lib = ma->id.lib; } + /* relink grease pencil settings */ + if (ma->gp_style != NULL) { + MaterialGPencilStyle *gp_style = ma->gp_style; + if (gp_style->sima != NULL) { + gp_style->sima = newlibadr_us(fd, ma->id.lib, gp_style->sima); + } + if (gp_style->ima != NULL) { + gp_style->ima = newlibadr_us(fd, ma->id.lib, gp_style->ima); + } + } + ma->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -4167,6 +4211,8 @@ static void direct_link_material(FileData *fd, Material *ma) ma->preview = direct_link_preview_image(fd, ma->preview); BLI_listbase_clear(&ma->gpumaterial); + + ma->gp_style = newdataadr(fd, ma->gp_style); } /* ************ READ PARTICLE SETTINGS ***************** */ @@ -4802,7 +4848,7 @@ static void direct_link_latt(FileData *fd, Lattice *lt) /* ************ READ OBJECT ***************** */ -static void lib_link_modifiers__linkModifiers( +static void lib_link_modifiers_common( void *userData, Object *ob, ID **idpoin, int cb_flag) { FileData *fd = userData; @@ -4812,9 +4858,10 @@ static void lib_link_modifiers__linkModifiers( id_us_plus_no_lib(*idpoin); } } + static void lib_link_modifiers(FileData *fd, Object *ob) { - modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd); + modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd); /* If linking from a library, clear 'local' static override flag. */ if (ob->id.lib != NULL) { @@ -4825,6 +4872,30 @@ static void lib_link_modifiers(FileData *fd, Object *ob) } +static void lib_link_gpencil_modifiers(FileData *fd, Object *ob) +{ + BKE_gpencil_modifiers_foreachIDLink(ob, lib_link_modifiers_common, fd); + + /* If linking from a library, clear 'local' static override flag. */ + if (ob->id.lib != NULL) { + for (GpencilModifierData *mod = ob->greasepencil_modifiers.first; mod != NULL; mod = mod->next) { + mod->flag &= ~eGpencilModifierFlag_StaticOverride_Local; + } + } +} + +static void lib_link_shaderfxs(FileData *fd, Object *ob) +{ + BKE_shaderfx_foreachIDLink(ob, lib_link_modifiers_common, fd); + + /* If linking from a library, clear 'local' static override flag. */ + if (ob->id.lib != NULL) { + for (ShaderFxData *fx = ob->shader_fx.first; fx != NULL; fx = fx->next) { + fx->flag &= ~eShaderFxFlag_StaticOverride_Local; + } + } +} + static void lib_link_object(FileData *fd, Main *main) { bool warn = false; @@ -4961,6 +5032,8 @@ static void lib_link_object(FileData *fd, Main *main) lib_link_particlesystems(fd, ob, &ob->id, &ob->particlesystem); lib_link_modifiers(fd, ob); + lib_link_gpencil_modifiers(fd, ob); + lib_link_shaderfxs(fd, ob); if (ob->rigidbody_constraint) { ob->rigidbody_constraint->ob1 = newlibadr(fd, ob->id.lib, ob->rigidbody_constraint->ob1); @@ -5356,6 +5429,61 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) } } +static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb) +{ + GpencilModifierData *md; + + link_list(fd, lb); + + for (md = lb->first; md; md = md->next) { + md->error = NULL; + + /* if modifiers disappear, or for upward compatibility */ + if (NULL == BKE_gpencil_modifierType_getInfo(md->type)) + md->type = eModifierType_None; + + if (md->type == eGpencilModifierType_Lattice) { + LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData*)md; + gpmd->cache_data = NULL; + } + else if (md->type == eGpencilModifierType_Hook) { + HookGpencilModifierData *hmd = (HookGpencilModifierData *)md; + + hmd->curfalloff = newdataadr(fd, hmd->curfalloff); + if (hmd->curfalloff) { + direct_link_curvemapping(fd, hmd->curfalloff); + } + } + else if (md->type == eGpencilModifierType_Thick) { + ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; + + gpmd->curve_thickness = newdataadr(fd, gpmd->curve_thickness); + if (gpmd->curve_thickness) { + direct_link_curvemapping(fd, gpmd->curve_thickness); + /* initialize the curve. Maybe this could be moved to modififer logic */ + curvemapping_initialize(gpmd->curve_thickness); + } + } + + } +} + +static void direct_link_shaderfxs(FileData *fd, ListBase *lb) +{ + ShaderFxData *fx; + + link_list(fd, lb); + + for (fx = lb->first; fx; fx = fx->next) { + fx->error = NULL; + + /* if shader disappear, or for upward compatibility */ + if (NULL == BKE_shaderfxType_getInfo(fx->type)) + fx->type = eShaderFxType_None; + + } +} + static void direct_link_object(FileData *fd, Object *ob) { PartEff *paf; @@ -5399,6 +5527,8 @@ static void direct_link_object(FileData *fd, Object *ob) /* do it here, below old data gets converted */ direct_link_modifiers(fd, &ob->modifiers); + direct_link_gpencil_modifiers(fd, &ob->greasepencil_modifiers); + direct_link_shaderfxs(fd, &ob->shader_fx); link_list(fd, &ob->effect); paf= ob->effect.first; @@ -5879,6 +6009,7 @@ static void lib_link_scene(FileData *fd, Main *main) link_paint(fd, sce, &sce->toolsettings->wpaint->paint); link_paint(fd, sce, &sce->toolsettings->imapaint.paint); link_paint(fd, sce, &sce->toolsettings->uvsculpt->paint); + link_paint(fd, sce, &sce->toolsettings->gp_paint->paint); if (sce->toolsettings->sculpt) sce->toolsettings->sculpt->gravity_object = @@ -6137,6 +6268,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->vpaint); direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->wpaint); direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->uvsculpt); + direct_link_paint_helper(fd, (Paint**)&sce->toolsettings->gp_paint); direct_link_paint(fd, &sce->toolsettings->imapaint.paint); @@ -6146,28 +6278,16 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->toolsettings->particle.object = NULL; sce->toolsettings->gp_sculpt.paintcursor = NULL; - /* relink grease pencil drawing brushes */ - link_list(fd, &sce->toolsettings->gp_brushes); - for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { - brush->cur_sensitivity = newdataadr(fd, brush->cur_sensitivity); - if (brush->cur_sensitivity) { - direct_link_curvemapping(fd, brush->cur_sensitivity); - } - brush->cur_strength = newdataadr(fd, brush->cur_strength); - if (brush->cur_strength) { - direct_link_curvemapping(fd, brush->cur_strength); - } - brush->cur_jitter = newdataadr(fd, brush->cur_jitter); - if (brush->cur_jitter) { - direct_link_curvemapping(fd, brush->cur_jitter); - } - } - /* relink grease pencil interpolation curves */ sce->toolsettings->gp_interpolate.custom_ipo = newdataadr(fd, sce->toolsettings->gp_interpolate.custom_ipo); if (sce->toolsettings->gp_interpolate.custom_ipo) { direct_link_curvemapping(fd, sce->toolsettings->gp_interpolate.custom_ipo); } + /* relink grease pencil multiframe falloff curve */ + sce->toolsettings->gp_sculpt.cur_falloff = newdataadr(fd, sce->toolsettings->gp_sculpt.cur_falloff); + if (sce->toolsettings->gp_sculpt.cur_falloff) { + direct_link_curvemapping(fd, sce->toolsettings->gp_sculpt.cur_falloff); + } } if (sce->ed) { @@ -6405,11 +6525,24 @@ static void direct_link_scene(FileData *fd, Scene *sce) /* relink's grease pencil data's refs */ static void lib_link_gpencil(FileData *fd, Main *main) { + /* Relink all datablock linked by GP datablock */ for (bGPdata *gpd = main->gpencil.first; gpd; gpd = gpd->id.next) { if (gpd->id.tag & LIB_TAG_NEED_LINK) { + /* Layers */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* Layer -> Parent References */ + gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent); + } + + /* Datablock Stuff */ IDP_LibLinkProperty(gpd->id.properties, fd); lib_link_animdata(fd, &gpd->id, gpd->adt); + /* materials */ + for (int a = 0; a < gpd->totcol; a++) { + gpd->mat[a] = newlibadr_us(fd, gpd->id.lib, gpd->mat[a]); + } + gpd->id.tag &= ~LIB_TAG_NEED_LINK; } } @@ -6431,36 +6564,49 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) gpd->adt = newdataadr(fd, gpd->adt); direct_link_animdata(fd, gpd->adt); - /* relink palettes */ + /* relink palettes (old palettes deprecated, only to convert old files) */ link_list(fd, &gpd->palettes); - for (palette = gpd->palettes.first; palette; palette = palette->next) { - link_list(fd, &palette->colors); + if (gpd->palettes.first != NULL) { + for (palette = gpd->palettes.first; palette; palette = palette->next) { + link_list(fd, &palette->colors); + } } + /* clear drawing cache */ + gpd->runtime.batch_cache_data = NULL; + + /* materials */ + gpd->mat = newdataadr(fd, gpd->mat); + test_pointer_array(fd, (void **)&gpd->mat); + /* relink layers */ link_list(fd, &gpd->layers); for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* parent */ - gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent); /* relink frames */ link_list(fd, &gpl->frames); + gpl->actframe = newdataadr(fd, gpl->actframe); + gpl->runtime.derived_data = NULL; + gpl->runtime.icon_id = 0; + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { /* relink strokes (and their points) */ link_list(fd, &gpf->strokes); for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* relink stroke points array */ gps->points = newdataadr(fd, gps->points); + /* relink weight data */ + gps->dvert = newdataadr(fd, gps->dvert); + direct_link_dverts(fd, gps->totpoints, gps->dvert); + /* the triangulation is not saved, so need to be recalculated */ gps->triangles = NULL; gps->tot_triangles = 0; gps->flag |= GP_STROKE_RECALC_CACHES; - /* the color pointer is not saved, so need to be recalculated using the color name */ - gps->palcolor = NULL; - gps->flag |= GP_STROKE_RECALC_COLOR; } } } @@ -8618,6 +8764,11 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd) user->walk_navigation.jump_height = 0.4f; /* m */ user->walk_navigation.teleport_time = 0.2f; /* s */ } + + /* grease pencil multisamples */ + if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "short", "gpencil_multisamples")) { + user->gpencil_multisamples = 4; + } } static void do_versions(FileData *fd, Library *lib, Main *main) @@ -8696,8 +8847,8 @@ static void lib_link_all(FileData *fd, Main *main) lib_link_action(fd, main); lib_link_vfont(fd, main); lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */ - lib_link_brush(fd, main); lib_link_palette(fd, main); + lib_link_brush(fd, main); lib_link_paint_curve(fd, main); lib_link_particlesettings(fd, main); lib_link_movieclip(fd, main); @@ -9434,6 +9585,9 @@ static void expand_brush(FileData *fd, Main *mainvar, Brush *brush) expand_doit(fd, mainvar, brush->mask_mtex.tex); expand_doit(fd, mainvar, brush->clone.image); expand_doit(fd, mainvar, brush->paint_curve); + if (brush->gpencil_settings != NULL) { + expand_doit(fd, mainvar, brush->gpencil_settings->material); + } } static void expand_material(FileData *fd, Main *mainvar, Material *ma) @@ -9445,6 +9599,12 @@ static void expand_material(FileData *fd, Main *mainvar, Material *ma) if (ma->nodetree) expand_nodetree(fd, mainvar, ma->nodetree); + + if (ma->gp_style) { + MaterialGPencilStyle *gp_style = ma->gp_style; + expand_doit(fd, mainvar, gp_style->sima); + expand_doit(fd, mainvar, gp_style->ima); + } } static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la) @@ -9621,6 +9781,24 @@ static void expand_object(FileData *fd, Main *mainvar, Object *ob) modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data); } + /* expand_object_expandModifier() */ + if (ob->greasepencil_modifiers.first) { + struct { FileData *fd; Main *mainvar; } data; + data.fd = fd; + data.mainvar = mainvar; + + BKE_gpencil_modifiers_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data); + } + + /* expand_object_expandShaderFx() */ + if (ob->shader_fx.first) { + struct { FileData *fd; Main *mainvar; } data; + data.fd = fd; + data.mainvar = mainvar; + + BKE_shaderfx_foreachIDLink(ob, expand_object_expandModifiers, (void *)&data); + } + expand_pose(fd, mainvar, ob->pose); expand_doit(fd, mainvar, ob->poselib); expand_constraints(fd, mainvar, &ob->constraints); @@ -9899,8 +10077,18 @@ static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *li static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) { - if (gpd->adt) + if (gpd->adt) { expand_animdata(fd, mainvar, gpd->adt); + } + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + expand_doit(fd, mainvar, gpl->parent); + } + + for (int a = 0; a < gpd->totcol; a++) { + expand_doit(fd, mainvar, gpd->mat[a]); + } + } static void expand_workspace(FileData *fd, Main *mainvar, WorkSpace *workspace) diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 7a032dc3c90..f2f2e7d7881 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -1685,7 +1685,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) case SPACE_VIEW3D: { View3D *v3d = (View3D *)sl; - v3d->flag2 |= V3D_SHOW_GPENCIL; + v3d->flag2 |= V3D_SHOW_ANNOTATION; break; } case SPACE_SEQ: @@ -1709,7 +1709,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) case SPACE_CLIP: { SpaceClip *sclip = (SpaceClip *)sl; - sclip->flag |= SC_SHOW_GPENCIL; + sclip->flag |= SC_SHOW_ANNOTATION; break; } } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 7a106611e64..fadf332c850 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -76,6 +76,9 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_string_utils.h" + +#include "BLT_translation.h" #include "BLO_readfile.h" @@ -87,6 +90,64 @@ #include "MEM_guardedalloc.h" +/* ************************************************** */ +/* GP Palettes API (Deprecated) */ + +/* add a new gp-palette */ +static bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name) +{ + bGPDpalette *palette; + + /* check that list is ok */ + if (gpd == NULL) { + return NULL; + } + + /* allocate memory and add to end of list */ + palette = MEM_callocN(sizeof(bGPDpalette), "bGPDpalette"); + + /* add to datablock */ + BLI_addtail(&gpd->palettes, palette); + + /* set basic settings */ + /* auto-name */ + BLI_strncpy(palette->info, name, sizeof(palette->info)); + BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info), + sizeof(palette->info)); + + /* return palette */ + return palette; +} + +/* add a new gp-palettecolor */ +static bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(bGPDpalette *palette, const char *name) +{ + bGPDpalettecolor *palcolor; + + /* check that list is ok */ + if (palette == NULL) { + return NULL; + } + + /* allocate memory and add to end of list */ + palcolor = MEM_callocN(sizeof(bGPDpalettecolor), "bGPDpalettecolor"); + + /* add to datablock */ + BLI_addtail(&palette->colors, palcolor); + + /* set basic settings */ + copy_v4_v4(palcolor->color, U.gpencil_new_layer_col); + ARRAY_SET_ITEMS(palcolor->fill, 1.0f, 1.0f, 1.0f); + + /* auto-name */ + BLI_strncpy(palcolor->info, name, sizeof(palcolor->info)); + BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info), + sizeof(palcolor->info)); + + /* return palette color */ + return palcolor; +} + /** * Setup rotation stabilization from ancient single track spec. * Former Version of 2D stabilization used a single tracking marker to determine the rotation @@ -1344,8 +1405,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) ToolSettings *ts = scene->toolsettings; /* initialize use position for sculpt brushes */ ts->gp_sculpt.flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION; - /* initialize selected vertices alpha factor */ - ts->gp_sculpt.alpha = 1.0f; /* new strength sculpt brush */ if (ts->gp_sculpt.brush[0].size >= 11) { @@ -1358,25 +1417,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; } } - /* create a default grease pencil drawing brushes set */ - if (!BLI_listbase_is_empty(&bmain->gpencil)) { - for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { - ToolSettings *ts = scene->toolsettings; - if (BLI_listbase_is_empty(&ts->gp_brushes)) { - BKE_gpencil_brush_init_presets(ts); - } - } - } /* Convert Grease Pencil to new palettes/brushes * Loop all strokes and create the palette and all colors */ for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { if (BLI_listbase_is_empty(&gpd->palettes)) { /* create palette */ - bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette", true); + bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette"); for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* create color using layer name */ - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info, true); + bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info); if (palcolor != NULL) { /* set color attributes */ copy_v4_v4(palcolor->color, gpl->color); @@ -1386,7 +1436,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) if (gpl->flag & GP_LAYER_LOCKED) palcolor->flag |= PC_COLOR_LOCKED; if (gpl->flag & GP_LAYER_ONIONSKIN) palcolor->flag |= PC_COLOR_ONIONSKIN; if (gpl->flag & GP_LAYER_VOLUMETRIC) palcolor->flag |= PC_COLOR_VOLUMETRIC; - if (gpl->flag & GP_LAYER_HQ_FILL) palcolor->flag |= PC_COLOR_HQ_FILL; /* set layer opacity to 1 */ gpl->opacity = 1.0f; @@ -1399,8 +1448,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* set stroke to palette and force recalculation */ BLI_strncpy(gps->colorname, gpl->info, sizeof(gps->colorname)); - gps->palcolor = NULL; - gps->flag |= GP_STROKE_RECALC_COLOR; gps->thickness = gpl->thickness; /* set alpha strength to 1 */ @@ -1410,13 +1457,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } - - /* set thickness to 0 (now it is a factor to override stroke thickness) */ - gpl->thickness = 0.0f; } - /* set first color as active */ - if (palette->colors.first) - BKE_gpencil_palettecolor_setactive(palette, palette->colors.first); } } } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 5b0a12a0b4c..7339f1977ff 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -54,16 +54,19 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" #include "DNA_genfile.h" +#include "DNA_gpencil_types.h" #include "DNA_workspace_types.h" #include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_customdata.h" +#include "BKE_colortools.h" #include "BKE_freestyle.h" #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_node.h" #include "BKE_pointcache.h" @@ -73,6 +76,9 @@ #include "BKE_sequencer.h" #include "BKE_studiolight.h" #include "BKE_workspace.h" +#include "BKE_gpencil.h" +#include "BKE_paint.h" +#include "BKE_object.h" #include "BLO_readfile.h" #include "readfile.h" @@ -743,6 +749,7 @@ void do_versions_after_linking_280(Main *bmain) } } #endif + } /* NOTE: this version patch is intended for versions < 2.52.2, but was initially introduced in 2.27 already. @@ -839,7 +846,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) if (ntree->type == NTREE_SHADER) { for (bNode *node = ntree->nodes.first; node; node = node->next) { if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ && - STREQ(node->idname, "ShaderNodeOutputMetallic")) + STREQ(node->idname, "ShaderNodeOutputMetallic")) { BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname)); error |= NTREE_DOVERSION_NEED_OUTPUT; @@ -851,14 +858,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } else if (node->type == 196 /* SH_NODE_OUTPUT_EEVEE_MATERIAL */ && - STREQ(node->idname, "ShaderNodeOutputEeveeMaterial")) + STREQ(node->idname, "ShaderNodeOutputEeveeMaterial")) { node->type = SH_NODE_OUTPUT_MATERIAL; BLI_strncpy(node->idname, "ShaderNodeOutputMaterial", sizeof(node->idname)); } else if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ && - STREQ(node->idname, "ShaderNodeEeveeMetallic")) + STREQ(node->idname, "ShaderNodeEeveeMetallic")) { node->type = SH_NODE_BSDF_PRINCIPLED; BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname)); @@ -869,10 +876,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } FOREACH_NODETREE_END - if (error & NTREE_DOVERSION_NEED_OUTPUT) { - BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console"); - printf("You need to connect Principled and Eevee Specular shader nodes to new material output nodes.\n"); - } + if (error & NTREE_DOVERSION_NEED_OUTPUT) { + BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console"); + printf("You need to connect Principled and Eevee Specular shader nodes to new material output nodes.\n"); + } if (error & NTREE_DOVERSION_TRANSPARENCY_EMISSION) { BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console"); @@ -896,6 +903,68 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } } #endif + + { + /* Grease pencil sculpt and paint cursors */ + if (!DNA_struct_elem_find(fd->filesdna, "GP_BrushEdit_Settings", "int", "weighttype")) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + /* sculpt brushes */ + GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt; + if (gset) { + gset->weighttype = GP_EDITBRUSH_TYPE_WEIGHT; + } + } + } + + { + float curcolor_add[3], curcolor_sub[3]; + ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f); + ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f); + GP_EditBrush_Data *gp_brush; + + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + ToolSettings *ts = scene->toolsettings; + /* sculpt brushes */ + GP_BrushEdit_Settings *gset = &ts->gp_sculpt; + for (int i = 0; i < TOT_GP_EDITBRUSH_TYPES; ++i) { + gp_brush = &gset->brush[i]; + gp_brush->flag |= GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(gp_brush->curcolor_add, curcolor_add); + copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub); + } + } + } + + /* Init grease pencil edit line color */ + if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "line_color[4]")) { + for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { + ARRAY_SET_ITEMS(gpd->line_color, 0.6f, 0.6f, 0.6f, 0.5f); + } + } + + /* Init grease pencil pixel size factor */ + if (!DNA_struct_elem_find(fd->filesdna, "bGPDdata", "int", "pixfactor")) { + for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { + gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; + } + } + + /* Grease pencil multiframe falloff curve */ + if (!DNA_struct_elem_find(fd->filesdna, "GP_BrushEdit_Settings", "CurveMapping", "cur_falloff")) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + /* sculpt brushes */ + GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt; + if ((gset) && (gset->cur_falloff == NULL)) { + gset->cur_falloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + curvemapping_initialize(gset->cur_falloff); + curvemap_reset(gset->cur_falloff->cm, + &gset->cur_falloff->clipr, + CURVE_PRESET_GAUSS, + CURVEMAP_SLOPE_POSITIVE); + } + } + } + } } #ifdef USE_COLLECTION_COMPAT_28 @@ -915,6 +984,26 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } #endif + if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) { + /* init grease pencil grids and paper */ + if (!DNA_struct_elem_find(fd->filesdna, "gp_paper_opacity", "float", "gpencil_paper_color[3]")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *area = screen->areabase.first; area; area = area->next) { + for (SpaceLink *sl = area->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.gpencil_grid_scale = 1.0f; // Scale + v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; // NUmber of lines + v3d->overlay.gpencil_paper_opacity = 0.5f; + v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y; + v3d->overlay.gpencil_grid_opacity = 0.9f; + } + } + } + } + } + } + if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) { if (DNA_struct_elem_find(fd->filesdna, "SpaceOops", "int", "filter") == false) { bScreen *sc; @@ -1017,6 +1106,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) tex->type = 0; } } + } if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) { @@ -1643,6 +1733,101 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) BKE_screen_view3d_shading_init(&scene->display.shading); } } + /* initialize grease pencil view data */ + if (!DNA_struct_elem_find(fd->filesdna, "SpaceView3D", "float", "vertex_opacity")) { + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->vertex_opacity = 1.0f; + v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES; + } + } + } + } + } + + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 22)) { + if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "annotate_v3d_align")) { + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + scene->toolsettings->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR; + scene->toolsettings->annotate_thickness = 3; + } + } + if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "short", "line_change")) { + for (bGPdata *gpd = bmain->gpencil.first; gpd; gpd = gpd->id.next) { + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + gpl->line_change = gpl->thickness; + if ((gpl->thickness < 1) || (gpl->thickness > 10)) { + gpl->thickness = 3; + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_scale")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.gpencil_grid_scale = 1.0f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_opacity")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.gpencil_paper_opacity = 0.5f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_grid_opacity")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.gpencil_grid_opacity = 0.5f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "int", "gpencil_grid_axis")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "int", "gpencil_grid_lines")) { + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; + } + } + } + } + } + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index bd7334516ca..a86986e2e09 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -170,46 +170,77 @@ void BLO_update_defaults_startup_blend(Main *bmain) if (ts->gp_sculpt.brush[0].size == 0) { GP_BrushEdit_Settings *gset = &ts->gp_sculpt; GP_EditBrush_Data *brush; + float curcolor_add[3], curcolor_sub[3]; + ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f); + ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f); + + /* default sculpt brush */ + gset->brushtype = GP_EDITBRUSH_TYPE_PUSH; + /* default weight paint brush */ + gset->weighttype = GP_EDITBRUSH_TYPE_WEIGHT; brush = &gset->brush[GP_EDITBRUSH_TYPE_SMOOTH]; brush->size = 25; brush->strength = 0.3f; - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); brush = &gset->brush[GP_EDITBRUSH_TYPE_THICKNESS]; brush->size = 25; brush->strength = 0.5f; - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); brush = &gset->brush[GP_EDITBRUSH_TYPE_STRENGTH]; brush->size = 25; brush->strength = 0.5f; - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); brush = &gset->brush[GP_EDITBRUSH_TYPE_GRAB]; brush->size = 50; brush->strength = 0.3f; - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); brush = &gset->brush[GP_EDITBRUSH_TYPE_PUSH]; brush->size = 25; brush->strength = 0.3f; - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); brush = &gset->brush[GP_EDITBRUSH_TYPE_TWIST]; brush->size = 50; brush->strength = 0.3f; // XXX? - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); brush = &gset->brush[GP_EDITBRUSH_TYPE_PINCH]; brush->size = 50; brush->strength = 0.5f; // XXX? - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); brush = &gset->brush[GP_EDITBRUSH_TYPE_RANDOMIZE]; brush->size = 25; brush->strength = 0.5f; - brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); + + brush = &gset->brush[GP_EDITBRUSH_TYPE_WEIGHT]; + brush->size = 25; + brush->strength = 0.5f; + brush->flag = GP_EDITBRUSH_FLAG_USE_FALLOFF | GP_EDITBRUSH_FLAG_ENABLE_CURSOR; + copy_v3_v3(brush->curcolor_add, curcolor_add); + copy_v3_v3(brush->curcolor_sub, curcolor_sub); } ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE; @@ -217,6 +248,9 @@ void BLO_update_defaults_startup_blend(Main *bmain) ts->gpencil_seq_align = GP_PROJECT_VIEWSPACE; ts->gpencil_ima_align = GP_PROJECT_VIEWSPACE; + ts->annotate_v3d_align = GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR; + ts->annotate_thickness = 3; + ParticleEditSettings *pset = &ts->particle; for (int a = 0; a < ARRAY_SIZE(pset->brush); a++) { pset->brush[a].strength = 0.5f; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 503f8b44ec3..3883e024ab7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -118,6 +118,8 @@ #include "DNA_genfile.h" #include "DNA_group_types.h" #include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_fileglobal_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" @@ -165,6 +167,7 @@ #include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_global.h" // for G +#include "BKE_gpencil_modifier.h" #include "BKE_idcode.h" #include "BKE_layer.h" #include "BKE_library.h" // for set_listbasepointers @@ -173,6 +176,7 @@ #include "BKE_node.h" #include "BKE_report.h" #include "BKE_sequencer.h" +#include "BKE_shader_fx.h" #include "BKE_subsurf.h" #include "BKE_modifier.h" #include "BKE_fcurve.h" @@ -1788,6 +1792,57 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) } } +static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase) +{ + GpencilModifierData *md; + + if (modbase == NULL) { + return; + } + + for (md = modbase->first; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + if (mti == NULL) { + return; + } + + writestruct_id(wd, DATA, mti->struct_name, 1, md); + + if (md->type == eGpencilModifierType_Thick) { + ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; + + if (gpmd->curve_thickness) { + write_curvemapping(wd, gpmd->curve_thickness); + } + } + else if (md->type == eGpencilModifierType_Hook) { + HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; + + if (gpmd->curfalloff) { + write_curvemapping(wd, gpmd->curfalloff); + } + } + } +} + +static void write_shaderfxs(WriteData *wd, ListBase *fxbase) +{ + ShaderFxData *fx; + + if (fxbase == NULL) { + return; + } + + for (fx = fxbase->first; fx; fx = fx->next) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(fx->type); + if (fxi == NULL) { + return; + } + + writestruct_id(wd, DATA, fxi->struct_name, 1, fx); + } +} + static void write_object(WriteData *wd, Object *ob) { if (ob->id.us > 0 || wd->use_memfile) { @@ -1842,6 +1897,8 @@ static void write_object(WriteData *wd, Object *ob) write_particlesystems(wd, &ob->particlesystem); write_modifiers(wd, &ob->modifiers); + write_gpencil_modifiers(wd, &ob->greasepencil_modifiers); + write_shaderfxs(wd, &ob->shader_fx); writelist(wd, DATA, LinkData, &ob->pc_ids); writelist(wd, DATA, LodLevel, &ob->lodlevels); @@ -2260,6 +2317,11 @@ static void write_material(WriteData *wd, Material *ma) } write_previews(wd, ma->preview); + + /* grease pencil settings */ + if (ma->gp_style) { + writestruct(wd, DATA, MaterialGPencilStyle, 1, ma->gp_style); + } } } @@ -2463,24 +2525,18 @@ static void write_scene(WriteData *wd, Scene *sce) writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt); write_paint(wd, &tos->uvsculpt->paint); } - /* write grease-pencil drawing brushes to file */ - writelist(wd, DATA, bGPDbrush, &tos->gp_brushes); - for (bGPDbrush *brush = tos->gp_brushes.first; brush; brush = brush->next) { - if (brush->cur_sensitivity) { - write_curvemapping(wd, brush->cur_sensitivity); - } - if (brush->cur_strength) { - write_curvemapping(wd, brush->cur_strength); - } - if (brush->cur_jitter) { - write_curvemapping(wd, brush->cur_jitter); - } + if (tos->gp_paint) { + writestruct(wd, DATA, GpPaint, 1, tos->gp_paint); + write_paint(wd, &tos->gp_paint->paint); } /* write grease-pencil custom ipo curve to file */ if (tos->gp_interpolate.custom_ipo) { write_curvemapping(wd, tos->gp_interpolate.custom_ipo); } - + /* write grease-pencil multiframe falloff curve to file */ + if (tos->gp_sculpt.cur_falloff) { + write_curvemapping(wd, tos->gp_sculpt.cur_falloff); + } write_paint(wd, &tos->imapaint.paint); @@ -2654,6 +2710,8 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd) write_animdata(wd, gpd->adt); } + writedata(wd, DATA, sizeof(void *) * gpd->totcol, gpd->mat); + /* write grease-pencil layers to file */ writelist(wd, DATA, bGPDlayer, &gpd->layers); for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { @@ -2664,15 +2722,10 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd) writelist(wd, DATA, bGPDstroke, &gpf->strokes); for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points); + write_dverts(wd, gps->totpoints, gps->dvert); } } } - - /* write grease-pencil palettes */ - writelist(wd, DATA, bGPDpalette, &gpd->palettes); - for (bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) { - writelist(wd, DATA, bGPDpalettecolor, &palette->colors); - } } } @@ -3159,6 +3212,20 @@ static void write_brush(WriteData *wd, Brush *brush) if (brush->curve) { write_curvemapping(wd, brush->curve); } + + if (brush->gpencil_settings) { + writestruct(wd, DATA, BrushGpencilSettings, 1, brush->gpencil_settings); + + if (brush->gpencil_settings->curve_sensitivity) { + write_curvemapping(wd, brush->gpencil_settings->curve_sensitivity); + } + if (brush->gpencil_settings->curve_strength) { + write_curvemapping(wd, brush->gpencil_settings->curve_strength); + } + if (brush->gpencil_settings->curve_jitter) { + write_curvemapping(wd, brush->gpencil_settings->curve_jitter); + } + } if (brush->gradient) { writestruct(wd, DATA, ColorBand, 1, brush->gradient); } diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp index 47d8f4f52bb..248c780102c 100644 --- a/source/blender/collada/SceneExporter.cpp +++ b/source/blender/collada/SceneExporter.cpp @@ -69,6 +69,7 @@ void SceneExporter::exportHierarchy(bContext *C, Depsgraph *depsgraph, Scene *sc case OB_CAMERA: case OB_LAMP: case OB_EMPTY: + case OB_GPENCIL: case OB_ARMATURE: base_objects.push_back(ob); break; @@ -122,6 +123,7 @@ void SceneExporter::writeNodes(bContext *C, Depsgraph *depsgraph, Object *ob, Sc case OB_CAMERA: case OB_LAMP: case OB_EMPTY: + case OB_GPENCIL: case OB_ARMATURE: if (bc_is_marked(cob)) child_objects.push_back(cob); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 1b68a73bbd7..e20b589bf22 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -77,6 +77,8 @@ extern "C" { #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_fcurve.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" #include "BKE_idcode.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -93,6 +95,7 @@ extern "C" { #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_rigidbody.h" +#include "BKE_shader_fx.h" #include "BKE_sound.h" #include "BKE_tracking.h" #include "BKE_world.h" @@ -514,6 +517,18 @@ void DepsgraphNodeBuilder::build_object(int base_index, data.builder = this; modifiers_foreachIDLink(object, modifier_walk, &data); } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Shadr FX. */ + if (object->shader_fx.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); + } /* Constraints. */ if (object->constraints.first != NULL) { BuilderWalkUserData data; @@ -538,10 +553,6 @@ void DepsgraphNodeBuilder::build_object(int base_index, if (object->particlesystem.first != NULL) { build_particles(object); } - /* Grease pencil. */ - if (object->gpd != NULL) { - build_gpencil(object->gpd); - } /* Proxy object to copy from. */ if (object->proxy_from != NULL) { build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY); @@ -592,6 +603,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) case OB_SURF: case OB_MBALL: case OB_LATTICE: + case OB_GPENCIL: build_object_data_geometry(object); /* TODO(sergey): Only for until we support granular * update of curves. @@ -1213,6 +1225,20 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata) op_node->set_as_entry(); break; } + + case ID_GD: + { + /* GPencil evaluation operations. */ + op_node = add_operation_node(obdata, + DEG_NODE_TYPE_GEOMETRY, + function_bind(BKE_gpencil_eval_geometry, + _1, + (bGPdata *)obdata_cow), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); + op_node->set_as_entry(); + break; + } default: BLI_assert(!"Should not happen"); break; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index f1db05b7220..3d7b2d6d232 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -134,10 +134,6 @@ void DepsgraphNodeBuilder::build_view_layer( if (scene->nodetree != NULL) { build_compositor(scene); } - /* Grease pencil. */ - if (scene->gpd != NULL) { - build_gpencil(scene->gpd); - } /* Cache file. */ LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { build_cachefile(cachefile); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 1a0c621ab43..c9a00b0bf0f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -85,10 +85,12 @@ extern "C" { #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_modifier.h" +#include "BKE_gpencil_modifier.h" #include "BKE_node.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_rigidbody.h" +#include "BKE_shader_fx.h" #include "BKE_sound.h" #include "BKE_tracking.h" #include "BKE_world.h" @@ -525,6 +527,18 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) data.builder = this; modifiers_foreachIDLink(object, modifier_walk, &data); } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Shader FX. */ + if (object->shader_fx.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); + } /* Constraints. */ if (object->constraints.first != NULL) { BuilderWalkUserData data; @@ -570,10 +584,6 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) if (object->particlesystem.first != NULL) { build_particles(object); } - /* Grease pencil. */ - if (object->gpd != NULL) { - build_gpencil(object->gpd); - } /* Proxy object to copy from. */ if (object->proxy_from != NULL) { build_object(NULL, object->proxy_from); @@ -630,6 +640,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) case OB_SURF: case OB_MBALL: case OB_LATTICE: + case OB_GPENCIL: { build_object_data_geometry(object); break; @@ -1798,6 +1809,42 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) } } } + /* Grease Pencil Modifiers */ + if (object->greasepencil_modifiers.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH(GpencilModifierData *, md, &object->greasepencil_modifiers) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo((GpencilModifierType)md->type); + if (mti->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); + mti->updateDepsgraph(md, &ctx); + } + if (BKE_object_modifier_gpencil_use_time(object, md)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } + /* Shader FX */ + if (object->shader_fx.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH(ShaderFxData *, fx, &object->shader_fx) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type); + if (fxi->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); + fxi->updateDepsgraph(fx, &ctx); + } + if (BKE_object_shaderfx_use_time(object, fx)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } /* Materials. */ if (object->totcol) { for (int a = 1; a <= object->totcol; a++) { @@ -1895,13 +1942,13 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) } /* Link object data evaluation node to exit operation. */ OperationKey obdata_geom_eval_key(obdata, - DEG_NODE_TYPE_GEOMETRY, - DEG_OPCODE_PLACEHOLDER, - "Geometry Eval"); + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); OperationKey obdata_geom_done_key(obdata, - DEG_NODE_TYPE_GEOMETRY, - DEG_OPCODE_PLACEHOLDER, - "Eval Done"); + DEG_NODE_TYPE_GEOMETRY, + DEG_OPCODE_PLACEHOLDER, + "Eval Done"); add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done"); @@ -1917,35 +1964,67 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) Curve *cu = (Curve *)obdata; if (cu->bevobj != NULL) { ComponentKey bevob_geom_key(&cu->bevobj->id, - DEG_NODE_TYPE_GEOMETRY); + DEG_NODE_TYPE_GEOMETRY); add_relation(bevob_geom_key, - obdata_geom_eval_key, - "Curve Bevel Geometry"); + obdata_geom_eval_key, + "Curve Bevel Geometry"); ComponentKey bevob_key(&cu->bevobj->id, - DEG_NODE_TYPE_TRANSFORM); + DEG_NODE_TYPE_TRANSFORM); add_relation(bevob_key, - obdata_geom_eval_key, - "Curve Bevel Transform"); + obdata_geom_eval_key, + "Curve Bevel Transform"); build_object(NULL, cu->bevobj); } if (cu->taperobj != NULL) { ComponentKey taperob_key(&cu->taperobj->id, - DEG_NODE_TYPE_GEOMETRY); + DEG_NODE_TYPE_GEOMETRY); add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); build_object(NULL, cu->taperobj); } if (cu->textoncurve != NULL) { ComponentKey textoncurve_key(&cu->textoncurve->id, - DEG_NODE_TYPE_GEOMETRY); + DEG_NODE_TYPE_GEOMETRY); add_relation(textoncurve_key, - obdata_geom_eval_key, - "Text on Curve"); + obdata_geom_eval_key, + "Text on Curve"); build_object(NULL, cu->textoncurve); } break; } case ID_LT: break; + case ID_GD: /* Grease Pencil */ + { + bGPdata *gpd = (bGPdata *)obdata; + + /* Geometry cache needs to be recalculated on frame change + * (e.g. to fix crashes after scrubbing the timeline when + * onion skinning is enabled, since the ghosts need to be + * re-added to the cache once scrubbing ends) + */ + TimeSourceKey time_key; + ComponentKey geometry_key(obdata, DEG_NODE_TYPE_GEOMETRY); + add_relation(time_key, + geometry_key, + "GP Frame Change"); + + /* Geometry cache also needs to be recalculated when Material + * settings change (e.g. when fill.opacity changes on/off, + * we need to rebuild the bGPDstroke->triangles caches) + */ + for (int i = 0; i < gpd->totcol; i++) { + Material *ma = gpd->mat[i]; + if ((ma != NULL) && (ma->gp_style != NULL)) { + OperationKey material_key(&ma->id, + DEG_NODE_TYPE_SHADING, + DEG_OPCODE_MATERIAL_UPDATE); + add_relation(material_key, + geometry_key, + "Material -> GP Data"); + } + } + break; + } default: BLI_assert(!"Should not happen"); break; @@ -2228,6 +2307,11 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDDepsNode *id_node if (id_type == ID_ME && comp_node->type == DEG_NODE_TYPE_GEOMETRY) { rel_flag &= ~DEPSREL_FLAG_NO_FLUSH; } + /* materials need update grease pencil objects */ + if (id_type == ID_MA) { + rel_flag &= ~DEPSREL_FLAG_NO_FLUSH; + } + /* Notes on exceptions: * - Parameters component is where drivers are living. Changing any * of the (custom) properties in the original datablock (even the diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index f069c63f138..78d1a930eb7 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -123,10 +123,6 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la if (scene->nodetree != NULL) { build_compositor(scene); } - /* Grease pencil. */ - if (scene->gpd != NULL) { - build_gpencil(scene->gpd); - } /* Masks. */ LISTBASE_FOREACH (Mask *, mask, &bmain_->mask) { build_mask(mask); diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 4229f8bf9a2..e4659a7a94d 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -100,6 +100,7 @@ void depsgraph_geometry_tag_to_component(const ID *id, case OB_FONT: case OB_LATTICE: case OB_MBALL: + case OB_GPENCIL: *component_type = DEG_NODE_TYPE_GEOMETRY; break; case OB_ARMATURE: @@ -112,11 +113,17 @@ void depsgraph_geometry_tag_to_component(const ID *id, case ID_ME: *component_type = DEG_NODE_TYPE_GEOMETRY; break; - case ID_PA: + case ID_PA: /* Particles */ return; case ID_LP: *component_type = DEG_NODE_TYPE_PARAMETERS; break; + case ID_GD: + *component_type = DEG_NODE_TYPE_GEOMETRY; + break; + case ID_PAL: /* Palettes */ + *component_type = DEG_NODE_TYPE_PARAMETERS; + break; default: break; } diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 6ec7b03501b..d672645dea0 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -123,6 +123,13 @@ set(SRC engines/workbench/solid_mode.c engines/workbench/transparent_mode.c engines/external/external_engine.c + engines/gpencil/gpencil_engine.h + engines/gpencil/gpencil_engine.c + engines/gpencil/gpencil_render.c + engines/gpencil/gpencil_cache_utils.c + engines/gpencil/gpencil_draw_utils.c + engines/gpencil/gpencil_draw_cache_impl.c + engines/gpencil/gpencil_shader_fx.c DRW_engine.h intern/DRW_render.h @@ -303,6 +310,33 @@ data_to_c_simple(modes/shaders/particle_strand_frag.glsl SRC) data_to_c_simple(modes/shaders/particle_strand_vert.glsl SRC) data_to_c_simple(modes/shaders/volume_velocity_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_fill_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_fill_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_geom.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_simple_mix_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_point_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_point_geom.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_point_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_background_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_paper_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_geom.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_edit_point_frag.glsl SRC) + +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl SRC) + + list(APPEND INC ) diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 4d4b486d247..6d8e8a69e29 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -126,6 +126,9 @@ void DRW_draw_depth_loop( struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d); +/* grease pencil render */ +void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph); + /* This is here because GPUViewport needs it */ void DRW_pass_free(struct DRWPass *pass); struct DRWInstanceDataList *DRW_instance_data_list_create(void); diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c new file mode 100644 index 00000000000..4e01c42d33d --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -0,0 +1,296 @@ +/* + * Copyright 2017, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Antonio Vazquez + * + */ + +/** \file blender/draw/engines/gpencil/gpencil_cache_utils.c + * \ingroup draw + */ + +#include "DRW_render.h" + +#include "BKE_global.h" + +#include "ED_gpencil.h" +#include "ED_view3d.h" + +#include "DNA_gpencil_types.h" +#include "DNA_view3d_types.h" + +#include "gpencil_engine.h" + +#include "draw_cache_impl.h" + + /* add a gpencil object to cache to defer drawing */ +tGPencilObjectCache *gpencil_object_cache_add(tGPencilObjectCache *cache_array, Object *ob, bool is_temp, + int *gp_cache_size, int *gp_cache_used) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + tGPencilObjectCache *cache_elem = NULL; + RegionView3D *rv3d = draw_ctx->rv3d; + tGPencilObjectCache *p = NULL; + + /* By default a cache is created with one block with a predefined number of free slots, + if the size is not enough, the cache is reallocated adding a new block of free slots. + This is done in order to keep cache small */ + if (*gp_cache_used + 1 > *gp_cache_size) { + if ((*gp_cache_size == 0) || (cache_array == NULL)) { + p = MEM_callocN(sizeof(struct tGPencilObjectCache) * GP_CACHE_BLOCK_SIZE, "tGPencilObjectCache"); + *gp_cache_size = GP_CACHE_BLOCK_SIZE; + } + else { + *gp_cache_size += GP_CACHE_BLOCK_SIZE; + p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size); + } + cache_array = p; + } + + /* zero out all pointers */ + cache_elem = &cache_array[*gp_cache_used]; + memset(cache_elem, 0, sizeof(*cache_elem)); + + /* save object */ + cache_elem->ob = ob; + cache_elem->temp_ob = is_temp; + cache_elem->idx = *gp_cache_used; + + cache_elem->init_grp = 0; + cache_elem->end_grp = -1; + + /* calculate zdepth from point of view */ + float zdepth = 0.0; + if (rv3d) { + if (rv3d->is_persp) { + zdepth = ED_view3d_calc_zfac(rv3d, ob->loc, NULL); + } + else { + zdepth = -dot_v3v3(rv3d->viewinv[2], ob->loc); + } + } + else { + /* In render mode, rv3d is not available, so use the distance to camera. + * The real distance is not important, but the relative distance to the camera plane + * in order to sort by z_depth of the objects + */ + float vn[3] = { 0.0f, 0.0f, -1.0f }; /* always face down */ + float plane_cam[4]; + struct Object *camera = draw_ctx->scene->camera; + if (camera) { + mul_m4_v3(camera->obmat, vn); + normalize_v3(vn); + plane_from_point_normal_v3(plane_cam, camera->loc, vn); + zdepth = dist_squared_to_plane_v3(ob->loc, plane_cam); + } + } + cache_elem->zdepth = zdepth; + /* increase slots used in cache */ + (*gp_cache_used)++; + + return cache_array; +} + +/* get current cache data */ +static GpencilBatchCache *gpencil_batch_get_element(Object *ob) +{ + bGPdata *gpd = ob->data; + if (gpd->runtime.batch_cache_data == NULL) { + gpd->runtime.batch_cache_data = BLI_ghash_str_new("GP batch cache data"); + return NULL; + } + + return (GpencilBatchCache *) BLI_ghash_lookup(gpd->runtime.batch_cache_data, ob->id.name); +} + +/* verify if cache is valid */ +static bool gpencil_batch_cache_valid(Object *ob, bGPdata *gpd, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_get_element(ob); + + if (cache == NULL) { + return false; + } + + cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); + + if (cfra != cache->cache_frame) { + return false; + } + + if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) { + return false; + } + + if (cache->is_editmode) { + return false; + } + + if (cache->is_dirty) { + return false; + } + + return true; +} + +/* resize the cache to the number of slots */ +static void gpencil_batch_cache_resize(GpencilBatchCache *cache, int slots) +{ + cache->cache_size = slots; + cache->batch_stroke = MEM_recallocN(cache->batch_stroke, sizeof(struct Gwn_Batch *) * slots); + cache->batch_fill = MEM_recallocN(cache->batch_fill, sizeof(struct Gwn_Batch *) * slots); + cache->batch_edit = MEM_recallocN(cache->batch_edit, sizeof(struct Gwn_Batch *) * slots); + cache->batch_edlin = MEM_recallocN(cache->batch_edlin, sizeof(struct Gwn_Batch *) * slots); +} + +/* check size and increase if no free slots */ +void gpencil_batch_cache_check_free_slots(Object *ob) +{ + GpencilBatchCache *cache = gpencil_batch_get_element(ob); + + /* the memory is reallocated by chunks, not for one slot only to improve speed */ + if (cache->cache_idx >= cache->cache_size) { + cache->cache_size += GPENCIL_MIN_BATCH_SLOTS_CHUNK; + gpencil_batch_cache_resize(cache, cache->cache_size); + } +} + +/* cache init */ +static void gpencil_batch_cache_init(Object *ob, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_get_element(ob); + bGPdata *gpd = ob->data; + + if (G.debug_value >= 664) { + printf("gpencil_batch_cache_init: %s\n", ob->id.name); + } + + if (!cache) { + cache = MEM_callocN(sizeof(*cache), __func__); + BLI_ghash_insert(gpd->runtime.batch_cache_data, ob->id.name, cache); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->cache_size = GPENCIL_MIN_BATCH_SLOTS_CHUNK; + cache->batch_stroke = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Stroke"); + cache->batch_fill = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Fill"); + cache->batch_edit = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edit"); + cache->batch_edlin = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edlin"); + + cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); + gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; + + cache->cache_idx = 0; + cache->is_dirty = true; + cache->cache_frame = cfra; +} + +/* clear cache */ +static void gpencil_batch_cache_clear(GpencilBatchCache *cache, bGPdata *gpd) +{ + if (!cache) { + return; + } + + if (cache->cache_size == 0) { + return; + } + + if (G.debug_value >= 664) { + printf("gpencil_batch_cache_clear: %s\n", gpd->id.name); + } + + if (cache->cache_size > 0) { + for (int i = 0; i < cache->cache_size; i++) { + GPU_BATCH_DISCARD_SAFE(cache->batch_stroke[i]); + GPU_BATCH_DISCARD_SAFE(cache->batch_fill[i]); + GPU_BATCH_DISCARD_SAFE(cache->batch_edit[i]); + GPU_BATCH_DISCARD_SAFE(cache->batch_edlin[i]); + } + MEM_SAFE_FREE(cache->batch_stroke); + MEM_SAFE_FREE(cache->batch_fill); + MEM_SAFE_FREE(cache->batch_edit); + MEM_SAFE_FREE(cache->batch_edlin); + } + + MEM_SAFE_FREE(cache); +} + +/* get cache */ +GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra) +{ + bGPdata *gpd = ob->data; + + if (!gpencil_batch_cache_valid(ob, gpd, cfra)) { + if (G.debug_value >= 664) { + printf("gpencil_batch_cache: %s\n", gpd->id.name); + } + + GpencilBatchCache *cache = gpencil_batch_get_element(ob); + if (cache) { + gpencil_batch_cache_clear(cache, gpd); + BLI_ghash_remove(gpd->runtime.batch_cache_data, ob->id.name, NULL, NULL); + } + gpencil_batch_cache_init(ob, cfra); + } + + return gpencil_batch_get_element(ob); +} + +/* set cache as dirty */ +void DRW_gpencil_batch_cache_dirty(bGPdata *gpd) +{ + if (gpd->runtime.batch_cache_data == NULL) { + return; + } + + GHashIterator *ihash = BLI_ghashIterator_new(gpd->runtime.batch_cache_data); + while (!BLI_ghashIterator_done(ihash)) { + GpencilBatchCache *cache = (GpencilBatchCache *)BLI_ghashIterator_getValue(ihash); + if (cache) { + cache->is_dirty = true; + } + BLI_ghashIterator_step(ihash); + } + BLI_ghashIterator_free(ihash); +} + +/* free batch cache */ +void DRW_gpencil_batch_cache_free(bGPdata *gpd) +{ + if (gpd->runtime.batch_cache_data == NULL) { + return; + } + + GHashIterator *ihash = BLI_ghashIterator_new(gpd->runtime.batch_cache_data); + while (!BLI_ghashIterator_done(ihash)) { + GpencilBatchCache *cache = (GpencilBatchCache *)BLI_ghashIterator_getValue(ihash); + if (cache) { + gpencil_batch_cache_clear(cache, gpd); + } + BLI_ghashIterator_step(ihash); + } + BLI_ghashIterator_free(ihash); + + /* free hash */ + if (gpd->runtime.batch_cache_data) { + BLI_ghash_free(gpd->runtime.batch_cache_data, NULL, NULL); + gpd->runtime.batch_cache_data = NULL; + } +} diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c new file mode 100644 index 00000000000..dd5db85f3f4 --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c @@ -0,0 +1,739 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file draw/engines/gpencil/gpencil_draw_cache_impl.c + * \ingroup draw + */ + +#include "BLI_polyfill_2d.h" +#include "BLI_math_color.h" + +#include "DNA_meshdata_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_gpencil.h" +#include "BKE_action.h" + +#include "DRW_render.h" + +#include "GPU_immediate.h" +#include "GPU_draw.h" + +#include "ED_gpencil.h" +#include "ED_view3d.h" + +#include "UI_resources.h" + +#include "gpencil_engine.h" + +/* Helper to add stroke point to vbo */ +static void gpencil_set_stroke_point( + GPUVertBuf *vbo, float matrix[4][4], const bGPDspoint *pt, int idx, + uint pos_id, uint color_id, + uint thickness_id, uint uvdata_id, short thickness, + const float ink[4]) +{ + float viewfpt[3]; + + float alpha = ink[3] * pt->strength; + CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); + float col[4]; + ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha); + + GPU_vertbuf_attr_set(vbo, color_id, idx, col); + + /* transfer both values using the same shader variable */ + float uvdata[2] = { pt->uv_fac, pt->uv_rot }; + GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata); + + /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */ + mul_v3_m4v3(viewfpt, matrix, &pt->x); + float thick = max_ff(pt->pressure * thickness, 1.0f); + GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick); + + GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); +} + +/* Helper to add a new fill point and texture coordinates to vertex buffer */ +static void gpencil_set_fill_point( + GPUVertBuf *vbo, int idx, bGPDspoint *pt, const float fcolor[4], float uv[2], + uint pos_id, uint color_id, uint text_id) +{ + GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); + GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); + GPU_vertbuf_attr_set(vbo, text_id, idx, uv); +} + +/* create batch geometry data for points stroke shader */ +GPUBatch *DRW_gpencil_get_point_geom(bGPDstroke *gps, short thickness, const float ink[4]) +{ + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id, size_id, uvdata_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + size_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, gps->totpoints); + + /* draw stroke curve */ + const bGPDspoint *pt = gps->points; + int idx = 0; + float alpha; + float col[4]; + + for (int i = 0; i < gps->totpoints; i++, pt++) { + /* set point */ + alpha = ink[3] * pt->strength; + CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); + ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha); + + float thick = max_ff(pt->pressure * thickness, 1.0f); + + GPU_vertbuf_attr_set(vbo, color_id, idx, col); + GPU_vertbuf_attr_set(vbo, size_id, idx, &thick); + + /* transfer both values using the same shader variable */ + float uvdata[2] = { pt->uv_fac, pt->uv_rot }; + GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata); + + GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); + idx++; + } + + return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +/* create batch geometry data for stroke shader */ +GPUBatch *DRW_gpencil_get_stroke_geom(bGPDframe *gpf, bGPDstroke *gps, short thickness, const float ink[4]) +{ + bGPDspoint *points = gps->points; + int totpoints = gps->totpoints; + /* if cyclic needs more vertex */ + int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0; + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id, thickness_id, uvdata_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, totpoints + cyclic_add + 2); + + /* draw stroke curve */ + const bGPDspoint *pt = points; + int idx = 0; + for (int i = 0; i < totpoints; i++, pt++) { + /* first point for adjacency (not drawn) */ + if (i == 0) { + if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { + gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[totpoints - 1], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + idx++; + } + else { + gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[1], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + idx++; + } + } + /* set point */ + gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + idx++; + } + + if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { + /* draw line to first point to complete the cycle */ + gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[0], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + idx++; + /* now add adjacency point (not drawn) */ + gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[1], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + idx++; + } + /* last adjacency point (not drawn) */ + else { + gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[totpoints - 2], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + } + + return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +/* create batch geometry data for current buffer stroke shader */ +GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, float matrix[4][4], short thickness) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + View3D *v3d = draw_ctx->v3d; + ARegion *ar = draw_ctx->ar; + RegionView3D *rv3d = draw_ctx->rv3d; + ToolSettings *ts = scene->toolsettings; + Object *ob = draw_ctx->obact; + + tGPspoint *points = gpd->runtime.sbuffer; + int totpoints = gpd->runtime.sbuffer_size; + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id, thickness_id, uvdata_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, totpoints + 2); + + /* draw stroke curve */ + const tGPspoint *tpt = points; + bGPDspoint pt, pt2; + int idx = 0; + + /* get origin to reproject point */ + float origin[3]; + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); + + for (int i = 0; i < totpoints; i++, tpt++) { + ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); + ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); + + /* first point for adjacency (not drawn) */ + if (i == 0) { + if (totpoints > 1) { + ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2); + gpencil_set_stroke_point(vbo, matrix, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + } + else { + gpencil_set_stroke_point(vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + } + idx++; + } + /* set point */ + gpencil_set_stroke_point(vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + idx++; + } + + /* last adjacency point (not drawn) */ + if (totpoints > 2) { + ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2); + gpencil_set_stroke_point(vbo, matrix, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + } + else { + gpencil_set_stroke_point(vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + } + + return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +/* create batch geometry data for current buffer point shader */ +GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, float matrix[4][4], short thickness) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + View3D *v3d = draw_ctx->v3d; + ARegion *ar = draw_ctx->ar; + RegionView3D *rv3d = draw_ctx->rv3d; + ToolSettings *ts = scene->toolsettings; + Object *ob = draw_ctx->obact; + + tGPspoint *points = gpd->runtime.sbuffer; + int totpoints = gpd->runtime.sbuffer_size; + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id, thickness_id, uvdata_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, totpoints); + + /* draw stroke curve */ + const tGPspoint *tpt = points; + bGPDspoint pt; + int idx = 0; + + /* get origin to reproject point */ + float origin[3]; + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); + + for (int i = 0; i < totpoints; i++, tpt++) { + ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); + ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); + + /* set point */ + gpencil_set_stroke_point(vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, + thickness, gpd->runtime.scolor); + idx++; + } + + return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +/* create batch geometry data for current buffer fill shader */ +GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd) +{ + if (gpd == NULL) { + return NULL; + } + + const tGPspoint *points = gpd->runtime.sbuffer; + int totpoints = gpd->runtime.sbuffer_size; + if (totpoints < 3) { + return NULL; + } + + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + View3D *v3d = draw_ctx->v3d; + ARegion *ar = draw_ctx->ar; + ToolSettings *ts = scene->toolsettings; + Object *ob = draw_ctx->obact; + + /* get origin to reproject point */ + float origin[3]; + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, origin); + + int tot_triangles = totpoints - 2; + /* allocate memory for temporary areas */ + uint (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__); + float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__); + + /* Convert points to array and triangulate + * Here a cache is not used because while drawing the information changes all the time, so the cache + * would be recalculated constantly, so it is better to do direct calculation for each function call + */ + for (int i = 0; i < totpoints; i++) { + const tGPspoint *pt = &points[i]; + points2d[i][0] = pt->x; + points2d[i][1] = pt->y; + } + BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles); + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + + /* draw triangulation data */ + if (tot_triangles > 0) { + GPU_vertbuf_data_alloc(vbo, tot_triangles * 3); + + const tGPspoint *tpt; + bGPDspoint pt; + + int idx = 0; + for (int i = 0; i < tot_triangles; i++) { + for (int j = 0; j < 3; j++) { + tpt = &points[tmp_triangles[i][j]]; + ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); + GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x); + GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill); + idx++; + } + } + } + + /* clear memory */ + if (tmp_triangles) { + MEM_freeN(tmp_triangles); + } + if (points2d) { + MEM_freeN(points2d); + } + + return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +/* create batch geometry data for stroke shader */ +GPUBatch *DRW_gpencil_get_fill_geom(Object *ob, bGPDstroke *gps, const float color[4]) +{ + BLI_assert(gps->totpoints >= 3); + + /* Calculate triangles cache for filling area (must be done only after changes) */ + if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { + DRW_gpencil_triangulate_stroke_fill(gps); + ED_gpencil_calc_stroke_uv(ob, gps); + } + + BLI_assert(gps->tot_triangles >= 1); + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id, text_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + text_id = GPU_vertformat_attr_add(&format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, gps->tot_triangles * 3); + + /* Draw all triangles for filling the polygon (cache must be calculated before) */ + bGPDtriangle *stroke_triangle = gps->triangles; + int idx = 0; + for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { + for (int j = 0; j < 3; j++) { + gpencil_set_fill_point( + vbo, idx, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j], + pos_id, color_id, text_id); + idx++; + } + } + + return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +/* Draw selected verts for strokes being edited */ +GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob->data; + bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + + int vgindex = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, vgindex)) { + vgindex = -1; + } + + /* Get size of verts: + * - The selected state needs to be larger than the unselected state so that + * they stand out more. + * - We use the theme setting for size of the unselected verts + */ + float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); + float vsize; + if ((int)bsize > 8) { + vsize = 10.0f; + bsize = 8.0f; + } + else { + vsize = bsize + 2; + } + + /* for now, we assume that the base color of the points is not too close to the real color */ + float selectColor[4]; + UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); + selectColor[3] = alpha; + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id, size_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, gps->totpoints); + + /* Draw start and end point differently if enabled stroke direction hint */ + bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1); + + /* Draw all the stroke points (selected or not) */ + bGPDspoint *pt = gps->points; + MDeformVert *dvert = gps->dvert; + + int idx = 0; + float fcolor[4]; + float fsize = 0; + for (int i = 0; i < gps->totpoints; i++, pt++, dvert++) { + /* weight paint */ + if (is_weight_paint) { + float weight = BKE_gpencil_vgroup_use_index(dvert, vgindex); + CLAMP(weight, 0.0f, 1.0f); + float hue = 2.0f * (1.0f - weight) / 3.0f; + hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]); + selectColor[3] = 1.0f; + copy_v4_v4(fcolor, selectColor); + fsize = vsize; + } + else { + if (show_direction_hint && i == 0) { + /* start point in green bigger */ + ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f); + fsize = vsize + 4; + } + else if (show_direction_hint && (i == gps->totpoints - 1)) { + /* end point in red smaller */ + ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f); + fsize = vsize + 1; + } + else if (pt->flag & GP_SPOINT_SELECT) { + copy_v4_v4(fcolor, selectColor); + fsize = vsize; + } + else { + copy_v4_v4(fcolor, gps->runtime.tmp_stroke_rgba); + fsize = bsize; + } + } + + GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); + GPU_vertbuf_attr_set(vbo, size_id, idx, &fsize); + GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); + idx++; + } + + return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +/* Draw lines for strokes being edited */ +GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED(dflag)) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob->data; + bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + + int vgindex = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, vgindex)) { + vgindex = -1; + } + + float selectColor[4]; + UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); + selectColor[3] = alpha; + float linecolor[4]; + copy_v4_v4(linecolor, gpd->line_color); + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, gps->totpoints); + + /* Draw all the stroke lines (selected or not) */ + bGPDspoint *pt = gps->points; + + /* GPXX: for some converted files, this struct could be null + * maybe we can remove this and move to versioning code after + * merge */ + if (gps->dvert == NULL) { + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); + } + + MDeformVert *dvert = gps->dvert; + + int idx = 0; + float fcolor[4]; + for (int i = 0; i < gps->totpoints; i++, pt++, dvert++) { + /* weight paint */ + if (is_weight_paint) { + float weight = BKE_gpencil_vgroup_use_index(dvert, vgindex); + CLAMP(weight, 0.0f, 1.0f); + float hue = 2.0f * (1.0f - weight) / 3.0f; + hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]); + selectColor[3] = 1.0f; + copy_v4_v4(fcolor, selectColor); + } + else { + if (pt->flag & GP_SPOINT_SELECT) { + copy_v4_v4(fcolor, selectColor); + } + else { + copy_v4_v4(fcolor, linecolor); + } + } + + GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); + GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); + idx++; + } + + return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); +} + +static void set_grid_point(GPUVertBuf *vbo, int idx, float col_grid[4], + uint pos_id, uint color_id, + float v1, float v2, int axis) +{ + GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid); + + float pos[3]; + /* Set the grid in the selected axis (default is always Y axis) */ + if (axis & V3D_GP_GRID_AXIS_X) { + pos[0] = 0.0f; + pos[1] = v1; + pos[2] = v2; + } + else if (axis & V3D_GP_GRID_AXIS_Z) { + pos[0] = v1; + pos[1] = v2; + pos[2] = 0.0f; + } + else + { + pos[0] = v1; + pos[1] = 0.0f; + pos[2] = v2; + } + + + + GPU_vertbuf_attr_set(vbo, pos_id, idx, pos); +} + +/* Draw grid lines */ +GPUBatch *DRW_gpencil_get_grid(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + View3D *v3d = draw_ctx->v3d; + + float col_grid[4]; + + /* verify we have something to draw and valid values */ + if (v3d->overlay.gpencil_grid_lines < 1) { + v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; + } + + if (v3d->overlay.gpencil_grid_scale == 0.0f) { + v3d->overlay.gpencil_grid_scale = 1.0f; + } + + if (v3d->overlay.gpencil_grid_opacity < 0.1f) { + v3d->overlay.gpencil_grid_opacity = 0.1f; + } + + UI_GetThemeColor3fv(TH_GRID, col_grid); + col_grid[3] = v3d->overlay.gpencil_grid_opacity; + + /* if use locked axis, copy value */ + int axis = v3d->overlay.gpencil_grid_axis; + if ((v3d->overlay.gpencil_grid_axis & V3D_GP_GRID_AXIS_LOCK) == 0) { + + axis = v3d->overlay.gpencil_grid_axis; + } + else { + switch (ts->gp_sculpt.lock_axis) { + case GP_LOCKAXIS_X: + { + axis = V3D_GP_GRID_AXIS_X; + break; + } + case GP_LOCKAXIS_NONE: + case GP_LOCKAXIS_Y: + { + axis = V3D_GP_GRID_AXIS_Y; + break; + } + case GP_LOCKAXIS_Z: + { + axis = V3D_GP_GRID_AXIS_Z; + break; + } + } + } + + const char *grid_unit = NULL; + const int gridlines = v3d->overlay.gpencil_grid_lines; + const float grid_scale = v3d->overlay.gpencil_grid_scale * ED_scene_grid_scale(scene, &grid_unit); + const float grid = grid_scale; + const float space = (grid_scale / gridlines); + + const uint vertex_len = 2 * (gridlines * 4 + 2); + + static GPUVertFormat format = { 0 }; + static uint pos_id, color_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, vertex_len); + + int idx = 0; + + for (int a = 1; a <= gridlines; a++) { + const float line = a * space; + + set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, -line, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, -line, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, +line, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, +line, axis); + idx++; + + set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line, -grid, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, -line, +grid, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line, -grid, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, +line, +grid, axis); + idx++; + } + /* center lines */ + set_grid_point(vbo, idx, col_grid, pos_id, color_id, -grid, 0.0f, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, +grid, 0.0f, axis); + idx++; + + set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f, -grid, axis); + idx++; + set_grid_point(vbo, idx, col_grid, pos_id, color_id, 0.0f, +grid, axis); + idx++; + + return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO); +} diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c new file mode 100644 index 00000000000..76cb1405a71 --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -0,0 +1,1336 @@ +/* + * Copyright 2017, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Antonio Vazquez + * + */ + +/** \file blender/draw/engines/gpencil/gpencil_draw_utils.c + * \ingroup draw + */ + +#include "BLI_polyfill_2d.h" + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "BKE_brush.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_image.h" +#include "BKE_material.h" + +#include "ED_gpencil.h" +#include "ED_view3d.h" + +#include "DNA_gpencil_types.h" +#include "DNA_material_types.h" +#include "DNA_view3d_types.h" +#include "DNA_gpencil_modifier_types.h" + + /* If builtin shaders are needed */ +#include "GPU_shader.h" +#include "GPU_texture.h" + +/* For EvaluationContext... */ +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "IMB_imbuf_types.h" + +#include "gpencil_engine.h" + +/* fill type to communicate to shader */ +#define SOLID 0 +#define GRADIENT 1 +#define RADIAL 2 +#define CHESS 3 +#define TEXTURE 4 +#define PATTERN 5 + +/* Helper for doing all the checks on whether a stroke can be drawn */ +static bool gpencil_can_draw_stroke(struct MaterialGPencilStyle *gp_style, const bGPDstroke *gps, + const bool onion, const bool is_mat_preview) +{ + /* skip stroke if it doesn't have any valid data */ + if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) + return false; + + /* if mat preview render always visible */ + if (is_mat_preview) { + return true; + } + + /* check if the color is visible */ + if ((gp_style == NULL) || + (gp_style->flag & GP_STYLE_COLOR_HIDE) || + (onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) + { + return false; + } + + /* stroke can be drawn */ + return true; +} + +/* calc bounding box in 2d using flat projection data */ +static void gpencil_calc_2d_bounding_box( + const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand) +{ + minv[0] = points2d[0][0]; + minv[1] = points2d[0][1]; + maxv[0] = points2d[0][0]; + maxv[1] = points2d[0][1]; + + for (int i = 1; i < totpoints; i++) { + /* min */ + if (points2d[i][0] < minv[0]) { + minv[0] = points2d[i][0]; + } + if (points2d[i][1] < minv[1]) { + minv[1] = points2d[i][1]; + } + /* max */ + if (points2d[i][0] > maxv[0]) { + maxv[0] = points2d[i][0]; + } + if (points2d[i][1] > maxv[1]) { + maxv[1] = points2d[i][1]; + } + } + /* If not expanded, use a perfect square */ + if (expand == false) { + if (maxv[0] > maxv[1]) { + maxv[1] = maxv[0]; + } + else { + maxv[0] = maxv[1]; + } + } +} + +/* calc texture coordinates using flat projected points */ +static void gpencil_calc_stroke_fill_uv( + const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], float(*r_uv)[2]) +{ + float d[2]; + d[0] = maxv[0] - minv[0]; + d[1] = maxv[1] - minv[1]; + for (int i = 0; i < totpoints; i++) { + r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0]; + r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1]; + } +} + +/* Get points of stroke always flat to view not affected by camera view or view position */ +static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction) +{ + const bGPDspoint *pt0 = &points[0]; + const bGPDspoint *pt1 = &points[1]; + const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)]; + + float locx[3]; + float locy[3]; + float loc3[3]; + float normal[3]; + + /* local X axis (p0 -> p1) */ + sub_v3_v3v3(locx, &pt1->x, &pt0->x); + + /* point vector at 3/4 */ + sub_v3_v3v3(loc3, &pt3->x, &pt0->x); + + /* vector orthogonal to polygon plane */ + cross_v3_v3v3(normal, locx, loc3); + + /* local Y axis (cross to normal/x axis) */ + cross_v3_v3v3(locy, normal, locx); + + /* Normalize vectors */ + normalize_v3(locx); + normalize_v3(locy); + + /* Get all points in local space */ + for (int i = 0; i < totpoints; i++) { + const bGPDspoint *pt = &points[i]; + float loc[3]; + + /* Get local space using first point as origin */ + sub_v3_v3v3(loc, &pt->x, &pt0->x); + + points2d[i][0] = dot_v3v3(loc, locx); + points2d[i][1] = dot_v3v3(loc, locy); + } + + /* Concave (-1), Convex (1), or Autodetect (0)? */ + *r_direction = (int)locy[2]; +} + +/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */ +void DRW_gpencil_triangulate_stroke_fill(bGPDstroke *gps) +{ + BLI_assert(gps->totpoints >= 3); + + /* allocate memory for temporary areas */ + gps->tot_triangles = gps->totpoints - 2; + uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); + float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points"); + float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data"); + + int direction = 0; + + /* convert to 2d and triangulate */ + gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); + BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles); + + /* calc texture coordinates automatically */ + float minv[2]; + float maxv[2]; + /* first needs bounding box data */ + gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv, false); + /* calc uv data */ + gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv); + + /* Number of triangles */ + gps->tot_triangles = gps->totpoints - 2; + /* save triangulation data in stroke cache */ + if (gps->tot_triangles > 0) { + if (gps->triangles == NULL) { + gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation"); + } + else { + gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles); + } + + for (int i = 0; i < gps->tot_triangles; i++) { + bGPDtriangle *stroke_triangle = &gps->triangles[i]; + memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); + /* copy texture coordinates */ + copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]); + copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]); + copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]); + } + } + else { + /* No triangles needed - Free anything allocated previously */ + if (gps->triangles) + MEM_freeN(gps->triangles); + + gps->triangles = NULL; + } + + /* disable recalculation flag */ + if (gps->flag & GP_STROKE_RECALC_CACHES) { + gps->flag &= ~GP_STROKE_RECALC_CACHES; + } + + /* clear memory */ + MEM_SAFE_FREE(tmp_triangles); + MEM_SAFE_FREE(points2d); + MEM_SAFE_FREE(uv); +} + +/* recalc the internal geometry caches for fill and uvs */ +static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps) +{ + if (gps->flag & GP_STROKE_RECALC_CACHES) { + /* Calculate triangles cache for filling area (must be done only after changes) */ + if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) { + if ((gps->totpoints > 2) && + ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0))) + { + DRW_gpencil_triangulate_stroke_fill(gps); + } + } + + /* calc uv data along the stroke */ + ED_gpencil_calc_stroke_uv(ob, gps); + + /* clear flag */ + gps->flag &= ~GP_STROKE_RECALC_CACHES; + } +} + +/* create shading group for filling */ +static DRWShadingGroup *DRW_gpencil_shgroup_fill_create( + GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, + GPUShader *shader, bGPdata *gpd, MaterialGPencilStyle *gp_style, int id) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + + /* e_data.gpencil_fill_sh */ + DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + + DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1); + + /* set style type */ + switch (gp_style->fill_style) { + case GP_STYLE_FILL_STYLE_SOLID: + stl->shgroups[id].fill_style = SOLID; + break; + case GP_STYLE_FILL_STYLE_GRADIENT: + if (gp_style->gradient_type == GP_STYLE_GRADIENT_LINEAR) { + stl->shgroups[id].fill_style = GRADIENT; + } + else { + stl->shgroups[id].fill_style = RADIAL; + } + break; + case GP_STYLE_FILL_STYLE_CHESSBOARD: + stl->shgroups[id].fill_style = CHESS; + break; + case GP_STYLE_FILL_STYLE_TEXTURE: + if (gp_style->flag & GP_STYLE_FILL_PATTERN) { + stl->shgroups[id].fill_style = PATTERN; + } + else { + stl->shgroups[id].fill_style = TEXTURE; + } + break; + default: + stl->shgroups[id].fill_style = GP_STYLE_FILL_STYLE_SOLID; + break; + } + DRW_shgroup_uniform_int(grp, "fill_type", &stl->shgroups[id].fill_style, 1); + + DRW_shgroup_uniform_float(grp, "mix_factor", &gp_style->mix_factor, 1); + + DRW_shgroup_uniform_float(grp, "gradient_angle", &gp_style->gradient_angle, 1); + DRW_shgroup_uniform_float(grp, "gradient_radius", &gp_style->gradient_radius, 1); + DRW_shgroup_uniform_float(grp, "pattern_gridsize", &gp_style->pattern_gridsize, 1); + DRW_shgroup_uniform_vec2(grp, "gradient_scale", gp_style->gradient_scale, 1); + DRW_shgroup_uniform_vec2(grp, "gradient_shift", gp_style->gradient_shift, 1); + + DRW_shgroup_uniform_float(grp, "texture_angle", &gp_style->texture_angle, 1); + DRW_shgroup_uniform_vec2(grp, "texture_scale", gp_style->texture_scale, 1); + DRW_shgroup_uniform_vec2(grp, "texture_offset", gp_style->texture_offset, 1); + DRW_shgroup_uniform_float(grp, "texture_opacity", &gp_style->texture_opacity, 1); + + stl->shgroups[id].texture_mix = gp_style->flag & GP_STYLE_COLOR_TEX_MIX ? 1 : 0; + DRW_shgroup_uniform_int(grp, "texture_mix", &stl->shgroups[id].texture_mix, 1); + + stl->shgroups[id].texture_flip = gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 0; + DRW_shgroup_uniform_int(grp, "texture_flip", &stl->shgroups[id].texture_flip, 1); + + DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1); + /* image texture */ + if ((gp_style->flag & GP_STYLE_COLOR_TEX_MIX) || + (gp_style->fill_style & GP_STYLE_FILL_STYLE_TEXTURE)) + { + ImBuf *ibuf; + Image *image = gp_style->ima; + ImageUser iuser = { NULL }; + void *lock; + + iuser.ok = true; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf == NULL || ibuf->rect == NULL) { + BKE_image_release_ibuf(image, ibuf, NULL); + } + else { + GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, GL_TEXTURE_2D, true, 0.0); + DRW_shgroup_uniform_texture(grp, "myTexture", texture); + + stl->shgroups[id].texture_clamp = gp_style->flag & GP_STYLE_COLOR_TEX_CLAMP ? 1 : 0; + DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1); + + BKE_image_release_ibuf(image, ibuf, NULL); + } + } + else { + /* if no texture defined, need a blank texture to avoid errors in draw manager */ + DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture); + stl->shgroups[id].texture_clamp = 0; + DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1); + } + + return grp; +} + +/* create shading group for strokes */ +DRWShadingGroup *DRW_gpencil_shgroup_stroke_create( + GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob, + bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const float *viewport_size = DRW_viewport_size_get(); + + /* e_data.gpencil_stroke_sh */ + DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + + DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1); + + DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(grp, "pixelsize", &U.pixelsize, 1); + + /* avoid wrong values */ + if ((gpd) && (gpd->pixfactor == 0)) { + gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; + } + + /* object scale and depth */ + if ((ob) && (id > -1)) { + stl->shgroups[id].obj_scale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f; + DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1); + stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS)); + DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1); + + stl->shgroups[id].stroke_style = gp_style->stroke_style; + stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID; + if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) { + stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE; + if (gp_style->flag & GP_STYLE_STROKE_PATTERN) { + stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN; + } + } + DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1); + DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1); + } + else { + stl->storage->obj_scale = 1.0f; + stl->storage->keep_size = 0; + stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR; + DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1); + DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1); + DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1); + if (gpd) { + DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1); + } + else { + DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1); + } + } + + if ((gpd) && (id > -1)) { + DRW_shgroup_uniform_int(grp, "xraymode", (const int *) &gpd->xray_mode, 1); + } + else { + /* for drawing always on front */ + DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1); + } + + /* image texture for pattern */ + if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) { + ImBuf *ibuf; + Image *image = gp_style->sima; + ImageUser iuser = { NULL }; + void *lock; + + iuser.ok = true; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf == NULL || ibuf->rect == NULL) { + BKE_image_release_ibuf(image, ibuf, NULL); + } + else { + GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true, 0.0f); + DRW_shgroup_uniform_texture(grp, "myTexture", texture); + + BKE_image_release_ibuf(image, ibuf, NULL); + } + } + else { + /* if no texture defined, need a blank texture to avoid errors in draw manager */ + DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture); + } + + return grp; +} + +/* create shading group for volumetrics */ +static DRWShadingGroup *DRW_gpencil_shgroup_point_create( + GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob, + bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const float *viewport_size = DRW_viewport_size_get(); + + /* e_data.gpencil_stroke_sh */ + DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); + + DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1); + DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(grp, "pixelsize", &U.pixelsize, 1); + + /* avoid wrong values */ + if ((gpd) && (gpd->pixfactor == 0)) { + gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; + } + + /* object scale and depth */ + if ((ob) && (id > -1)) { + stl->shgroups[id].obj_scale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f; + DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1); + stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS)); + DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1); + + stl->shgroups[id].mode = gp_style->mode; + stl->shgroups[id].stroke_style = gp_style->stroke_style; + stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID; + if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) { + stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE; + if (gp_style->flag & GP_STYLE_STROKE_PATTERN) { + stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN; + } + } + DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1); + DRW_shgroup_uniform_int(grp, "mode", &stl->shgroups[id].mode, 1); + DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1); + } + else { + stl->storage->obj_scale = 1.0f; + stl->storage->keep_size = 0; + stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR; + stl->storage->mode = gp_style->mode; + DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1); + DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1); + DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1); + DRW_shgroup_uniform_int(grp, "mode", &stl->storage->mode, 1); + if (gpd) { + DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1); + } + else { + DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1); + } + } + + if (gpd) { + DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&gpd->xray_mode, 1); + } + else { + /* for drawing always on front */ + DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1); + } + + /* image texture */ + if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) { + ImBuf *ibuf; + Image *image = gp_style->sima; + ImageUser iuser = { NULL }; + void *lock; + + iuser.ok = true; + + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf == NULL || ibuf->rect == NULL) { + BKE_image_release_ibuf(image, ibuf, NULL); + } + else { + GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, GL_TEXTURE_2D, true, 0.0f); + DRW_shgroup_uniform_texture(grp, "myTexture", texture); + + BKE_image_release_ibuf(image, ibuf, NULL); + } + } + else { + /* if no texture defined, need a blank texture to avoid errors in draw manager */ + DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture); + } + + return grp; +} + +/* add fill shading group to pass */ +static void gpencil_add_fill_shgroup( + GpencilBatchCache *cache, DRWShadingGroup *fillgrp, + Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, + const float tintcolor[4], const bool onion, const bool custonion) +{ + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + if (gps->totpoints >= 3) { + float tfill[4]; + /* set color using material, tint color and opacity */ + interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]); + tfill[3] = gps->runtime.tmp_fill_rgba[3] * gpl->opacity; + if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) { + const float *color; + if (!onion) { + color = tfill; + } + else { + if (custonion) { + color = tintcolor; + } + else { + ARRAY_SET_ITEMS(tfill, UNPACK3(gps->runtime.tmp_fill_rgba), tintcolor[3]); + color = tfill; + } + } + if (cache->is_dirty) { + gpencil_batch_cache_check_free_slots(ob); + cache->batch_fill[cache->cache_idx] = DRW_gpencil_get_fill_geom(ob, gps, color); + } + DRW_shgroup_call_add(fillgrp, cache->batch_fill[cache->cache_idx], gpf->runtime.viewmatrix); + } + } +} + +/* add stroke shading group to pass */ +static void gpencil_add_stroke_shgroup(GpencilBatchCache *cache, DRWShadingGroup *strokegrp, + Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, + const float opacity, const float tintcolor[4], const bool onion, const bool custonion) +{ + float tcolor[4]; + float ink[4]; + short sthickness; + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + + /* set color using base color, tint color and opacity */ + if (!onion) { + /* if special stroke, use fill color as stroke color */ + if (gps->flag & GP_STROKE_NOFILL) { + interp_v3_v3v3(tcolor, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]); + tcolor[3] = gps->runtime.tmp_fill_rgba[3] * opacity; + } + else { + interp_v3_v3v3(tcolor, gps->runtime.tmp_stroke_rgba, tintcolor, tintcolor[3]); + tcolor[3] = gps->runtime.tmp_stroke_rgba[3] * opacity; + } + copy_v4_v4(ink, tcolor); + } + else { + if (custonion) { + copy_v4_v4(ink, tintcolor); + } + else { + ARRAY_SET_ITEMS(tcolor, UNPACK3(gps->runtime.tmp_stroke_rgba), opacity); + copy_v4_v4(ink, tcolor); + } + } + + sthickness = gps->thickness + gpl->line_change; + CLAMP_MIN(sthickness, 1); + if (cache->is_dirty) { + gpencil_batch_cache_check_free_slots(ob); + if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) { + cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_stroke_geom(gpf, gps, sthickness, ink); + } + else { + cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_point_geom(gps, sthickness, ink); + } + } + DRW_shgroup_call_add(strokegrp, cache->batch_stroke[cache->cache_idx], gpf->runtime.viewmatrix); +} + +/* add edit points shading group to pass */ +static void gpencil_add_editpoints_shgroup( + GPENCIL_StorageList *stl, GpencilBatchCache *cache, ToolSettings *UNUSED(ts), Object *ob, + bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + + /* alpha factor for edit points/line to make them more subtle */ + float edit_alpha = v3d->vertex_opacity; + + if (GPENCIL_ANY_EDIT_MODE(gpd)) { + Object *obact = DRW_context_state_get()->obact; + if ((!obact) || (obact->type != OB_GPENCIL)) { + return; + } + const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + + /* line of the original stroke */ + if (cache->is_dirty) { + gpencil_batch_cache_check_free_slots(ob); + cache->batch_edlin[cache->cache_idx] = DRW_gpencil_get_edlin_geom(gps, edit_alpha, gpd->flag); + } + if (cache->batch_edlin[cache->cache_idx]) { + if ((obact) && (obact == ob) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->flag3 & V3D_GP_SHOW_EDIT_LINES)) + { + DRW_shgroup_call_add( + stl->g_data->shgrps_edit_line, + cache->batch_edlin[cache->cache_idx], + gpf->runtime.viewmatrix); + } + } + /* edit points */ + if ((gps->flag & GP_STROKE_SELECT) || (is_weight_paint)) { + if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) || ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) { + if (cache->is_dirty) { + gpencil_batch_cache_check_free_slots(ob); + cache->batch_edit[cache->cache_idx] = DRW_gpencil_get_edit_geom(gps, edit_alpha, gpd->flag); + } + if (cache->batch_edit[cache->cache_idx]) { + if ((obact) && (obact == ob)) { + /* edit pass */ + DRW_shgroup_call_add( + stl->g_data->shgrps_edit_point, + cache->batch_edit[cache->cache_idx], + gpf->runtime.viewmatrix); + } + } + } + } + } +} + +/* function to draw strokes for onion only */ +static void gpencil_draw_onion_strokes( + GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, Object *ob, + bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, + const float opacity, const float tintcolor[4], const bool custonion) +{ + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + Depsgraph *depsgraph = DRW_context_state_get()->depsgraph; + + float viewmatrix[4][4]; + + /* get parent matrix and save as static data */ + ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix); + copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix); + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); + copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); + + int id = stl->storage->shgroup_id; + /* check if stroke can be drawn */ + if (gpencil_can_draw_stroke(gp_style, gps, true, false) == false) { + continue; + } + /* limit the number of shading groups */ + if (id >= GPENCIL_MAX_SHGROUPS) { + continue; + } + + stl->shgroups[id].shgrps_fill = NULL; + if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) { + stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, true); + } + else { + stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, true); + } + + /* stroke */ + gpencil_add_stroke_shgroup( + cache, stl->shgroups[id].shgrps_stroke, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion); + + stl->storage->shgroup_id++; + cache->cache_idx++; + } +} + + +/* main function to draw strokes */ +static void gpencil_draw_strokes( + GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob, + bGPdata *gpd, bGPDlayer *gpl, bGPDframe *src_gpf, bGPDframe *derived_gpf, + const float opacity, const float tintcolor[4], const bool custonion) +{ + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + View3D *v3d = draw_ctx->v3d; + bGPDstroke *gps, *src_gps; + DRWShadingGroup *fillgrp; + DRWShadingGroup *strokegrp; + float viewmatrix[4][4]; + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool playing = (bool)stl->storage->playing; + const bool is_render = (bool)stl->storage->is_render; + const bool is_mat_preview = (bool)stl->storage->is_mat_preview; + const bool overlay_multiedit = v3d != NULL ? (v3d->flag3 & V3D_GP_SHOW_MULTIEDIT_LINES) : true; + + /* Get evaluation context */ + /* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files + * (i.e. the thumbnail offscreen rendering fails) + */ + Depsgraph *depsgraph = DRW_context_state_get()->depsgraph; + + /* get parent matrix and save as static data */ + ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix); + copy_m4_m4(derived_gpf->runtime.viewmatrix, viewmatrix); + + /* apply geometry modifiers */ + if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) { + if (!stl->storage->simplify_modif) { + if (BKE_gpencil_has_geometry_modifiers(ob)) { + BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, derived_gpf, stl->storage->is_render); + } + } + } + + if (src_gpf) { + src_gps = src_gpf->strokes.first; + } + else { + src_gps = NULL; + } + + for (gps = derived_gpf->strokes.first; gps; gps = gps->next) { + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + + /* check if stroke can be drawn */ + if (gpencil_can_draw_stroke(gp_style, gps, false, is_mat_preview) == false) { + continue; + } + /* limit the number of shading groups */ + if (stl->storage->shgroup_id >= GPENCIL_MAX_SHGROUPS) { + continue; + } + + /* be sure recalc all chache in source stroke to avoid recalculation when frame change + * and improve fps */ + if (src_gps) { + DRW_gpencil_recalc_geometry_caches(ob, gp_style, src_gps); + } + + /* if the fill has any value, it's considered a fill and is not drawn if simplify fill is enabled */ + if ((stl->storage->simplify_fill) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_REMOVE_FILL_LINE)) { + if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || + (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID)) + { + continue; + } + } + + if ((gpl->actframe->framenum == derived_gpf->framenum) || + (!is_multiedit) || (overlay_multiedit)) + { + int id = stl->storage->shgroup_id; + if (gps->totpoints > 0) { + if ((gps->totpoints > 2) && (!stl->storage->simplify_fill) && + ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) && + ((gps->flag & GP_STROKE_NOFILL) == 0)) + { + stl->shgroups[id].shgrps_fill = DRW_gpencil_shgroup_fill_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh, gpd, gp_style, id); + } + else { + stl->shgroups[id].shgrps_fill = NULL; + } + if ((gp_style->mode == GP_STYLE_MODE_LINE) && (gps->totpoints > 1)) { + stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, false); + } + else { + stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, false); + } + } + else { + stl->shgroups[id].shgrps_fill = NULL; + stl->shgroups[id].shgrps_stroke = NULL; + } + stl->storage->shgroup_id++; + + fillgrp = stl->shgroups[id].shgrps_fill; + strokegrp = stl->shgroups[id].shgrps_stroke; + + /* copy color to temp fields to apply temporal changes in the stroke */ + copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); + copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); + + /* apply modifiers (only modify geometry, but not create ) */ + if ((cache->is_dirty) && (ob->greasepencil_modifiers.first) && (!is_multiedit)) { + if (!stl->storage->simplify_modif) { + BKE_gpencil_stroke_modifiers(depsgraph, ob, gpl, derived_gpf, gps, stl->storage->is_render); + } + } + + /* fill */ + if ((fillgrp) && (!stl->storage->simplify_fill)) { + gpencil_add_fill_shgroup( + cache, fillgrp, ob, gpl, derived_gpf, gps, tintcolor, false, custonion); + } + /* stroke */ + if (strokegrp) { + gpencil_add_stroke_shgroup( + cache, strokegrp, ob, gpl, derived_gpf, gps, opacity, tintcolor, false, custonion); + } + } + + /* edit points (only in edit mode and not play animation not render) */ + if ((src_gps) && (!playing) && (!is_render)) { + if (!stl->g_data->shgrps_edit_line) { + stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh, psl->edit_pass); + } + if (!stl->g_data->shgrps_edit_point) { + stl->g_data->shgrps_edit_point = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->edit_pass); + const float *viewport_size = DRW_viewport_size_get(); + DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1); + } + + gpencil_add_editpoints_shgroup(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps); + } + + if (src_gps) { + src_gps = src_gps->next; + } + + cache->cache_idx++; + } +} + + /* draw stroke in drawing buffer */ +void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob) +{ + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + Brush *brush = BKE_brush_getactive_gpencil(ts); + bGPdata *gpd = ob->data; + MaterialGPencilStyle *gp_style = NULL; + + float obscale = (ob->size[0] + ob->size[1] + ob->size[2]) / 3.0f; + + /* use the brush material */ + Material *ma = BKE_gpencil_get_material_from_brush(brush); + if (ma != NULL) { + gp_style = ma->gp_style; + } + /* this is not common, but avoid any special situations when brush could be without material */ + if (gp_style == NULL) { + gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol); + } + + /* drawing strokes */ + /* Check if may need to draw the active stroke cache, only if this layer is the active layer + * that is being edited. (Stroke buffer is currently stored in gp-data) + */ + if (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 0)) { + if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { + /* It should also be noted that sbuffer contains temporary point types + * i.e. tGPspoints NOT bGPDspoints + */ + short lthick = brush->size * obscale; + /* if only one point, don't need to draw buffer because the user has no time to see it */ + if (gpd->runtime.sbuffer_size > 1) { + if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) { + stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create( + e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false); + } + else { + stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create( + e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false); + } + + /* use unit matrix because the buffer is in screen space and does not need conversion */ + if (gpd->runtime.mode == GP_STYLE_MODE_LINE) { + stl->g_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom( + gpd, stl->storage->unit_matrix, lthick); + } + else { + stl->g_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom( + gpd, stl->storage->unit_matrix, lthick); + } + + DRW_shgroup_call_add( + stl->g_data->shgrps_drawing_stroke, + stl->g_data->batch_buffer_stroke, + stl->storage->unit_matrix); + + if ((gpd->runtime.sbuffer_size >= 3) && (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) && + ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0)) + { + /* if not solid, fill is simulated with solid color */ + if (gpd->runtime.bfill_style > 0) { + gpd->runtime.sfill[3] = 0.5f; + } + stl->g_data->shgrps_drawing_fill = DRW_shgroup_create( + e_data->gpencil_drawing_fill_sh, psl->drawing_pass); + stl->g_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd); + DRW_shgroup_call_add( + stl->g_data->shgrps_drawing_fill, + stl->g_data->batch_buffer_fill, + stl->storage->unit_matrix); + } + } + } + } +} + +/* get alpha factor for onion strokes */ +static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd) +{ +#define MIN_ALPHA_VALUE 0.01f + + /* if fade is disabled, opacity is equal in all frames */ + if ((gpd->onion_flag & GP_ONION_FADE) == 0) { + color[3] = gpd->onion_factor; + } + else { + /* add override opacity factor */ + color[3] += gpd->onion_factor - 0.5f; + } + + CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f); +} + +/* draw onion-skinning for a layer */ +static void gpencil_draw_onionskins( + GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, + Object *ob, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf) +{ + + const float default_color[3] = { UNPACK3(U.gpencil_new_layer_col) }; + const float alpha = 1.0f; + float color[4]; + int idx; + float fac = 1.0f; + int step = 0; + int mode = 0; + bool colflag = false; + bGPDframe *gpf_loop = NULL; + int last = gpf->framenum; + + colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL; + + + /* ------------------------------- + * 1) Draw Previous Frames First + * ------------------------------- */ + step = gpd->gstep; + mode = gpd->onion_mode; + + if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) { + copy_v3_v3(color, gpd->gcolor_prev); + } + else { + copy_v3_v3(color, default_color); + } + + idx = 0; + for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) { + /* only selected frames */ + if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) { + continue; + } + /* absolute range */ + if (mode == GP_ONION_MODE_ABSOLUTE) { + if ((gpf->framenum - gf->framenum) > step) { + break; + } + } + /* relative range */ + if (mode == GP_ONION_MODE_RELATIVE) { + idx++; + if (idx > step) { + break; + } + + } + /* alpha decreases with distance from curframe index */ + if (mode != GP_ONION_MODE_SELECTED) { + if (mode == GP_ONION_MODE_ABSOLUTE) { + fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(step + 1)); + } + else { + fac = 1.0f - ((float)idx / (float)(step + 1)); + } + color[3] = alpha * fac * 0.66f; + } + else { + idx++; + fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f); + color[3] = fac; + } + + /* if loop option, save the frame to use later */ + if ((mode != GP_ONION_MODE_ABSOLUTE) && (gpd->onion_flag & GP_ONION_LOOP)) { + gpf_loop = gf; + } + + gpencil_get_onion_alpha(color, gpd); + gpencil_draw_onion_strokes(cache, e_data, vedata, ob, gpd, gpl, gf, color[3], color, colflag); + } + /* ------------------------------- + * 2) Now draw next frames + * ------------------------------- */ + step = gpd->gstep_next; + mode = gpd->onion_mode; + + if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) { + copy_v3_v3(color, gpd->gcolor_next); + } + else { + copy_v3_v3(color, default_color); + } + + idx = 0; + for (bGPDframe *gf = gpf->next; gf; gf = gf->next) { + /* only selected frames */ + if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) { + continue; + } + /* absolute range */ + if (mode == GP_ONION_MODE_ABSOLUTE) { + if ((gf->framenum - gpf->framenum) > step) { + break; + } + } + /* relative range */ + if (mode == GP_ONION_MODE_RELATIVE) { + idx++; + if (idx > step) { + break; + } + + } + /* alpha decreases with distance from curframe index */ + if (mode != GP_ONION_MODE_SELECTED) { + if (mode == GP_ONION_MODE_ABSOLUTE) { + fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(step + 1)); + } + else { + fac = 1.0f - ((float)idx / (float)(step + 1)); + } + color[3] = alpha * fac * 0.66f; + } + else { + idx++; + fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f); + color[3] = fac; + } + + gpencil_get_onion_alpha(color, gpd); + gpencil_draw_onion_strokes(cache, e_data, vedata, ob, gpd, gpl, gf, color[3], color, colflag); + if (last < gf->framenum) { + last = gf->framenum; + } + } + + /* Draw first frame in blue for loop mode */ + if ((gpd->onion_flag & GP_ONION_LOOP) && (gpf_loop != NULL)) { + if ((last == gpf->framenum) || (gpf->next == NULL)) { + gpencil_get_onion_alpha(color, gpd); + gpencil_draw_onion_strokes( + cache, e_data, vedata, ob, gpd, gpl, + gpf_loop, color[3], color, colflag); + } + } +} + +/* populate a datablock for multiedit (no onions, no modifiers) */ +void DRW_gpencil_populate_multiedit(GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob, bGPdata *gpd) +{ + bGPDframe *gpf = NULL; + + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph); + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval); + ToolSettings *ts = scene->toolsettings; + cache->cache_idx = 0; + + /* check if playing animation */ + bool playing = (bool)stl->storage->playing; + + /* draw strokes */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* don't draw layer if hidden */ + if (gpl->flag & GP_LAYER_HIDE) + continue; + + /* list of frames to draw */ + if (!playing) { + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { + gpencil_draw_strokes( + cache, e_data, vedata, ts, ob, gpd, gpl, gpf, gpf, + gpl->opacity, gpl->tintcolor, false); + } + } + } + else { + gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); + if (gpf) { + gpencil_draw_strokes( + cache, e_data, vedata, ts, ob, gpd, gpl, gpf, gpf, + gpl->opacity, gpl->tintcolor, false); + } + } + + } + + cache->is_dirty = false; +} + +/* helper for populate a complete grease pencil datablock */ +void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob, bGPdata *gpd) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph); + ToolSettings *ts = scene->toolsettings; + bGPDframe *derived_gpf = NULL; + const bool main_onion = v3d != NULL ? ((v3d->flag3 & V3D_GP_SHOW_ONION_SKIN) == 0) : true; + const bool no_onion = (bool)(gpd->flag & GP_DATA_STROKE_WEIGHTMODE) || main_onion; + const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true; + + /* check if playing animation */ + bool playing = (bool)stl->storage->playing; + + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval); + cache->cache_idx = 0; + + /* init general modifiers data */ + if (!stl->storage->simplify_modif) { + if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) { + BKE_gpencil_lattice_init(ob); + } + } + /* draw normal strokes */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* don't draw layer if hidden */ + if (gpl->flag & GP_LAYER_HIDE) + continue; + + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); + if (gpf == NULL) + continue; + + /* create GHash if need */ + if (gpl->runtime.derived_data == NULL) { + gpl->runtime.derived_data = (GHash *)BLI_ghash_str_new(gpl->info); + } + + derived_gpf = BLI_ghash_lookup(gpl->runtime.derived_data, ob->id.name); + if (derived_gpf == NULL) { + cache->is_dirty = true; + } + if (cache->is_dirty) { + if (derived_gpf != NULL) { + /* first clear temp data */ + BKE_gpencil_free_frame_runtime_data(derived_gpf); + BLI_ghash_remove(gpl->runtime.derived_data, ob->id.name, NULL, NULL); + } + /* create new data */ + derived_gpf = BKE_gpencil_frame_duplicate(gpf); + BLI_ghash_insert(gpl->runtime.derived_data, ob->id.name, derived_gpf); + } + + /* draw onion skins */ + if ((gpd->flag & GP_DATA_SHOW_ONIONSKINS) && + (!no_onion) && (overlay) && + (gpl->onion_flag & GP_LAYER_ONIONSKIN) && + ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) + { + if ((!stl->storage->is_render) || + ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) + { + gpencil_draw_onionskins(cache, e_data, vedata, ob, gpd, gpl, gpf); + } + } + + /* draw normal strokes */ + gpencil_draw_strokes( + cache, e_data, vedata, ts, ob, gpd, gpl, gpf, derived_gpf, + gpl->opacity, gpl->tintcolor, false); + + } + + /* clear any lattice data */ + if ((cache->is_dirty) && (ob->greasepencil_modifiers.first)) { + BKE_gpencil_lattice_clear(ob); + } + + cache->is_dirty = false; +} + +/* Helper for gpencil_instance_modifiers() + * See also MOD_gpencilinstance.c -> bakeModifier() + */ +static void gp_instance_modifier_make_instances(GPENCIL_StorageList *stl, Object *ob, InstanceGpencilModifierData *mmd) +{ + /* reset random */ + mmd->rnd[0] = 1; + + /* Generate instances */ + for (int x = 0; x < mmd->count[0]; x++) { + for (int y = 0; y < mmd->count[1]; y++) { + for (int z = 0; z < mmd->count[2]; z++) { + Object *newob; + + const int elem_idx[3] = {x, y, z}; + float mat[4][4]; + int sh; + + /* original strokes are at index = 0,0,0 */ + if ((x == 0) && (y == 0) && (z == 0)) { + continue; + } + + /* compute transform for instance */ + BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat); + + /* add object to cache */ + newob = MEM_dupallocN(ob); + mul_m4_m4m4(newob->obmat, ob->obmat, mat); + + /* apply scale */ + ARRAY_SET_ITEMS(newob->size, mat[0][0], mat[1][1], mat[2][2]); + + /* apply shift */ + sh = x; + if (mmd->lock_axis == GP_LOCKAXIS_Y) { + sh = y; + } + if (mmd->lock_axis == GP_LOCKAXIS_Z) { + sh = z; + } + madd_v3_v3fl(newob->obmat[3], mmd->shift, sh); + + /* add temp object to cache */ + stl->g_data->gp_object_cache = gpencil_object_cache_add( + stl->g_data->gp_object_cache, newob, true, + &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used); + } + } + } +} + +/* create instances using instance modifiers */ +void gpencil_instance_modifiers(GPENCIL_StorageList *stl, Object *ob) +{ + if ((ob) && (ob->data)) { + bGPdata *gpd = ob->data; + if (GPENCIL_ANY_EDIT_MODE(gpd)) { + return; + } + } + + for (GpencilModifierData *md = ob->greasepencil_modifiers.first; md; md = md->next) { + if (((md->mode & eGpencilModifierMode_Realtime) && (stl->storage->is_render == false)) || + ((md->mode & eGpencilModifierMode_Render) && (stl->storage->is_render == true))) + { + if (md->type == eGpencilModifierType_Instance) { + InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md; + + /* Only add instances if the "Make Objects" flag is set + * FIXME: This is a workaround for z-ordering weirdness when all instances are in the same object + */ + if (mmd->flag & GP_INSTANCE_MAKE_OBJECTS) { + gp_instance_modifier_make_instances(stl, ob, mmd); + } + } + } + } +} diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c new file mode 100644 index 00000000000..71c99b2bcdf --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -0,0 +1,794 @@ +/* + * Copyright 2017, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Antonio Vazquez + * + */ + +/** \file blender/draw/engines/gpencil/gpencil_engine.c + * \ingroup draw + */ +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "BKE_camera.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_gpencil.h" +#include "BKE_shader_fx.h" + +#include "DNA_gpencil_types.h" +#include "DNA_view3d_types.h" + +#include "draw_mode_engines.h" + +#include "UI_resources.h" + +#include "GPU_texture.h" + +#include "gpencil_engine.h" + +#include "ED_screen.h" +#include "ED_gpencil.h" + +extern char datatoc_gpencil_fill_vert_glsl[]; +extern char datatoc_gpencil_fill_frag_glsl[]; +extern char datatoc_gpencil_stroke_vert_glsl[]; +extern char datatoc_gpencil_stroke_geom_glsl[]; +extern char datatoc_gpencil_stroke_frag_glsl[]; +extern char datatoc_gpencil_zdepth_mix_frag_glsl[]; +extern char datatoc_gpencil_simple_mix_frag_glsl[]; +extern char datatoc_gpencil_point_vert_glsl[]; +extern char datatoc_gpencil_point_geom_glsl[]; +extern char datatoc_gpencil_point_frag_glsl[]; +extern char datatoc_gpencil_background_frag_glsl[]; +extern char datatoc_gpencil_paper_frag_glsl[]; +extern char datatoc_gpencil_edit_point_vert_glsl[]; +extern char datatoc_gpencil_edit_point_geom_glsl[]; +extern char datatoc_gpencil_edit_point_frag_glsl[]; + +/* *********** STATIC *********** */ +static GPENCIL_e_data e_data = {NULL}; /* Engine data */ + +/* *********** FUNCTIONS *********** */ + +/* create a multisample buffer if not present */ +void DRW_gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h) +{ + GPENCIL_FramebufferList *fbl = vedata->fbl; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl; + + short samples = stl->storage->multisamples; + + if (samples > 0) { + if (!fbl->multisample_fb) { + fbl->multisample_fb = GPU_framebuffer_create(); + if (fbl->multisample_fb) { + if (txl->multisample_color == NULL) { + txl->multisample_color = GPU_texture_create_2D_multisample( + rect_w, rect_h, GPU_RGBA16F, NULL, samples, NULL); + } + if (txl->multisample_depth == NULL) { + txl->multisample_depth = GPU_texture_create_2D_multisample( + rect_w, rect_h, GPU_DEPTH24_STENCIL8, NULL, samples, NULL); + } + GPU_framebuffer_ensure_config(&fbl->multisample_fb, { + GPU_ATTACHMENT_TEXTURE(txl->multisample_depth), + GPU_ATTACHMENT_TEXTURE(txl->multisample_color) + }); + if (!GPU_framebuffer_check_valid(fbl->multisample_fb, NULL)) { + GPU_framebuffer_free(fbl->multisample_fb); + } + } + } + } +} + +static void GPENCIL_create_framebuffers(void *vedata) +{ + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + + /* Go full 32bits for rendering */ + GPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F; + + if (DRW_state_is_fbo()) { + const float *viewport_size = DRW_viewport_size_get(); + const int size[2] = { (int)viewport_size[0], (int)viewport_size[1] }; + + /* create multiframe framebuffer for AA */ + if (stl->storage->multisamples > 0) { + DRW_gpencil_multisample_ensure(vedata, size[0], size[1]); + } + + /* temp textures */ + e_data.temp_depth_tx_a = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + e_data.temp_color_tx_a = DRW_texture_pool_query_2D(size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config(&fbl->temp_fb_a, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_a), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a) + }); + + e_data.temp_depth_tx_b = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + e_data.temp_color_tx_b = DRW_texture_pool_query_2D(size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config(&fbl->temp_fb_b, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_b), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b) + }); + + /* used for rim FX effect */ + e_data.temp_depth_tx_rim = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + e_data.temp_color_tx_rim = DRW_texture_pool_query_2D(size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config(&fbl->temp_fb_rim, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_rim), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_rim), + }); + + /* background framebuffer to speed up drawing process (always 16 bits) */ + e_data.background_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + e_data.background_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA32F, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config(&fbl->background_fb, { + GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx), + GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx) + }); + } +} + +static void GPENCIL_create_shaders(void) +{ + /* normal fill shader */ + if (!e_data.gpencil_fill_sh) { + e_data.gpencil_fill_sh = DRW_shader_create( + datatoc_gpencil_fill_vert_glsl, NULL, + datatoc_gpencil_fill_frag_glsl, NULL); + } + + /* normal stroke shader using geometry to display lines (line mode) */ + if (!e_data.gpencil_stroke_sh) { + e_data.gpencil_stroke_sh = DRW_shader_create( + datatoc_gpencil_stroke_vert_glsl, + datatoc_gpencil_stroke_geom_glsl, + datatoc_gpencil_stroke_frag_glsl, + NULL); + } + + /* dot/rectangle mode for normal strokes using geometry */ + if (!e_data.gpencil_point_sh) { + e_data.gpencil_point_sh = DRW_shader_create( + datatoc_gpencil_point_vert_glsl, + datatoc_gpencil_point_geom_glsl, + datatoc_gpencil_point_frag_glsl, + NULL); + } + /* used for edit points or strokes with one point only */ + if (!e_data.gpencil_edit_point_sh) { + e_data.gpencil_edit_point_sh = DRW_shader_create( + datatoc_gpencil_edit_point_vert_glsl, + datatoc_gpencil_edit_point_geom_glsl, + datatoc_gpencil_edit_point_frag_glsl, NULL); + } + + /* used for edit lines for edit modes */ + if (!e_data.gpencil_line_sh) { + e_data.gpencil_line_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_FLAT_COLOR); + } + + /* used to filling during drawing */ + if (!e_data.gpencil_drawing_fill_sh) { + e_data.gpencil_drawing_fill_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR); + } + + /* full screen for mix zdepth*/ + if (!e_data.gpencil_fullscreen_sh) { + e_data.gpencil_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_zdepth_mix_frag_glsl, NULL); + } + if (!e_data.gpencil_simple_fullscreen_sh) { + e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_simple_mix_frag_glsl, NULL); + } + + /* shaders for use when drawing */ + if (!e_data.gpencil_background_sh) { + e_data.gpencil_background_sh = DRW_shader_create_fullscreen(datatoc_gpencil_background_frag_glsl, NULL); + } + if (!e_data.gpencil_paper_sh) { + e_data.gpencil_paper_sh = DRW_shader_create_fullscreen(datatoc_gpencil_paper_frag_glsl, NULL); + } +} + +void GPENCIL_engine_init(void *vedata) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + /* init storage */ + if (!stl->storage) { + stl->storage = MEM_callocN(sizeof(GPENCIL_Storage), "GPENCIL_Storage"); + + /* unit matrix */ + unit_m4(stl->storage->unit_matrix); + } + + stl->storage->multisamples = U.gpencil_multisamples; + + /* create framebuffers */ + GPENCIL_create_framebuffers(vedata); + + /* create shaders */ + GPENCIL_create_shaders(); + GPENCIL_create_fx_shaders(&e_data); + + /* blank texture used if no texture defined for fill shader */ + if (!e_data.gpencil_blank_texture) { + float rect[16][16][4] = {{{0.0f}}}; + e_data.gpencil_blank_texture = DRW_texture_create_2D(16, 16, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect); + } +} + +static void GPENCIL_engine_free(void) +{ + /* only free custom shaders, builtin shaders are freed in blender close */ + DRW_SHADER_FREE_SAFE(e_data.gpencil_fill_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh); + DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh); + + DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture); + + /* effects */ + GPENCIL_delete_fx_shaders(&e_data); +} + +void GPENCIL_cache_init(void *vedata) +{ + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + View3D *v3d = draw_ctx->v3d; + + /* Special handling for when active object is GP object (e.g. for draw mode) */ + Object *obact = draw_ctx->obact; + bGPdata *obact_gpd = NULL; + MaterialGPencilStyle *gp_style = NULL; + + if (obact && (obact->type == OB_GPENCIL) && (obact->data)) { + obact_gpd = (bGPdata *)obact->data; + gp_style = BKE_material_gpencil_settings_get(obact, obact->actcol); + } + + if (!stl->g_data) { + /* Alloc transient pointers */ + stl->g_data = MEM_mallocN(sizeof(g_data), "g_data"); + stl->storage->xray = GP_XRAY_FRONT; /* used for drawing */ + stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID; /* used for drawing */ + } + stl->storage->tonemapping = 0; + + stl->g_data->shgrps_edit_line = NULL; + stl->g_data->shgrps_edit_point = NULL; + + if (!stl->shgroups) { + /* Alloc maximum size because count strokes is very slow and can be very complex due onion skinning. + I tried to allocate only one block and using realloc, increasing the size when read a new strokes + in cache_finish, but the realloc produce weird things on screen, so we keep as is while we found + a better solution + */ + stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup"); + } + + /* init gp objects cache */ + stl->g_data->gp_cache_used = 0; + stl->g_data->gp_cache_size = 0; + stl->g_data->gp_object_cache = NULL; + + { + /* Stroke pass */ + psl->stroke_pass = DRW_pass_create( + "GPencil Stroke Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND); + stl->storage->shgroup_id = 0; + + /* edit pass */ + psl->edit_pass = DRW_pass_create( + "GPencil Edit Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND); + + /* detect if playing animation */ + stl->storage->playing = 0; + if (draw_ctx->evil_C) { + stl->storage->playing = ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != NULL ? 1 : 0; + } + + if (obact_gpd) { + /* for some reason, when press play there is a delay in the animation flag check + * and this produces errors. To be sure, we set cache as dirty because the frame + * is changing. + */ + if (stl->storage->playing == 1) { + obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY; + } + /* if render, set as dirty to update all data */ + else if (stl->storage->is_render == true) { + obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY; + } + } + + /* save render state */ + stl->storage->is_render = DRW_state_is_image_render(); + stl->storage->is_mat_preview = (bool)stl->storage->is_render && STREQ(scene->id.name + 2, "preview"); + + /* save simplify flags (can change while drawing, so it's better to save) */ + stl->storage->simplify_fill = GP_SIMPLIFY_FILL(scene, stl->storage->playing); + stl->storage->simplify_modif = GP_SIMPLIFY_MODIF(scene, stl->storage->playing); + + /* save pixsize */ + stl->storage->pixsize = DRW_viewport_pixelsize_get(); + if ((!DRW_state_is_opengl_render()) && (stl->storage->is_render)) { + stl->storage->pixsize = &stl->storage->render_pixsize; + } + + /* detect if painting session */ + if ((obact_gpd) && + (obact_gpd->flag & GP_DATA_STROKE_PAINTMODE) && + (stl->storage->playing == 0)) + { + if (((obact_gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) && + (obact_gpd->runtime.sbuffer_size > 1)) + { + stl->g_data->session_flag = GP_DRW_PAINT_PAINTING; + } + else { + stl->g_data->session_flag = GP_DRW_PAINT_IDLE; + } + } + else { + /* if not drawing mode */ + stl->g_data->session_flag = GP_DRW_PAINT_HOLD; + } + + if (gp_style) { + stl->storage->stroke_style = gp_style->stroke_style; + stl->storage->color_type = GPENCIL_COLOR_SOLID; + if (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) { + stl->storage->color_type = GPENCIL_COLOR_TEXTURE; + if (gp_style->flag & GP_STYLE_STROKE_PATTERN) { + stl->storage->color_type = GPENCIL_COLOR_PATTERN; + } + } + } + else { + stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID; + stl->storage->color_type = GPENCIL_COLOR_SOLID; + } + + /* drawing buffer pass for drawing the stroke that is beeing drawing by the user. The data + * is stored in sbuffer + */ + psl->drawing_pass = DRW_pass_create( + "GPencil Drawing Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + + /* full screen pass to combine the result with default framebuffer */ + struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + psl->mix_pass = DRW_pass_create( + "GPencil Mix Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass); + DRW_shgroup_call_add(mix_shgrp, quad, NULL); + DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &e_data.input_color_tx); + DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &e_data.input_depth_tx); + DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1); + + /* mix pass no blend used to copy between passes. A separated pass is required + * because if mix_pass is used, the acumulation of blend degrade the colors. + * + * This pass is used too to take the snapshot used for background_pass. This image + * will be used as the background while the user is drawing. + */ + psl->mix_pass_noblend = DRW_pass_create( + "GPencil Mix Pass no blend", + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + DRWShadingGroup *mix_shgrp_noblend = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass_noblend); + DRW_shgroup_call_add(mix_shgrp_noblend, quad, NULL); + DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeColor", &e_data.input_color_tx); + DRW_shgroup_uniform_texture_ref(mix_shgrp_noblend, "strokeDepth", &e_data.input_depth_tx); + DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 1); + + /* Painting session pass (used only to speedup while the user is drawing ) + * This pass is used to show the snapshot of the current grease pencil strokes captured + * when the user starts to draw (see comments above). + * In this way, the previous strokes don't need to be redraw and the drawing process + * is far to agile. + */ + psl->background_pass = DRW_pass_create( + "GPencil Background Painting Session Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + DRWShadingGroup *background_shgrp = DRW_shgroup_create(e_data.gpencil_background_sh, psl->background_pass); + DRW_shgroup_call_add(background_shgrp, quad, NULL); + DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &e_data.background_color_tx); + DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &e_data.background_depth_tx); + + /* pass for drawing paper (only if viewport) + * In render, the v3d is null so the paper is disabled + * The paper is way to isolate the drawing in complex scene and to have a cleaner + * drawing area. + */ + if (v3d) { + psl->paper_pass = DRW_pass_create( + "GPencil Paper Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND); + DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass); + DRW_shgroup_call_add(paper_shgrp, quad, NULL); + DRW_shgroup_uniform_vec3(paper_shgrp, "color", v3d->shading.background_color, 1); + DRW_shgroup_uniform_float(paper_shgrp, "opacity", &v3d->overlay.gpencil_paper_opacity, 1); + } + + /* grid pass */ + if (v3d) { + psl->grid_pass = DRW_pass_create( + "GPencil Grid Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); + stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass); + } + + /* create effects passes */ + GPENCIL_create_fx_passes(psl); + } +} + +void GPENCIL_cache_populate(void *vedata, Object *ob) +{ + /* object must be visible */ + if (!DRW_check_object_visible_within_active_context(ob)) { + return; + } + + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + View3D *v3d = draw_ctx->v3d; + + /* object datablock (this is not draw now) */ + if (ob->type == OB_GPENCIL && ob->data) { + bGPdata *gpd = (bGPdata *)ob->data; + if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) { + + /* if render set as dirty */ + if (stl->storage->is_render == true) { + gpd->flag |= GP_DATA_CACHE_IS_DIRTY; + } + + /* allocate memory for saving gp objects for drawing later */ + stl->g_data->gp_object_cache = gpencil_object_cache_add(stl->g_data->gp_object_cache, ob, false, + &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used); + + /* generate instances as separate cache objects for instance modifiers + * with the "Make as Objects" option enabled + */ + if (!stl->storage->simplify_modif) { + gpencil_instance_modifiers(stl, ob); + } + } + /* draw current painting strokes */ + DRW_gpencil_populate_buffer_strokes(&e_data, vedata, ts, ob); + + /* grid */ + if ((v3d) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->flag3 & V3D_GP_SHOW_GRID) && + (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact)) + { + stl->g_data->batch_grid = DRW_gpencil_get_grid(); + DRW_shgroup_call_add(stl->g_data->shgrps_grid, + stl->g_data->batch_grid, + ob->obmat); + } + } +} + +void GPENCIL_cache_finish(void *vedata) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + bool is_multiedit = false; + + /* if painting session, don't need to do more */ + if (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING) { + return; + } + + /* Draw all pending objects */ + if (stl->g_data->gp_cache_used > 0) { + for (int i = 0; i < stl->g_data->gp_cache_used; i++) { + Object *ob = stl->g_data->gp_object_cache[i].ob; + bGPdata *gpd = ob->data; + + /* save init shading group */ + stl->g_data->gp_object_cache[i].init_grp = stl->storage->shgroup_id; + + /* fill shading groups */ + is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + if (!is_multiedit) { + DRW_gpencil_populate_datablock(&e_data, vedata, scene, ob, gpd); + } + else { + DRW_gpencil_populate_multiedit(&e_data, vedata, scene, ob, gpd); + } + + /* save end shading group */ + stl->g_data->gp_object_cache[i].end_grp = stl->storage->shgroup_id - 1; + /* if render set to dirty to refresh viewport */ + if (stl->storage->is_render == true) { + gpd->flag |= GP_DATA_CACHE_IS_DIRTY; + } + /* FX passses */ + tGPencilObjectCache *cache = &stl->g_data->gp_object_cache[i]; + if (!is_multiedit) { + DRW_gpencil_fx_prepare(&e_data, vedata, cache); + } + } + } +} + +/* helper function to sort inverse gpencil objects using qsort */ +static int gpencil_object_cache_compare_zdepth(const void *a1, const void *a2) +{ + const tGPencilObjectCache *ps1 = a1, *ps2 = a2; + + if (ps1->zdepth < ps2->zdepth) return 1; + else if (ps1->zdepth > ps2->zdepth) return -1; + + return 0; +} + +/* prepare a texture with full viewport screenshot for fast drawing */ +static void gpencil_prepare_fast_drawing( + GPENCIL_StorageList *stl, DefaultFramebufferList *dfbl, + GPENCIL_FramebufferList *fbl, DRWPass *pass, + const float clearcol[4]) +{ + if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) { + GPU_framebuffer_bind(fbl->background_fb); + /* clean only in first loop cycle */ + if (stl->g_data->session_flag & GP_DRW_PAINT_IDLE) { + GPU_framebuffer_clear_color_depth(fbl->background_fb, clearcol, 1.0f); + stl->g_data->session_flag = GP_DRW_PAINT_FILLING; + } + /* repeat pass to fill temp texture */ + DRW_draw_pass(pass); + /* set default framebuffer again */ + GPU_framebuffer_bind(dfbl->default_fb); + } +} + +static void gpencil_free_obj_list(GPENCIL_StorageList *stl) +{ + /* Clear temp objects created for display instances only. These objects are created + * while the draw manager draw the scene, but only to hold the strokes data. + * see: gp_instance_modifier_make_instances() + * + * the normal objects are not freed because they are not tagged as temp objects + */ + for (int i = 0; i < stl->g_data->gp_cache_used; i++) { + Object *ob = stl->g_data->gp_object_cache[i].ob; + if (stl->g_data->gp_object_cache[i].temp_ob) { + MEM_SAFE_FREE(ob); + } + } + + /* free the cache itself */ + MEM_SAFE_FREE(stl->g_data->gp_object_cache); +} + +/* draw scene */ +void GPENCIL_draw_scene(void *ved) +{ + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl; + + int init_grp, end_grp; + tGPencilObjectCache *cache; + const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + Object *obact = draw_ctx->obact; + const bool playing = (bool)stl->storage->playing; + const bool is_render = stl->storage->is_render; + + /* paper pass to display a confortable area to draw over complex scenes with geometry */ + if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->flag3 & V3D_GP_SHOW_PAPER) && + (stl->g_data->gp_cache_used > 0)) + { + DRW_draw_pass(psl->paper_pass); + } + } + + /* if we have a painting session, we use fast viewport drawing method */ + if ((!is_render) && (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING)) { + GPU_framebuffer_bind(dfbl->default_fb); + + MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); + + DRW_draw_pass(psl->background_pass); + DRW_draw_pass(psl->drawing_pass); + + MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, dfbl->default_fb, txl); + + /* free memory */ + gpencil_free_obj_list(stl); + + /* grid pass */ + if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->flag3 & V3D_GP_SHOW_GRID)) + { + DRW_draw_pass(psl->grid_pass); + } + } + + return; + } + + if (DRW_state_is_fbo()) { + /* attach temp textures */ + GPU_framebuffer_texture_attach(fbl->temp_fb_a, e_data.temp_depth_tx_a, 0, 0); + GPU_framebuffer_texture_attach(fbl->temp_fb_a, e_data.temp_color_tx_a, 0, 0); + GPU_framebuffer_texture_attach(fbl->temp_fb_b, e_data.temp_depth_tx_b, 0, 0); + GPU_framebuffer_texture_attach(fbl->temp_fb_b, e_data.temp_color_tx_b, 0, 0); + + GPU_framebuffer_texture_attach(fbl->background_fb, e_data.background_depth_tx, 0, 0); + GPU_framebuffer_texture_attach(fbl->background_fb, e_data.background_color_tx, 0, 0); + + /* Draw all pending objects */ + if (stl->g_data->gp_cache_used > 0) { + + /* sort by zdepth */ + qsort(stl->g_data->gp_object_cache, stl->g_data->gp_cache_used, + sizeof(tGPencilObjectCache), gpencil_object_cache_compare_zdepth); + + for (int i = 0; i < stl->g_data->gp_cache_used; i++) { + cache = &stl->g_data->gp_object_cache[i]; + Object *ob = cache->ob; + bGPdata *gpd = ob->data; + init_grp = cache->init_grp; + end_grp = cache->end_grp; + /* Render stroke in separated framebuffer */ + GPU_framebuffer_bind(fbl->temp_fb_a); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f); + + /* Stroke Pass: DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH + * draw only a subset that usually start with a fill and end with stroke because the + * shading groups are created by pairs */ + if (end_grp >= init_grp) { + MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); + + DRW_draw_pass_subset( + psl->stroke_pass, + stl->shgroups[init_grp].shgrps_fill != NULL ? + stl->shgroups[init_grp].shgrps_fill : stl->shgroups[init_grp].shgrps_stroke, + stl->shgroups[end_grp].shgrps_stroke); + + MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl); + } + + /* Current buffer drawing */ + if ((!is_render) && (gpd->runtime.sbuffer_size > 0)) { + DRW_draw_pass(psl->drawing_pass); + } + /* fx passes */ + if (BKE_shaderfx_has_gpencil(ob)) { + stl->storage->tonemapping = 0; + DRW_gpencil_fx_draw(&e_data, vedata, cache); + } + + e_data.input_depth_tx = e_data.temp_depth_tx_a; + e_data.input_color_tx = e_data.temp_color_tx_a; + + /* Combine with scene buffer */ + if ((!is_render) || (fbl->main == NULL)) { + GPU_framebuffer_bind(dfbl->default_fb); + } + else { + GPU_framebuffer_bind(fbl->main); + } + /* tonemapping */ + stl->storage->tonemapping = stl->storage->is_render ? 1 : 0; + + DRW_draw_pass(psl->mix_pass); + + /* prepare for fast drawing */ + if (!is_render) { + gpencil_prepare_fast_drawing(stl, dfbl, fbl, psl->mix_pass_noblend, clearcol); + } + } + /* edit points */ + if ((!is_render) && (!playing)) { + DRW_draw_pass(psl->edit_pass); + } + } + /* grid pass */ + if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->flag3 & V3D_GP_SHOW_GRID)) + { + DRW_draw_pass(psl->grid_pass); + } + } + } + /* free memory */ + gpencil_free_obj_list(stl); + + /* detach temp textures */ + if (DRW_state_is_fbo()) { + GPU_framebuffer_texture_detach(fbl->temp_fb_a, e_data.temp_depth_tx_a); + GPU_framebuffer_texture_detach(fbl->temp_fb_a, e_data.temp_color_tx_a); + GPU_framebuffer_texture_detach(fbl->temp_fb_b, e_data.temp_depth_tx_b); + GPU_framebuffer_texture_detach(fbl->temp_fb_b, e_data.temp_color_tx_b); + + GPU_framebuffer_texture_detach(fbl->background_fb, e_data.background_depth_tx); + GPU_framebuffer_texture_detach(fbl->background_fb, e_data.background_color_tx); + + /* attach again default framebuffer after detach textures */ + if (!is_render) { + GPU_framebuffer_bind(dfbl->default_fb); + } + + /* the temp texture is ready. Now we can use fast screen drawing */ + if (stl->g_data->session_flag & GP_DRW_PAINT_FILLING) { + stl->g_data->session_flag = GP_DRW_PAINT_READY; + } + } +} + +static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data); + +DrawEngineType draw_engine_gpencil_type = { + NULL, NULL, + N_("GpencilMode"), + &GPENCIL_data_size, + &GPENCIL_engine_init, + &GPENCIL_engine_free, + &GPENCIL_cache_init, + &GPENCIL_cache_populate, + &GPENCIL_cache_finish, + NULL, + &GPENCIL_draw_scene, + NULL, + NULL, + &GPENCIL_render_to_image, +}; diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h new file mode 100644 index 00000000000..24a627f1012 --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -0,0 +1,355 @@ +/* + * Copyright 2017, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Antonio Vazquez + * + */ + +/** \file blender/draw/engines/gpencil/gpencil_engine.h + * \ingroup draw + */ + +#ifndef __GPENCIL_ENGINE_H__ +#define __GPENCIL_ENGINE_H__ + +#include "GPU_batch.h" + +struct tGPspoint; +struct bGPDstroke; +struct ModifierData; +struct GPENCIL_Data; +struct GPENCIL_StorageList; +struct Object; +struct MaterialGPencilStyle; +struct RenderEngine; +struct RenderLayer; + + /* TODO: these could be system parameter in userprefs screen */ +#define GPENCIL_MAX_GP_OBJ 256 + +#define GPENCIL_CACHE_BLOCK_SIZE 8 +#define GPENCIL_MAX_SHGROUPS 65536 +#define GPENCIL_MIN_BATCH_SLOTS_CHUNK 16 + +#define GPENCIL_COLOR_SOLID 0 +#define GPENCIL_COLOR_TEXTURE 1 +#define GPENCIL_COLOR_PATTERN 2 + +#define GP_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)) +#define GP_SIMPLIFY_ONPLAY(playing) (((playing == true) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY)) || ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY) == 0)) +#define GP_SIMPLIFY_FILL(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL))) +#define GP_SIMPLIFY_MODIF(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER))) + +#define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera)) + + /* *********** OBJECTS CACHE *********** */ + + /* used to save gpencil objects */ +typedef struct tGPencilObjectCache { + struct Object *ob; + int init_grp, end_grp; + int idx; /*original index, can change after sort */ + + /* effects */ + DRWShadingGroup *fx_wave_sh; + DRWShadingGroup *fx_blur_sh; + DRWShadingGroup *fx_colorize_sh; + DRWShadingGroup *fx_pixel_sh; + DRWShadingGroup *fx_rim_sh; + DRWShadingGroup *fx_swirl_sh; + DRWShadingGroup *fx_flip_sh; + DRWShadingGroup *fx_light_sh; + + float zdepth; /* z-depth value to sort gp object */ + bool temp_ob; /* flag to tag temporary objects that must be removed after drawing loop */ +} tGPencilObjectCache; + + /* *********** LISTS *********** */ +typedef struct GPENCIL_shgroup { + int s_clamp; + int stroke_style; + int color_type; + int mode; + int texture_mix; + int texture_flip; + int texture_clamp; + int fill_style; + int keep_size; + float obj_scale; + struct DRWShadingGroup *shgrps_fill; + struct DRWShadingGroup *shgrps_stroke; +} GPENCIL_shgroup; + +typedef struct GPENCIL_Storage { + int shgroup_id; /* total elements */ + float unit_matrix[4][4]; + int stroke_style; + int color_type; + int mode; + int xray; + int keep_size; + float obj_scale; + float pixfactor; + int playing; + bool is_render; + bool is_mat_preview; + const float *pixsize; + float render_pixsize; + int tonemapping; + short multisamples; + + /* simplify settings*/ + bool simplify_fill; + bool simplify_modif; + bool simplify_fx; + + /* Render Matrices and data */ + float persmat[4][4], persinv[4][4]; + float viewmat[4][4], viewinv[4][4]; + float winmat[4][4], wininv[4][4]; + float view_vecs[2][4]; /* vec4[2] */ + + Object *camera; /* camera pointer for render mode */ +} GPENCIL_Storage; + +typedef struct GPENCIL_StorageList { + struct GPENCIL_Storage *storage; + struct g_data *g_data; + struct GPENCIL_shgroup *shgroups; +} GPENCIL_StorageList; + +typedef struct GPENCIL_PassList { + struct DRWPass *stroke_pass; + struct DRWPass *edit_pass; + struct DRWPass *drawing_pass; + struct DRWPass *mix_pass; + struct DRWPass *mix_pass_noblend; + struct DRWPass *background_pass; + struct DRWPass *paper_pass; + struct DRWPass *grid_pass; + + /* effects */ + struct DRWPass *fx_shader_pass; + struct DRWPass *fx_shader_pass_blend; + +} GPENCIL_PassList; + +typedef struct GPENCIL_FramebufferList { + struct GPUFrameBuffer *main; + struct GPUFrameBuffer *temp_fb_a; + struct GPUFrameBuffer *temp_fb_b; + struct GPUFrameBuffer *temp_fb_rim; + struct GPUFrameBuffer *background_fb; + + struct GPUFrameBuffer *multisample_fb; +} GPENCIL_FramebufferList; + +typedef struct GPENCIL_TextureList { + struct GPUTexture *texture; + + /* multisample textures */ + struct GPUTexture *multisample_color; + struct GPUTexture *multisample_depth; + +} GPENCIL_TextureList; + +typedef struct GPENCIL_Data { + void *engine_type; /* Required */ + struct GPENCIL_FramebufferList *fbl; + struct GPENCIL_TextureList *txl; + struct GPENCIL_PassList *psl; + struct GPENCIL_StorageList *stl; + + /* render textures */ + struct GPUTexture *render_depth_tx; + struct GPUTexture *render_color_tx; + +} GPENCIL_Data; + +/* *********** STATIC *********** */ +typedef struct g_data { + struct DRWShadingGroup *shgrps_edit_point; + struct DRWShadingGroup *shgrps_edit_line; + struct DRWShadingGroup *shgrps_drawing_stroke; + struct DRWShadingGroup *shgrps_drawing_fill; + struct DRWShadingGroup *shgrps_grid; + + /* for buffer only one batch is nedeed because the drawing is only of one stroke */ + GPUBatch *batch_buffer_stroke; + GPUBatch *batch_buffer_fill; + + /* grid geometry */ + GPUBatch *batch_grid; + + int gp_cache_used; /* total objects in cache */ + int gp_cache_size; /* size of the cache */ + struct tGPencilObjectCache *gp_object_cache; + + int session_flag; + +} g_data; /* Transient data */ + +/* flags for fast drawing support */ +typedef enum eGPsession_Flag { + GP_DRW_PAINT_HOLD = (1 << 0), + GP_DRW_PAINT_IDLE = (1 << 1), + GP_DRW_PAINT_FILLING = (1 << 2), + GP_DRW_PAINT_READY = (1 << 3), + GP_DRW_PAINT_PAINTING = (1 << 4), +} eGPsession_Flag; + +typedef struct GPENCIL_e_data { + /* general drawing shaders */ + struct GPUShader *gpencil_fill_sh; + struct GPUShader *gpencil_stroke_sh; + struct GPUShader *gpencil_point_sh; + struct GPUShader *gpencil_edit_point_sh; + struct GPUShader *gpencil_line_sh; + struct GPUShader *gpencil_drawing_fill_sh; + struct GPUShader *gpencil_fullscreen_sh; + struct GPUShader *gpencil_simple_fullscreen_sh; + struct GPUShader *gpencil_background_sh; + struct GPUShader *gpencil_paper_sh; + + /* effects */ + struct GPUShader *gpencil_fx_blur_sh; + struct GPUShader *gpencil_fx_colorize_sh; + struct GPUShader *gpencil_fx_flip_sh; + struct GPUShader *gpencil_fx_light_sh; + struct GPUShader *gpencil_fx_pixel_sh; + struct GPUShader *gpencil_fx_rim_prepare_sh; + struct GPUShader *gpencil_fx_rim_resolve_sh; + struct GPUShader *gpencil_fx_swirl_sh; + struct GPUShader *gpencil_fx_wave_sh; + + /* textures */ + struct GPUTexture *background_depth_tx; + struct GPUTexture *background_color_tx; + + struct GPUTexture *gpencil_blank_texture; + + /* runtime pointers texture */ + struct GPUTexture *input_depth_tx; + struct GPUTexture *input_color_tx; + + /* working textures */ + struct GPUTexture *temp_color_tx_a; + struct GPUTexture *temp_depth_tx_a; + + struct GPUTexture *temp_color_tx_b; + struct GPUTexture *temp_depth_tx_b; + + struct GPUTexture *temp_color_tx_rim; + struct GPUTexture *temp_depth_tx_rim; +} GPENCIL_e_data; /* Engine data */ + +/* GPUBatch Cache */ +typedef struct GpencilBatchCache { + /* For normal strokes, a variable number of batch can be needed depending of number of strokes. + It could use the stroke number as total size, but when activate the onion skining, the number + can change, so the size is changed dinamically. + */ + GPUBatch **batch_stroke; + GPUBatch **batch_fill; + GPUBatch **batch_edit; + GPUBatch **batch_edlin; + + /* settings to determine if cache is invalid */ + bool is_dirty; + bool is_editmode; + int cache_frame; + + /* keep information about the size of the cache */ + int cache_size; /* total batch slots available */ + int cache_idx; /* current slot index */ +} GpencilBatchCache; + +/* general drawing functions */ +struct DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, struct DRWPass *pass, struct GPUShader *shader, + struct Object *ob, struct bGPdata *gpd, struct MaterialGPencilStyle *gp_style, int id, bool onion); +void DRW_gpencil_populate_datablock(struct GPENCIL_e_data *e_data, void *vedata, struct Scene *scene, struct Object *ob, struct bGPdata *gpd); +void DRW_gpencil_populate_buffer_strokes(struct GPENCIL_e_data *e_data, void *vedata, struct ToolSettings *ts, struct Object *ob); +void DRW_gpencil_populate_multiedit(struct GPENCIL_e_data *e_data, void *vedata, struct Scene *scene, struct Object *ob, struct bGPdata *gpd); +void DRW_gpencil_triangulate_stroke_fill(struct bGPDstroke *gps); + +void DRW_gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h); + +/* create geometry functions */ +struct GPUBatch *DRW_gpencil_get_point_geom(struct bGPDstroke *gps, short thickness, const float ink[4]); +struct GPUBatch *DRW_gpencil_get_stroke_geom(struct bGPDframe *gpf, struct bGPDstroke *gps, short thickness, const float ink[4]); +struct GPUBatch *DRW_gpencil_get_fill_geom(struct Object *ob, struct bGPDstroke *gps, const float color[4]); +struct GPUBatch *DRW_gpencil_get_edit_geom(struct bGPDstroke *gps, float alpha, short dflag); +struct GPUBatch *DRW_gpencil_get_edlin_geom(struct bGPDstroke *gps, float alpha, short dflag); +struct GPUBatch *DRW_gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, float matrix[4][4], short thickness); +struct GPUBatch *DRW_gpencil_get_buffer_fill_geom(struct bGPdata *gpd); +struct GPUBatch *DRW_gpencil_get_buffer_point_geom(struct bGPdata *gpd, float matrix[4][4], short thickness); +struct GPUBatch *DRW_gpencil_get_grid(void); + +/* object cache functions */ +struct tGPencilObjectCache *gpencil_object_cache_add(struct tGPencilObjectCache *cache_array, struct Object *ob, + bool is_temp, int *gp_cache_size, int *gp_cache_used); + +/* geometry batch cache functions */ +void gpencil_batch_cache_check_free_slots(struct Object *ob); +struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra); + +/* modifier functions */ +void gpencil_instance_modifiers(struct GPENCIL_StorageList *stl, struct Object *ob); + +/* effects */ +void GPENCIL_create_fx_shaders(struct GPENCIL_e_data *e_data); +void GPENCIL_delete_fx_shaders(struct GPENCIL_e_data *e_data); +void GPENCIL_create_fx_passes(struct GPENCIL_PassList *psl); + +void DRW_gpencil_fx_prepare( + struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, + struct tGPencilObjectCache *cache); +void DRW_gpencil_fx_draw( + struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, + struct tGPencilObjectCache *cache); + +/* main functions */ +void GPENCIL_engine_init(void *vedata); +void GPENCIL_cache_init(void *vedata); +void GPENCIL_cache_populate(void *vedata, struct Object *ob); +void GPENCIL_cache_finish(void *vedata); +void GPENCIL_draw_scene(void *vedata); + +/* render */ +void GPENCIL_render_init(struct GPENCIL_Data *ved, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void GPENCIL_render_to_image(void *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect); + +/* Use of multisample framebuffers. */ +#define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) { \ + if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \ + DRW_stats_query_start("GP Multisample Blit"); \ + GPU_framebuffer_bind(fbl->multisample_fb); \ + GPU_framebuffer_clear_color_depth(fbl->multisample_fb, (const float[4]){0.0f}, 1.0f); \ + DRW_stats_query_end(); \ + } \ +} + +#define MULTISAMPLE_GP_SYNC_DISABLE(lvl, fbl, fb, txl) { \ + if ((lvl > 0) && (fbl->multisample_fb != NULL)) { \ + DRW_stats_query_start("GP Multisample Resolve"); \ + GPU_framebuffer_bind(fb); \ + DRW_multisamples_resolve(txl->multisample_depth, txl->multisample_color, true); \ + DRW_stats_query_end(); \ + } \ +} + +#endif /* __GPENCIL_ENGINE_H__ */ diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c new file mode 100644 index 00000000000..d76ea56894f --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -0,0 +1,353 @@ +/* + * Copyright 2017, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Antonio Vazquez + * + */ + +/** \file blender/draw/engines/gpencil/gpencil_render.c + * \ingroup draw + */ +#include "BLI_rect.h" + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "BKE_camera.h" + +#include "DNA_gpencil_types.h" + +#include "DEG_depsgraph_query.h" + +#include "draw_mode_engines.h" + +#include "RE_pipeline.h" + +#include "gpencil_engine.h" + +/* Get pixel size for render +* This function uses the same calculation used for viewport, because if use +* camera pixelsize, the result is not correct. +*/ +static float get_render_pixelsize(float persmat[4][4], int winx, int winy) +{ + float v1[3], v2[3]; + float len_px, len_sc; + + v1[0] = persmat[0][0]; + v1[1] = persmat[1][0]; + v1[2] = persmat[2][0]; + + v2[0] = persmat[0][1]; + v2[1] = persmat[1][1]; + v2[2] = persmat[2][1]; + + len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); + len_sc = (float)MAX2(winx, winy); + + return len_px / len_sc; +} + +/* init render data */ +void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph) +{ + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_StorageList *stl = vedata->stl; + GPENCIL_FramebufferList *fbl = vedata->fbl; + + Scene *scene = DEG_get_evaluated_scene(depsgraph); + const float *viewport_size = DRW_viewport_size_get(); + const int size[2] = { (int)viewport_size[0], (int)viewport_size[1] }; + + /* In render mode the default framebuffer is not generated + * because there is no viewport. So we need to manually create one + * NOTE : use 32 bit format for precision in render mode. + */ + /* create multiframe framebuffer for AA */ + if (U.gpencil_multisamples > 0) { + int rect_w = (int)viewport_size[0]; + int rect_h = (int)viewport_size[1]; + DRW_gpencil_multisample_ensure(vedata, rect_w, rect_h); + } + + vedata->render_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + vedata->render_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA32F, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config(&fbl->main, { + GPU_ATTACHMENT_TEXTURE(vedata->render_depth_tx), + GPU_ATTACHMENT_TEXTURE(vedata->render_color_tx) + }); + + /* Alloc transient data. */ + if (!stl->g_data) { + stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); + } + + /* Set the pers & view matrix. */ + struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + float frame = BKE_scene_frame_get(scene); + RE_GetCameraWindow(engine->re, camera, frame, stl->storage->winmat); + RE_GetCameraModelMatrix(engine->re, camera, stl->storage->viewinv); + + invert_m4_m4(stl->storage->viewmat, stl->storage->viewinv); + mul_m4_m4m4(stl->storage->persmat, stl->storage->winmat, stl->storage->viewmat); + invert_m4_m4(stl->storage->persinv, stl->storage->persmat); + invert_m4_m4(stl->storage->wininv, stl->storage->winmat); + + DRW_viewport_matrix_override_set(stl->storage->persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(stl->storage->persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(stl->storage->winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(stl->storage->wininv, DRW_MAT_WININV); + DRW_viewport_matrix_override_set(stl->storage->viewmat, DRW_MAT_VIEW); + DRW_viewport_matrix_override_set(stl->storage->viewinv, DRW_MAT_VIEWINV); + + /* calculate pixel size for render */ + stl->storage->render_pixsize = get_render_pixelsize(stl->storage->persmat, viewport_size[0], viewport_size[1]); + /* INIT CACHE */ + GPENCIL_cache_init(vedata); +} + +/* render all objects and select only grease pencil */ +static void GPENCIL_render_cache( + void *vedata, struct Object *ob, + struct RenderEngine *UNUSED(engine), struct Depsgraph *UNUSED(depsgraph)) +{ + if ((ob == NULL) || (DRW_check_object_visible_within_active_context(ob) == false)) { + return; + } + + if (ob->type == OB_GPENCIL) { + GPENCIL_cache_populate(vedata, ob); + } +} + +/* TODO: Reuse Eevee code in shared module instead to duplicate here */ +static void GPENCIL_render_update_viewvecs(float invproj[4][4], float winmat[4][4], float(*r_viewvecs)[4]) +{ + /* view vectors for the corners of the view frustum. + * Can be used to recreate the world space position easily */ + float view_vecs[4][4] = { + { -1.0f, -1.0f, -1.0f, 1.0f }, + { 1.0f, -1.0f, -1.0f, 1.0f }, + { -1.0f, 1.0f, -1.0f, 1.0f }, + { -1.0f, -1.0f, 1.0f, 1.0f } + }; + + /* convert the view vectors to view space */ + const bool is_persp = (winmat[3][3] == 0.0f); + for (int i = 0; i < 4; i++) { + mul_project_m4_v3(invproj, view_vecs[i]); + /* normalized trick see: + * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + if (is_persp) { + /* Divide XY by Z. */ + mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]); + } + } + + /** + * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and + * view_vecs[1] is the vector going from the near-bottom-left corner to + * the far-top-right corner. + * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner + * when Z = 1, and top-left corner if Z = 1. + * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed) + * distance from the near plane to the far clip plane. + **/ + copy_v4_v4(r_viewvecs[0], view_vecs[0]); + + /* we need to store the differences */ + r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0]; + r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1]; + r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2]; +} + +/* Update view_vecs */ +static void GPENCIL_render_update_vecs(GPENCIL_Data *vedata) +{ + GPENCIL_StorageList *stl = vedata->stl; + + float invproj[4][4], winmat[4][4]; + DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); + DRW_viewport_matrix_get(invproj, DRW_MAT_WININV); + + /* this is separated to keep function equal to Eevee for future reuse of same code */ + GPENCIL_render_update_viewvecs(invproj, winmat, stl->storage->view_vecs); +} + +/* read z-depth render result */ +static void GPENCIL_render_result_z(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, const rcti *rect) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + GPENCIL_StorageList *stl = vedata->stl; + + if ((view_layer->passflag & SCE_PASS_Z) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); + + GPU_framebuffer_read_depth(vedata->fbl->main, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), rp->rect); + + bool is_persp = DRW_viewport_is_persp_get(); + + GPENCIL_render_update_vecs(vedata); + + /* Convert ogl depth [0..1] to view Z [near..far] */ + for (int i = 0; i < BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); i++) { + if (rp->rect[i] == 1.0f) { + rp->rect[i] = 1e10f; /* Background */ + } + else { + if (is_persp) { + rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; + rp->rect[i] = stl->storage->winmat[3][2] / (rp->rect[i] + stl->storage->winmat[2][2]); + } + else { + rp->rect[i] = -stl->storage->view_vecs[0][2] + rp->rect[i] * -stl->storage->view_vecs[1][2]; + } + } + } + } +} + +/* read combined render result */ +static void GPENCIL_render_result_combined(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, const rcti *rect) +{ + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname); + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + + GPU_framebuffer_bind(fbl->main); + GPU_framebuffer_read_color(vedata->fbl->main, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 4, 0, rp->rect); +} + +/* helper to blend pixels */ +static void blend_pixel(float src[4], float dst[4]) +{ + float alpha = src[3]; + + /* use blend: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA */ + dst[0] = (src[0] * alpha) + (dst[0] * (1.0f - alpha)); + dst[1] = (src[1] * alpha) + (dst[1] * (1.0f - alpha)); + dst[2] = (src[2] * alpha) + (dst[2] * (1.0f - alpha)); +} + +/* render grease pencil to image */ +void GPENCIL_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) +{ + const char *viewname = RE_GetActiveRenderView(engine->re); + const DRWContextState *draw_ctx = DRW_context_state_get(); + int imgsize = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); + + /* save previous render data */ + RenderPass *rpass_color_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); + RenderPass *rpass_depth_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname); + float *src_rect_color_data = NULL; + float *src_rect_depth_data = NULL; + if ((rpass_color_src) && (rpass_depth_src) && (rpass_color_src->rect) && (rpass_depth_src->rect)) { + src_rect_color_data = MEM_dupallocN(rpass_color_src->rect); + src_rect_depth_data = MEM_dupallocN(rpass_depth_src->rect); + } + else { + /* TODO: put this message in a better place */ + printf("Warning: To render grease pencil, enable Combined and Z passes.\n"); + } + + GPENCIL_engine_init(vedata); + GPENCIL_render_init(vedata, engine, draw_ctx->depsgraph); + + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + Object *camera = DEG_get_evaluated_object(draw_ctx->depsgraph, RE_GetCamera(engine->re)); + stl->storage->camera = camera; /* save current camera */ + + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + if (fbl->main) { + GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx, 0, 0); + GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx, 0, 0); + /* clean first time the buffer */ + float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + GPU_framebuffer_bind(fbl->main); + GPU_framebuffer_clear_color_depth(fbl->main, clearcol, 1.0f); + } + + /* loop all objects and draw */ + DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache); + + GPENCIL_cache_finish(vedata); + GPENCIL_draw_scene(vedata); + + /* combined data */ + GPENCIL_render_result_combined(render_layer, viewname, vedata, rect); + /* z-depth data */ + GPENCIL_render_result_z(render_layer, viewname, vedata, rect); + + /* detach textures */ + if (fbl->main) { + GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx); + GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx); + } + + /* merge previous render image with new GP image */ + if (src_rect_color_data) { + RenderPass *rpass_color_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); + RenderPass *rpass_depth_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname); + float *gp_rect_color_data = rpass_color_gp->rect; + float *gp_rect_depth_data = rpass_depth_gp->rect; + float *gp_pixel_rgba; + float *gp_pixel_depth; + float *src_pixel_rgba; + float *src_pixel_depth; + float tmp[4]; + + for (int i = 0; i < imgsize; i++) { + gp_pixel_rgba = &gp_rect_color_data[i * 4]; + gp_pixel_depth = &gp_rect_depth_data[i]; + + src_pixel_rgba = &src_rect_color_data[i * 4]; + src_pixel_depth = &src_rect_depth_data[i]; + + /* check grease pencil render transparency */ + if (gp_pixel_rgba[3] > 0.0f) { + copy_v4_v4(tmp, gp_pixel_rgba); + if (src_pixel_rgba[3] > 0.0f) { + /* copy source color on back */ + copy_v4_v4(gp_pixel_rgba, src_pixel_rgba); + /* check z-depth */ + if (gp_pixel_depth[0] > src_pixel_depth[0]) { + /* copy source z-depth */ + gp_pixel_depth[0] = src_pixel_depth[0]; + /* blend gp render */ + blend_pixel(tmp, gp_pixel_rgba); + /* blend object on top */ + blend_pixel(src_pixel_rgba, gp_pixel_rgba); + } + else { + /* blend gp render */ + blend_pixel(tmp, gp_pixel_rgba); + } + } + } + else { + copy_v4_v4(gp_pixel_rgba, src_pixel_rgba); + gp_pixel_depth[0] = src_pixel_depth[0]; + } + } + + /* free memory */ + MEM_SAFE_FREE(src_rect_color_data); + MEM_SAFE_FREE(src_rect_depth_data); + } +} diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c new file mode 100644 index 00000000000..e453224020d --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -0,0 +1,848 @@ +/* + * Copyright 2017, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Antonio Vazquez + * + */ + +/** \file blender/draw/engines/gpencil/gpencil_shader_fx.c + * \ingroup draw + */ +#include "DNA_gpencil_types.h" +#include "DNA_shader_fx_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_camera_types.h" + +#include "BKE_gpencil.h" +#include "BKE_shader_fx.h" + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "BKE_camera.h" + +#include "ED_view3d.h" +#include "ED_gpencil.h" + +#include "gpencil_engine.h" + +extern char datatoc_gpencil_fx_blur_frag_glsl[]; +extern char datatoc_gpencil_fx_colorize_frag_glsl[]; +extern char datatoc_gpencil_fx_flip_frag_glsl[]; +extern char datatoc_gpencil_fx_light_frag_glsl[]; +extern char datatoc_gpencil_fx_pixel_frag_glsl[]; +extern char datatoc_gpencil_fx_rim_prepare_frag_glsl[]; +extern char datatoc_gpencil_fx_rim_resolve_frag_glsl[]; +extern char datatoc_gpencil_fx_swirl_frag_glsl[]; +extern char datatoc_gpencil_fx_wave_frag_glsl[]; + +/* verify if this fx is active */ +static bool effect_is_active(Object *ob, ShaderFxData *fx, bool is_render) +{ + if (fx == NULL) { + return false; + } + + bGPdata *gpd = ob->data; + if (gpd == NULL) { + return false; + } + + bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); + if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit)) { + return false; + } + + if (((fx->mode & eShaderFxMode_Realtime) && (is_render == false)) || + ((fx->mode & eShaderFxMode_Render) && (is_render == true))) + { + return true; + } + + return false; +} + +/* get normal of draw using one stroke of visible layer +* /param gpd GP datablock +* /param r_point Point on plane +* /param r_normal Normal vector +*/ +static bool get_normal_vector(bGPdata *gpd, float r_point[3], float r_normal[3]) +{ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->flag & GP_LAYER_HIDE) + continue; + + /* get frame */ + bGPDframe *gpf = gpl->actframe; + if (gpf == NULL) + continue; + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + if (gps->totpoints >= 3) { + bGPDspoint *pt = &gps->points[0]; + BKE_gpencil_stroke_normal(gps, r_normal); + /* in some weird situations, the normal cannot be calculated, so try next stroke */ + if ((r_normal[0] != 0.0f) || (r_normal[1] != 0.0f) || (r_normal[2] != 0.0f)) { + copy_v3_v3(r_point, &pt->x); + return true; + } + } + } + } + + return false; +} + +/* helper to get near and far depth of field values */ +static void GPENCIL_dof_nearfar(Object *camera, float coc, float nearfar[2]) +{ + if (camera == NULL) { + return; + } + + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + Camera *cam = (Camera *)camera->data; + + float fstop = cam->gpu_dof.fstop; + float focus_dist = BKE_camera_object_dof_distance(camera); + float focal_len = cam->lens; + + /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm + * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though + * because the shader reads coordinates in world space, which is in blender units. + * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */ + float scale = (scene->unit.system) ? scene->unit.scale_length : 1.0f; + float scale_camera = 0.001f / scale; + /* we want radius here for the aperture number */ + float aperture_scaled = 0.5f * scale_camera * focal_len / fstop; + float focal_len_scaled = scale_camera * focal_len; + + float hyperfocal = (focal_len_scaled * focal_len_scaled) / (aperture_scaled * coc); + nearfar[0] = (hyperfocal * focus_dist) / (hyperfocal + focal_len); + nearfar[1] = (hyperfocal * focus_dist) / (hyperfocal - focal_len); +} + +/* **************** Shader Effects ***************************** */ + +/* Gaussian Blur FX + * The effect is done using two shading groups because is faster to apply horizontal + * and vertical in different operations. + */ +static void DRW_gpencil_fx_blur( + ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data, + GPENCIL_Data *vedata, tGPencilObjectCache *cache) +{ + if (fx == NULL) { + return; + } + + BlurShaderFxData *fxd = (BlurShaderFxData *)fx; + + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + RegionView3D *rv3d = draw_ctx->rv3d; + DRWShadingGroup *fx_shgrp; + + Object *ob = cache->ob; + bGPdata *gpd = (bGPdata *)ob->data; + + fxd->blur[0] = fxd->radius[0]; + fxd->blur[1] = fxd->radius[1]; + + /* init weight */ + if (fxd->flag & FX_BLUR_DOF_MODE) { + /* viewport and opengl render */ + Object *camera = NULL; + if (rv3d) { + if (rv3d->persp == RV3D_CAMOB) { + camera = v3d->camera; + } + } + else { + camera = stl->storage->camera; + } + + if (camera) { + float nearfar[2]; + GPENCIL_dof_nearfar(camera, fxd->coc, nearfar); + float zdepth = stl->g_data->gp_object_cache[ob_idx].zdepth; + /* the object is on focus area */ + if ((zdepth >= nearfar[0]) && (zdepth <= nearfar[1])) { + fxd->blur[0] = 0; + fxd->blur[1] = 0; + } + else { + float f; + if (zdepth < nearfar[0]) { + f = nearfar[0] - zdepth; + } + else { + f = zdepth - nearfar[1]; + } + fxd->blur[0] = f; + fxd->blur[1] = f; + CLAMP2(&fxd->blur[0], 0, fxd->radius[0]); + } + } + else { + /* if not camera view, the blur is disabled */ + fxd->blur[0] = 0; + fxd->blur[1] = 0; + } + } + + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, + psl->fx_shader_pass_blend); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2); + + DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &ob->loc[0], 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); + + fxd->runtime.fx_sh = fx_shgrp; +} + +/* Colorize FX */ +static void DRW_gpencil_fx_colorize( + ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata) +{ + if (fx == NULL) { + return; + } + ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + DRWShadingGroup *fx_shgrp; + + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_colorize_sh, psl->fx_shader_pass); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + DRW_shgroup_uniform_vec4(fx_shgrp, "low_color", &fxd->low_color[0], 1); + DRW_shgroup_uniform_vec4(fx_shgrp, "high_color", &fxd->high_color[0], 1); + DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1); + DRW_shgroup_uniform_float(fx_shgrp, "factor", &fxd->factor, 1); + + fxd->runtime.fx_sh = fx_shgrp; +} + +/* Flip FX */ +static void DRW_gpencil_fx_flip( + ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata) +{ + if (fx == NULL) { + return; + } + FlipShaderFxData *fxd = (FlipShaderFxData *)fx; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + DRWShadingGroup *fx_shgrp; + + fxd->flipmode = 100; + /* the number works as bit flag */ + if (fxd->flag & FX_FLIP_HORIZONTAL) { + fxd->flipmode += 10; + } + if (fxd->flag & FX_FLIP_VERTICAL) { + fxd->flipmode += 1; + } + + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_flip_sh, psl->fx_shader_pass); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + DRW_shgroup_uniform_int(fx_shgrp, "flipmode", &fxd->flipmode, 1); + + DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1); + + fxd->runtime.fx_sh = fx_shgrp; +} + +/* Light FX */ +static void DRW_gpencil_fx_light( + ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, + tGPencilObjectCache *cache) +{ + if (fx == NULL) { + return; + } + Object *ob = cache->ob; + LightShaderFxData *fxd = (LightShaderFxData *)fx; + + if (fxd->object == NULL) { + return; + } + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + DRWShadingGroup *fx_shgrp; + + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_light_sh, psl->fx_shader_pass); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + + DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); + + /* location of the light using obj location as origin */ + copy_v3_v3(fxd->loc, &fxd->object->loc[0]); + + /* Calc distance to strokes plane + * The w component of location is used to transfer the distance to drawing plane + */ + float r_point[3], r_normal[3]; + float r_plane[4]; + bGPdata *gpd = (bGPdata *)ob->data; + if (!get_normal_vector(gpd, r_point, r_normal)) { + return; + } + mul_mat3_m4_v3(ob->obmat, r_normal); /* only rotation component */ + plane_from_point_normal_v3(r_plane, r_point, r_normal); + float dt = dist_to_plane_v3(fxd->object->loc, r_plane); + fxd->loc[3] = dt; /* use last element to save it */ + + DRW_shgroup_uniform_vec4(fx_shgrp, "loc", &fxd->loc[0], 1); + + DRW_shgroup_uniform_float(fx_shgrp, "energy", &fxd->energy, 1); + DRW_shgroup_uniform_float(fx_shgrp, "ambient", &fxd->ambient, 1); + + DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); + + fxd->runtime.fx_sh = fx_shgrp; +} + +/* Pixelate FX */ +static void DRW_gpencil_fx_pixel( + ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, + tGPencilObjectCache *cache) +{ + if (fx == NULL) { + return; + } + Object *ob = cache->ob; + PixelShaderFxData *fxd = (PixelShaderFxData *)fx; + + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + DRWShadingGroup *fx_shgrp; + bGPdata *gpd = (bGPdata *)ob->data; + + fxd->size[2] = (int)fxd->flag & FX_PIXEL_USE_LINES; + + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_pixel_sh, psl->fx_shader_pass); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + DRW_shgroup_uniform_int(fx_shgrp, "size", &fxd->size[0], 3); + DRW_shgroup_uniform_vec4(fx_shgrp, "color", &fxd->rgba[0], 1); + + DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &ob->loc[0], 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); + + fxd->runtime.fx_sh = fx_shgrp; +} + +/* Rim FX */ +static void DRW_gpencil_fx_rim( + ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, + tGPencilObjectCache *cache) +{ + if (fx == NULL) { + return; + } + Object *ob = cache->ob; + RimShaderFxData *fxd = (RimShaderFxData *)fx; + + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + DRWShadingGroup *fx_shgrp; + bGPdata *gpd = (bGPdata *)ob->data; + + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + /* prepare pass */ + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_prepare_sh, + psl->fx_shader_pass_blend); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); + + DRW_shgroup_uniform_int(fx_shgrp, "offset", &fxd->offset[0], 2); + DRW_shgroup_uniform_vec3(fx_shgrp, "rim_color", &fxd->rim_rgb[0], 1); + DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1); + + DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &ob->loc[0], 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); + + fxd->runtime.fx_sh = fx_shgrp; + + /* blur pass */ + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, + psl->fx_shader_pass_blend); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_rim); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_rim); + DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2); + + DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &ob->loc[0], 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); + + fxd->runtime.fx_sh_b = fx_shgrp; + + /* resolve pass */ + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_resolve_sh, + psl->fx_shader_pass_blend); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeRim", &e_data->temp_color_tx_rim); + DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1); + DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1); + + fxd->runtime.fx_sh_c = fx_shgrp; +} + +/* Swirl FX */ +static void DRW_gpencil_fx_swirl( + ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, + tGPencilObjectCache *cache) +{ + if (fx == NULL) { + return; + } + Object *ob = cache->ob; + SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; + if (fxd->object == NULL) { + return; + } + + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + DRWShadingGroup *fx_shgrp; + bGPdata *gpd = (bGPdata *)ob->data; + + fxd->transparent = (int)fxd->flag & FX_SWIRL_MAKE_TRANSPARENT; + + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_swirl_sh, psl->fx_shader_pass); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + + DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); + + DRW_shgroup_uniform_vec3(fx_shgrp, "loc", &fxd->object->loc[0], 1); + + DRW_shgroup_uniform_int(fx_shgrp, "radius", &fxd->radius, 1); + DRW_shgroup_uniform_float(fx_shgrp, "angle", &fxd->angle, 1); + DRW_shgroup_uniform_int(fx_shgrp, "transparent", &fxd->transparent, 1); + + DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); + DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); + + fxd->runtime.fx_sh = fx_shgrp; +} + +/* Wave Distorsion FX */ +static void DRW_gpencil_fx_wave( + ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata) +{ + if (fx == NULL) { + return; + } + + WaveShaderFxData *fxd = (WaveShaderFxData *)fx; + + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + + DRWShadingGroup *fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_wave_sh, psl->fx_shader_pass); + DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); + DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); + DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1); + DRW_shgroup_uniform_float(fx_shgrp, "period", &fxd->period, 1); + DRW_shgroup_uniform_float(fx_shgrp, "phase", &fxd->phase, 1); + DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1); + DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1); + + fxd->runtime.fx_sh = fx_shgrp; +} + +/* ************************************************************** */ + +/* create all FX shaders */ +void GPENCIL_create_fx_shaders(GPENCIL_e_data *e_data) +{ + /* fx shaders (all in screen space) */ + if (!e_data->gpencil_fx_blur_sh) { + e_data->gpencil_fx_blur_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_blur_frag_glsl, NULL); + } + if (!e_data->gpencil_fx_colorize_sh) { + e_data->gpencil_fx_colorize_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_colorize_frag_glsl, NULL); + } + if (!e_data->gpencil_fx_flip_sh) { + e_data->gpencil_fx_flip_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_flip_frag_glsl, NULL); + } + if (!e_data->gpencil_fx_light_sh) { + e_data->gpencil_fx_light_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_light_frag_glsl, NULL); + } + if (!e_data->gpencil_fx_pixel_sh) { + e_data->gpencil_fx_pixel_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_pixel_frag_glsl, NULL); + } + if (!e_data->gpencil_fx_rim_prepare_sh) { + e_data->gpencil_fx_rim_prepare_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_rim_prepare_frag_glsl, NULL); + + e_data->gpencil_fx_rim_resolve_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_rim_resolve_frag_glsl, NULL); + } + if (!e_data->gpencil_fx_swirl_sh) { + e_data->gpencil_fx_swirl_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_swirl_frag_glsl, NULL); + } + if (!e_data->gpencil_fx_wave_sh) { + e_data->gpencil_fx_wave_sh = DRW_shader_create_fullscreen( + datatoc_gpencil_fx_wave_frag_glsl, NULL); + } +} + +/* free FX shaders */ +void GPENCIL_delete_fx_shaders(GPENCIL_e_data *e_data) +{ + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_blur_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_colorize_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_flip_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_light_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_pixel_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_prepare_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_resolve_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_swirl_sh); + DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_wave_sh); +} + +/* create all passes used by FX */ +void GPENCIL_create_fx_passes(GPENCIL_PassList *psl) +{ + psl->fx_shader_pass = DRW_pass_create( + "GPencil Shader FX Pass", + DRW_STATE_WRITE_COLOR | + DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + psl->fx_shader_pass_blend = DRW_pass_create( + "GPencil Shader FX Pass", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | + DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); +} + + +/* prepare fx shading groups */ +void DRW_gpencil_fx_prepare( + struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, + struct tGPencilObjectCache *cache) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + Object *ob = cache->ob; + int ob_idx = cache->idx; + + if (ob->shader_fx.first == NULL) { + return; + } + /* loop FX */ + for (ShaderFxData *fx = ob->shader_fx.first; fx; fx = fx->next) { + if (effect_is_active(ob, fx, stl->storage->is_render)) { + switch (fx->type) { + case eShaderFxType_Blur: + DRW_gpencil_fx_blur(fx, ob_idx, e_data, vedata, cache); + break; + case eShaderFxType_Colorize: + DRW_gpencil_fx_colorize(fx, e_data, vedata); + break; + case eShaderFxType_Flip: + DRW_gpencil_fx_flip(fx, e_data, vedata); + break; + case eShaderFxType_Light: + DRW_gpencil_fx_light(fx, e_data, vedata, cache); + break; + case eShaderFxType_Pixel: + DRW_gpencil_fx_pixel(fx, e_data, vedata, cache); + break; + case eShaderFxType_Rim: + DRW_gpencil_fx_rim(fx, e_data, vedata, cache); + break; + case eShaderFxType_Swirl: + DRW_gpencil_fx_swirl(fx, e_data, vedata, cache); + break; + case eShaderFxType_Wave: + DRW_gpencil_fx_wave(fx, e_data, vedata); + break; + default: + break; + } + } + } + +} + +/* helper to draw one FX pass and do ping-pong copy */ +static void gpencil_draw_fx_pass( + GPENCIL_e_data *e_data, + GPENCIL_PassList *psl, + GPENCIL_FramebufferList *fbl, + DRWShadingGroup *shgrp, bool blend) +{ + if (shgrp == NULL) { + return; + } + + static float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + GPU_framebuffer_bind(fbl->temp_fb_b); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f); + + /* draw effect pass in temp texture (B) using as source the previous image + * existing in the other temp texture (A) */ + if (!blend) { + DRW_draw_pass_subset(psl->fx_shader_pass, shgrp, shgrp); + } + else { + DRW_draw_pass_subset(psl->fx_shader_pass_blend, shgrp, shgrp); + } + + /* copy pass from b to a for ping-pong frame buffers */ + e_data->input_depth_tx = e_data->temp_depth_tx_b; + e_data->input_color_tx = e_data->temp_color_tx_b; + + GPU_framebuffer_bind(fbl->temp_fb_a); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f); + DRW_draw_pass(psl->mix_pass_noblend); +} + +/* helper to manage gaussian blur passes */ +static void draw_gpencil_blur_passes( + struct GPENCIL_e_data *e_data, + struct GPENCIL_Data *vedata, + struct BlurShaderFxData *fxd) +{ + if (fxd->runtime.fx_sh == NULL) { + return; + } + + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + DRWShadingGroup *shgrp = fxd->runtime.fx_sh; + int samples = fxd->samples; + + float bx = fxd->blur[0]; + float by = fxd->blur[1]; + + /* the blur is done in two steps (Hor/Ver) because is faster and + * gets better result + * + * samples could be 0 and disable de blur effects because sometimes + * is easier animate the number of samples only, instead to animate the + * hide/unhide and the number of samples to make some effects. + */ + for (int b = 0; b < samples; b++) { + /* horizontal */ + if (bx > 0) { + fxd->blur[0] = bx; + fxd->blur[1] = 0; + gpencil_draw_fx_pass(e_data, psl, fbl, shgrp, true); + } + /* vertical */ + if (by > 0) { + fxd->blur[0] = 0; + fxd->blur[1] = by; + gpencil_draw_fx_pass(e_data, psl, fbl, shgrp, true); + } + } +} + +static void draw_gpencil_rim_blur( + struct GPENCIL_e_data *UNUSED(e_data), + struct GPENCIL_Data *vedata, + struct RimShaderFxData *fxd) +{ + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + static float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + GPU_framebuffer_bind(fbl->temp_fb_b); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f); + DRW_draw_pass_subset(psl->fx_shader_pass_blend, + fxd->runtime.fx_sh_b, fxd->runtime.fx_sh_b); + + /* copy pass from b for ping-pong frame buffers */ + GPU_framebuffer_bind(fbl->temp_fb_rim); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_rim, clearcol, 1.0f); + DRW_draw_pass(psl->mix_pass_noblend); +} + +/* helper to draw RIM passes */ +static void draw_gpencil_rim_passes( + struct GPENCIL_e_data *e_data, + struct GPENCIL_Data *vedata, + struct RimShaderFxData *fxd) +{ + if (fxd->runtime.fx_sh_b == NULL) { + return; + } + + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + + static float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + int bx = fxd->blur[0]; + int by = fxd->blur[1]; + + /* prepare mask */ + GPU_framebuffer_bind(fbl->temp_fb_rim); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_rim, clearcol, 1.0f); + DRW_draw_pass_subset( + psl->fx_shader_pass_blend, + fxd->runtime.fx_sh, fxd->runtime.fx_sh); + + /* blur rim */ + e_data->input_depth_tx = e_data->temp_depth_tx_b; + e_data->input_color_tx = e_data->temp_color_tx_b; + + if ((fxd->samples > 0) && ((bx > 0) || (by > 0))) { + for (int x = 0; x < fxd->samples; x++) { + + /* horizontal */ + fxd->blur[0] = bx; + fxd->blur[1] = 0; + draw_gpencil_rim_blur(e_data, vedata, fxd); + + /* Vertical */ + fxd->blur[0] = 0; + fxd->blur[1] = by; + draw_gpencil_rim_blur(e_data, vedata, fxd); + + fxd->blur[0] = bx; + fxd->blur[1] = by; + } + } + /* resolve */ + GPU_framebuffer_bind(fbl->temp_fb_b); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f); + DRW_draw_pass_subset( + psl->fx_shader_pass_blend, + fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c); + + /* copy pass from b to a for ping-pong frame buffers */ + e_data->input_depth_tx = e_data->temp_depth_tx_b; + e_data->input_color_tx = e_data->temp_color_tx_b; + + GPU_framebuffer_bind(fbl->temp_fb_a); + GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f); + DRW_draw_pass(psl->mix_pass_noblend); +} + +/* apply all object fx effects */ +void DRW_gpencil_fx_draw( + struct GPENCIL_e_data *e_data, + struct GPENCIL_Data *vedata, struct tGPencilObjectCache *cache) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; + Object *ob = cache->ob; + + /* loop FX modifiers */ + for (ShaderFxData *fx = ob->shader_fx.first; fx; fx = fx->next) { + if (effect_is_active(ob, fx, stl->storage->is_render)) { + switch (fx->type) { + case eShaderFxType_Blur: + { + BlurShaderFxData *fxd = (BlurShaderFxData *)fx; + draw_gpencil_blur_passes(e_data, vedata, fxd); + break; + } + case eShaderFxType_Colorize: + { + ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx; + gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false); + break; + } + case eShaderFxType_Flip: + { + FlipShaderFxData *fxd = (FlipShaderFxData *)fx; + gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false); + break; + } + case eShaderFxType_Light: + { + LightShaderFxData *fxd = (LightShaderFxData *)fx; + gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false); + break; + } + case eShaderFxType_Pixel: + { + PixelShaderFxData *fxd = (PixelShaderFxData *)fx; + gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false); + break; + } + case eShaderFxType_Rim: + { + RimShaderFxData *fxd = (RimShaderFxData *)fx; + draw_gpencil_rim_passes(e_data, vedata, fxd); + break; + } + case eShaderFxType_Swirl: + { + SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; + gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false); + break; + } + case eShaderFxType_Wave: + { + WaveShaderFxData *fxd = (WaveShaderFxData *)fx; + gpencil_draw_fx_pass(e_data, psl, fbl, fxd->runtime.fx_sh, false); + break; + } + default: + break; + } + } + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl new file mode 100644 index 00000000000..1d66ba3d4d4 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl @@ -0,0 +1,60 @@ +uniform mat4 ProjectionMatrix; +uniform mat4 ViewMatrix; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; + +uniform int blur[2]; + +uniform vec3 loc; +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform float pixfactor; + +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); +vec2 noffset = vec2(blur[0], blur[1]); + +out vec4 FragColor; + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + + vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); + + float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) : (noffset[0] / defaultpixsize); + float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) : (noffset[1] / defaultpixsize); + + /* apply blurring, using a 9-tap filter with predefined gaussian weights */ + /* depth */ + float outdepth = 0; + outdepth += texelFetch(strokeDepth, ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy), 0).r * 0.0947416; + outdepth += texelFetch(strokeDepth, ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy), 0).r * 0.118318; + outdepth += texelFetch(strokeDepth, ivec2(uv.x + 1.0 * dx, uv.y + 1.0 * dy), 0).r * 0.0947416; + outdepth += texelFetch(strokeDepth, ivec2(uv.x - 1.0 * dx, uv.y + 0.0 * dy), 0).r * 0.118318; + + outdepth += texelFetch(strokeDepth, ivec2(uv.x, uv.y), 0).r * 0.147761; + + outdepth += texelFetch(strokeDepth, ivec2(uv.x + 1.0 * dx, uv.y + 0.0 * dy), 0).r * 0.118318; + outdepth += texelFetch(strokeDepth, ivec2(uv.x - 1.0 * dx, uv.y - 1.0 * dy), 0).r * 0.0947416; + outdepth += texelFetch(strokeDepth, ivec2(uv.x + 0.0 * dx, uv.y - 1.0 * dy), 0).r * 0.118318; + outdepth += texelFetch(strokeDepth, ivec2(uv.x + 1.0 * dx, uv.y - 1.0 * dy), 0).r * 0.0947416; + + gl_FragDepth = outdepth; + + /* color */ + vec4 outcolor = vec4(0.0); + outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416; + outcolor += texelFetch(strokeColor, ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy), 0) * 0.118318; + outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416; + outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318; + + outcolor += texelFetch(strokeColor, ivec2(uv.x, uv.y), 0) * 0.147761; + + outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318; + outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416; + outcolor += texelFetch(strokeColor, ivec2(uv.x + 0.0 * dx, uv.y - 1.0 * dy), 0) * 0.118318; + outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416; + + FragColor = clamp(outcolor, 0, 1.0); +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl new file mode 100644 index 00000000000..7d0ce4a804e --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl @@ -0,0 +1,86 @@ +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; + +uniform vec4 low_color; +uniform vec4 high_color; +uniform int mode; +uniform float factor; + +out vec4 FragColor; + +#define MODE_GRAYSCALE 0 +#define MODE_SEPIA 1 +#define MODE_BITONE 2 +#define MODE_CUSTOM 3 +#define MODE_TRANSPARENT 4 + +float get_luminance(vec4 color) +{ + float lum = (color.r * 0.2126) + (color.g * 0.7152) + (color.b * 0.723); + return lum; +} + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + + float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r; + vec4 src_pixel= texelFetch(strokeColor, uv.xy, 0); + float luminance = get_luminance(src_pixel); + vec4 outcolor; + + /* is transparent */ + if (src_pixel.a == 0.0f) { + discard; + } + + switch(mode) { + case MODE_GRAYSCALE: + { + outcolor = vec4(luminance, luminance, luminance, src_pixel.a); + break; + } + case MODE_SEPIA: + { + float Red = (src_pixel.r * 0.393) + (src_pixel.g * 0.769) + (src_pixel.b * 0.189); + float Green = (src_pixel.r * 0.349) + (src_pixel.g * 0.686) + (src_pixel.b * 0.168); + float Blue = (src_pixel.r * 0.272) + (src_pixel.g * 0.534) + (src_pixel.b * 0.131); + outcolor = vec4(Red, Green, Blue, src_pixel.a); + break; + } + case MODE_BITONE: + { + if (luminance <= factor) { + outcolor = low_color; + } + else { + outcolor = high_color; + } + break; + } + case MODE_CUSTOM: + { + /* if below umbral, force custom color */ + if (luminance <= factor) { + outcolor = low_color; + } + else { + outcolor = vec4(luminance * low_color.r, luminance * low_color.b, luminance * low_color.b, src_pixel.a); + } + break; + } + case MODE_TRANSPARENT: + { + outcolor = vec4(src_pixel.rgb, src_pixel.a * factor); + break; + } + default: + { + outcolor = src_pixel; + } + + } + + gl_FragDepth = stroke_depth; + FragColor = outcolor; +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl new file mode 100644 index 00000000000..94fb3405c79 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl @@ -0,0 +1,37 @@ +out vec4 FragColor; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; +uniform vec2 wsize; +uniform int flipmode; + +void main() +{ + vec2 mode = vec2(0,0); + /* horz. */ + if (flipmode >= 110) { + mode[0] = 1; + } + /* vert. */ + if ((flipmode == 101) || (flipmode == 111)) { + mode[1] = 1; + } + + vec2 uv = vec2(gl_FragCoord.xy); + float stroke_depth; + vec4 outcolor; + + if (mode[0] > 0) { + uv.x = wsize.x - uv.x; + } + if (mode[1] > 0) { + uv.y = wsize.y - uv.y; + } + + ivec2 iuv = ivec2(uv.x, uv.y); + stroke_depth = texelFetch(strokeDepth, iuv, 0).r; + outcolor = texelFetch(strokeColor, iuv, 0); + + gl_FragDepth = stroke_depth; + FragColor = outcolor; +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl new file mode 100644 index 00000000000..f3026c32fc8 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl @@ -0,0 +1,70 @@ +uniform mat4 ProjectionMatrix; +uniform mat4 ViewMatrix; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; +uniform vec2 Viewport; +uniform vec4 loc; +uniform float energy; +uniform float ambient; + +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform float pixfactor; + +out vec4 FragColor; + +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); + +#define height loc.w + +/* project 3d point to 2d on screen space */ +vec2 toScreenSpace(vec4 vertex) +{ + /* need to calculate ndc because this is not done by vertex shader */ + vec3 ndc = vec3(vertex).xyz / vertex.w; + + vec2 sc; + sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x; + sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y; + + return sc; +} + +void main() +{ + float stroke_depth; + vec4 objcolor; + + vec4 light_loc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); + vec2 light2d = toScreenSpace(light_loc); + + /* calc pixel scale */ + float pxscale = (ProjectionMatrix[3][3] == 0.0) ? (10.0 / (light_loc.z * defaultpixsize)) : (10.0 / defaultpixsize); + pxscale = max(pxscale, 0.000001); + + /* the height over plane is received in the w component of the loc + * and needs a factor to adapt to pixels + */ + float peak = height * 10.0 * pxscale; + vec3 light3d = vec3(light2d.x, light2d.y, peak); + + vec2 uv = vec2(gl_FragCoord.xy); + vec3 frag_loc = vec3(uv.x, uv.y, 0); + vec3 norm = vec3(0, 0, 1.0); /* always z-up */ + + ivec2 iuv = ivec2(uv.x, uv.y); + stroke_depth = texelFetch(strokeDepth, iuv, 0).r; + objcolor = texelFetch(strokeColor, iuv, 0); + + /* diffuse light */ + vec3 lightdir = normalize(light3d - frag_loc); + float diff = max(dot(norm, lightdir), 0.0); + float dist = length(light3d - frag_loc) / pxscale; + float factor = diff * ((energy * 100.0) / (dist * dist)); + + vec3 result = factor * max(ambient, 0.1) * vec3(objcolor); + + gl_FragDepth = stroke_depth; + FragColor = vec4(result.r, result.g, result.b, objcolor.a); +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl new file mode 100644 index 00000000000..d1a57a9a1b6 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl @@ -0,0 +1,50 @@ +uniform mat4 ProjectionMatrix; +uniform mat4 ViewMatrix; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; + +uniform int size[3]; +uniform vec4 color; + +uniform vec3 loc; +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform float pixfactor; + +out vec4 FragColor; + +int uselines = size[2]; +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); +vec2 nsize = max(vec2(size[0], size[1]), 3.0); + +/* This pixelation shader is a modified version of original Geeks3d.com code */ +void main() +{ + vec2 uv = vec2(gl_FragCoord.xy); + vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); + + float dx = (ProjectionMatrix[3][3] == 0.0) ? (nsize[0] / (nloc.z * defaultpixsize)) : (nsize[0] / defaultpixsize); + float dy = (ProjectionMatrix[3][3] == 0.0) ? (nsize[1] / (nloc.z * defaultpixsize)) : (nsize[1] / defaultpixsize); + + dx = max(abs(dx), 3.0); + dy = max(abs(dy), 3.0); + + vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy)); + + float stroke_depth = texelFetch(strokeDepth, ivec2(coord), 0).r; + vec4 outcolor = texelFetch(strokeColor, ivec2(coord), 0); + + if (uselines == 1) { + float difx = uv.x - (floor(uv.x / nsize[0]) * nsize[0]); + if ((difx == 0.5) && (outcolor.a > 0)) { + outcolor = color; + } + float dify = uv.y - (floor(uv.y / nsize[1]) * nsize[1]); + if ((dify == 0.5) && (outcolor.a > 0)) { + outcolor = color; + } + } + gl_FragDepth = stroke_depth; + FragColor = outcolor; +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl new file mode 100644 index 00000000000..fe35d3832e1 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl @@ -0,0 +1,64 @@ +uniform mat4 ProjectionMatrix; +uniform mat4 ViewMatrix; + +/* ******************************************************************* */ +/* create rim and mask */ +/* ******************************************************************* */ +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; +uniform vec2 Viewport; + +uniform int offset[2]; +uniform vec3 rim_color; +uniform vec3 mask_color; + +uniform vec3 loc; +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform float pixfactor; + +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); +vec2 noffset = vec2(offset[0], offset[1]); + +out vec4 FragColor; + +void main() +{ + vec2 uv = vec2(gl_FragCoord.xy); + vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); + + float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) : (noffset[0] / defaultpixsize); + float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) : (noffset[1] / defaultpixsize); + + float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r; + vec4 src_pixel= texelFetch(strokeColor, ivec2(uv.xy), 0); + vec4 offset_pixel= texelFetch(strokeColor, ivec2(uv.x - dx, uv.y - dy), 0); + vec4 outcolor; + + /* is transparent */ + if (src_pixel.a == 0.0f) { + discard; + } + /* check inside viewport */ + else if ((uv.x - dx < 0) || (uv.x - dx > Viewport[0])) { + discard; + } + else if ((uv.y - dy < 0) || (uv.y - dy > Viewport[1])) { + discard; + } + /* pixel is equal to mask color, keep */ + else if (src_pixel.rgb == mask_color.rgb) { + discard; + } + else { + if ((src_pixel.a > 0) && (offset_pixel.a > 0)) { + discard; + } + else { + outcolor = vec4(rim_color, 1.0); + } + } + + gl_FragDepth = stroke_depth; + FragColor = outcolor; +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl new file mode 100644 index 00000000000..5e5edbd8325 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl @@ -0,0 +1,101 @@ +/* ******************************************************************* */ +/* Resolve RIM pass and add blur if needed */ +/* ******************************************************************* */ +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; +uniform sampler2D strokeRim; + +uniform vec3 mask_color; +uniform int mode; + +out vec4 FragColor; + +#define MODE_NORMAL 0 +#define MODE_OVERLAY 1 +#define MODE_ADD 2 +#define MODE_SUB 3 +#define MODE_MULTIPLY 4 +#define MODE_DIVIDE 5 + +float overlay_color(float a, float b) +{ + float rtn; + if (a < 0.5) { + rtn = 2.0 * a * b; + } + else { + rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b); + } + + return rtn; +} + +vec4 get_blend_color(int mode, vec4 src_color, vec4 mix_color) +{ + vec4 outcolor; + if (mode == MODE_NORMAL) { + outcolor = mix_color; + } + else if (mode == MODE_OVERLAY) { + outcolor.r = overlay_color(src_color.r, mix_color.r); + outcolor.g = overlay_color(src_color.g, mix_color.g); + outcolor.b = overlay_color(src_color.b, mix_color.b); + } + else if (mode == MODE_ADD){ + outcolor = src_color + mix_color; + } + else if (mode == MODE_SUB){ + outcolor = src_color - mix_color; + } + else if (mode == MODE_MULTIPLY) { + outcolor = src_color * mix_color; + } + else if (mode == MODE_DIVIDE) { + outcolor = src_color / mix_color; + } + else { + outcolor = mix_color; + } + + /* use always the alpha of source color */ + + outcolor.a = src_color.a; + /* use alpha to calculate the weight of the mixed color */ + outcolor = mix(src_color, outcolor, mix_color.a); + + return outcolor; +} + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + + float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r; + vec4 src_pixel= texelFetch(strokeColor, uv.xy, 0); + vec4 rim_pixel= texelFetch(strokeRim, uv.xy, 0); + + vec4 outcolor = src_pixel; + + /* is transparent */ + if (src_pixel.a == 0.0f) { + discard; + } + /* pixel is equal to mask color, keep */ + else if (src_pixel.rgb == mask_color.rgb) { + outcolor = src_pixel; + } + else { + if (rim_pixel.a == 0.0f) { + outcolor = src_pixel; + } + else { + outcolor = get_blend_color(mode, src_pixel, rim_pixel); + } + } + + gl_FragDepth = stroke_depth; + FragColor = outcolor; +} + + + diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl new file mode 100644 index 00000000000..6ce64350b3d --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl @@ -0,0 +1,70 @@ +uniform mat4 ProjectionMatrix; +uniform mat4 ViewMatrix; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; + +uniform vec2 Viewport; +uniform vec3 loc; +uniform int radius; +uniform float angle; +uniform int transparent; + +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform float pixfactor; + +out vec4 FragColor; + +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); + +/* project 3d point to 2d on screen space */ +vec2 toScreenSpace(vec4 vertex) +{ + /* need to calculate ndc because this is not done by vertex shader */ + vec3 ndc = vec3(vertex).xyz / vertex.w; + + vec2 sc; + sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x; + sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y; + + return sc; +} + +/* This swirl shader is a modified version of original Geeks3d.com code */ +void main() +{ + vec2 uv = vec2(gl_FragCoord.xy); + float stroke_depth; + vec4 outcolor; + + vec4 center3d = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); + vec2 center = toScreenSpace(center3d); + vec2 tc = uv - center; + + float dist = length(tc); + float pxradius = (ProjectionMatrix[3][3] == 0.0) ? (radius / (loc.z * defaultpixsize)) : (radius / defaultpixsize); + pxradius = max(pxradius, 1); + + if (dist <= pxradius) { + float percent = (pxradius - dist) / pxradius; + float theta = percent * percent * angle * 8.0; + float s = sin(theta); + float c = cos(theta); + tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c))); + tc += center; + + stroke_depth = texelFetch(strokeDepth, ivec2(tc), 0).r; + outcolor = texelFetch(strokeColor, ivec2(tc), 0); + } + else { + if (transparent == 1) { + discard; + } + stroke_depth = texelFetch(strokeDepth, ivec2(uv), 0).r; + outcolor = texelFetch(strokeColor, ivec2(uv), 0); + } + + gl_FragDepth = stroke_depth; + FragColor = outcolor; +} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl new file mode 100644 index 00000000000..882b2cf59f1 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl @@ -0,0 +1,40 @@ + +out vec4 FragColor; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; + +uniform float amplitude; +uniform float period; +uniform float phase; +uniform int orientation; +uniform vec2 wsize; + +#define M_PI 3.1415926535897932384626433832795 + +#define HORIZONTAL 0 +#define VERTICAL 1 + +void main() +{ + vec4 outcolor; + ivec2 uv = ivec2(gl_FragCoord.xy); + float stroke_depth; + + float value; + if (orientation == HORIZONTAL) { + float pval = (uv.x * M_PI) / wsize[0]; + value = amplitude * sin((period * pval) + phase); + outcolor = texelFetch(strokeColor, ivec2(uv.x, uv.y + value), 0); + stroke_depth = texelFetch(strokeDepth, ivec2(uv.x, uv.y + value), 0).r; + } + else { + float pval = (uv.y * M_PI) / wsize[1]; + value = amplitude * sin((period * pval) + phase); + outcolor = texelFetch(strokeColor, ivec2(uv.x + value, uv.y), 0); + stroke_depth = texelFetch(strokeDepth, ivec2(uv.x + value, uv.y), 0).r; + } + + FragColor = outcolor; + gl_FragDepth = stroke_depth; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl new file mode 100644 index 00000000000..cbd7a461dd3 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl @@ -0,0 +1,12 @@ +out vec4 FragColor; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + + gl_FragDepth = texelFetch(strokeDepth, uv, 0).r; + FragColor = texelFetch(strokeColor, uv, 0); +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl new file mode 100644 index 00000000000..b3bd8e488f2 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl @@ -0,0 +1,17 @@ +in vec4 mColor; +in vec2 mTexCoord; +out vec4 fragColor; + +void main() +{ + vec2 centered = mTexCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if (dist_squared > rad_squared) { + discard; + } + + fragColor = mColor; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl new file mode 100644 index 00000000000..0d2da00db66 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl @@ -0,0 +1,48 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 Viewport; + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +in vec4 finalColor[1]; +in float finalThickness[1]; + +out vec4 mColor; +out vec2 mTexCoord; + +/* project 3d point to 2d on screen space */ +vec2 toScreenSpace(vec4 vertex) +{ + return vec2(vertex.xy / vertex.w) * Viewport; +} + +void main(void) +{ + vec4 P0 = gl_in[0].gl_Position; + vec2 sp0 = toScreenSpace(P0); + + float size = finalThickness[0]; + + /* generate the triangle strip */ + mTexCoord = vec2(0, 1); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x - size, sp0.y + size) / Viewport, 0, 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x - size, sp0.y - size) / Viewport, 0, 1.0); + EmitVertex(); + + mTexCoord = vec2(1, 1); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x + size, sp0.y + size) / Viewport, 0, 1.0); + EmitVertex(); + + mTexCoord = vec2(1, 0); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x + size, sp0.y - size) / Viewport, 0, 1.0); + EmitVertex(); + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl new file mode 100644 index 00000000000..77fdf58bea0 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl @@ -0,0 +1,15 @@ +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec4 color; +in float size; + +out vec4 finalColor; +out float finalThickness; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 ); + finalColor = color; + finalThickness = size; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl new file mode 100644 index 00000000000..35f47d6c418 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl @@ -0,0 +1,140 @@ +uniform vec4 color2; +uniform int fill_type; +uniform float mix_factor; + +uniform float gradient_angle; +uniform float gradient_radius; +uniform float pattern_gridsize; +uniform vec2 gradient_scale; +uniform vec2 gradient_shift; + +uniform float texture_angle; +uniform vec2 texture_scale; +uniform vec2 texture_offset; +uniform int texture_mix; +uniform int texture_flip; +uniform float texture_opacity; +uniform int xraymode; + +uniform sampler2D myTexture; +uniform int texture_clamp; + +/* keep this list synchronized with list in gpencil_draw_utils.c */ +#define SOLID 0 +#define GRADIENT 1 +#define RADIAL 2 +#define CHESS 3 +#define TEXTURE 4 +#define PATTERN 5 + +#define GP_XRAY_FRONT 0 +#define GP_XRAY_3DSPACE 1 +#define GP_XRAY_BACK 2 + +in vec4 finalColor; +in vec2 texCoord_interp; +out vec4 fragColor; +#define texture2D texture + +void set_color(in vec4 color, in vec4 color2, in vec4 tcolor, in float mixv, in float factor, + in int tmix, in int flip, out vec4 ocolor) +{ + /* full color A */ + if (mixv == 1.0) { + if (tmix == 1) { + ocolor = (flip == 0) ? color : tcolor; + } + else { + ocolor = (flip == 0) ? color : color2; + } + } + /* full color B */ + else if (mixv == 0.0) { + if (tmix == 1) { + ocolor = (flip == 0) ? tcolor : color; + } + else { + ocolor = (flip == 0) ? color2 : color; + } + } + /* mix of colors */ + else { + if (tmix == 1) { + ocolor = (flip == 0) ? mix(color, tcolor, factor) : mix(tcolor, color, factor); + } + else { + ocolor = (flip == 0) ? mix(color, color2, factor) : mix(color2, color, factor); + } + } +} + +void main() +{ + vec2 t_center = vec2(0.5, 0.5); + mat2 matrot_tex = mat2(cos(texture_angle), -sin(texture_angle), sin(texture_angle), cos(texture_angle)); + vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + texture_offset; + vec4 tmp_color; + tmp_color = (texture_clamp == 0) ? texture2D(myTexture, rot_tex * texture_scale) : texture2D(myTexture, clamp(rot_tex * texture_scale, 0.0, 1.0)); + vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * texture_opacity); + vec4 chesscolor; + + /* solid fill */ + if (fill_type == SOLID) { + fragColor = finalColor; + } + else { + vec2 center = vec2(0.5, 0.5) + gradient_shift; + mat2 matrot = mat2(cos(gradient_angle), -sin(gradient_angle), sin(gradient_angle), cos(gradient_angle)); + vec2 rot = (((matrot * (texCoord_interp - center)) + center) * gradient_scale) + gradient_shift; + /* gradient */ + if (fill_type == GRADIENT) { + set_color(finalColor, color2, text_color, mix_factor, rot.x - mix_factor + 0.5, texture_mix, texture_flip, fragColor); + } + /* radial gradient */ + if (fill_type == RADIAL) { + float in_rad = gradient_radius * mix_factor; + float ex_rad = gradient_radius - in_rad; + float intensity = 0; + float distance = length((center - texCoord_interp) * gradient_scale); + if (distance > gradient_radius) { + discard; + } + if (distance > in_rad) { + intensity = clamp(((distance - in_rad) / ex_rad), 0.0, 1.0); + } + set_color(finalColor, color2, text_color, mix_factor, intensity, texture_mix, texture_flip, fragColor); + } + /* chessboard */ + if (fill_type == CHESS) { + vec2 pos = rot / pattern_gridsize; + if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) || (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) { + chesscolor = (texture_flip == 0) ? finalColor : color2; + } + else { + chesscolor = (texture_flip == 0) ? color2 : finalColor; + } + /* mix with texture */ + fragColor = (texture_mix == 1) ? mix(chesscolor, text_color, mix_factor) : chesscolor; + } + /* texture */ + if (fill_type == TEXTURE) { + fragColor = (texture_mix == 1) ? mix(text_color, finalColor, mix_factor) : text_color; + } + /* pattern */ + if (fill_type == PATTERN) { + fragColor = finalColor; + fragColor.a = min(text_color.a, finalColor.a); + } + } + + /* set zdepth */ + if (xraymode == GP_XRAY_FRONT) { + gl_FragDepth = 0.0; + } + if (xraymode == GP_XRAY_3DSPACE) { + gl_FragDepth = gl_FragCoord.z; + } + if (xraymode == GP_XRAY_BACK) { + gl_FragDepth = 0.999999; + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl new file mode 100644 index 00000000000..52da354a562 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl @@ -0,0 +1,14 @@ +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec4 color; +in vec2 texCoord; +out vec4 finalColor; +out vec2 texCoord_interp; + +void main(void) +{ + gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 ); + finalColor = color; + texCoord_interp = texCoord; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl new file mode 100644 index 00000000000..c2e3f787bec --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl @@ -0,0 +1,9 @@ +uniform vec3 color; +uniform float opacity; + +out vec4 FragColor; + +void main() +{ + FragColor = vec4(color, opacity); +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl new file mode 100644 index 00000000000..0d6d2b22a55 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl @@ -0,0 +1,49 @@ +uniform int color_type; +uniform int mode; +uniform sampler2D myTexture; + +in vec4 mColor; +in vec2 mTexCoord; +out vec4 fragColor; + +#define texture2D texture + +#define GPENCIL_MODE_LINE 0 +#define GPENCIL_MODE_DOTS 1 +#define GPENCIL_MODE_BOX 2 + +/* keep this list synchronized with list in gpencil_engine.h */ +#define GPENCIL_COLOR_SOLID 0 +#define GPENCIL_COLOR_TEXTURE 1 +#define GPENCIL_COLOR_PATTERN 2 + +void main() +{ + vec2 centered = mTexCoord - vec2(0.5); + float dist_squared = dot(centered, centered); + const float rad_squared = 0.25; + + // round point with jaggy edges + if ((mode != GPENCIL_MODE_BOX) && (dist_squared > rad_squared)) + discard; + + vec4 tmp_color = texture2D(myTexture, mTexCoord); + + /* Solid */ + if (color_type == GPENCIL_COLOR_SOLID) { + fragColor = mColor; + } + /* texture */ + if (color_type == GPENCIL_COLOR_TEXTURE) { + fragColor = texture2D(myTexture, mTexCoord); + /* mult both alpha factor to use strength factor with texture */ + fragColor.a = min(fragColor.a * mColor.a, fragColor.a); + } + /* pattern */ + if (color_type == GPENCIL_COLOR_PATTERN) { + vec4 text_color = texture2D(myTexture, mTexCoord); + fragColor = mColor; + /* mult both alpha factor to use strength factor with color alpha limit */ + fragColor.a = min(text_color.a * mColor.a, mColor.a); + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl new file mode 100644 index 00000000000..f092149430c --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl @@ -0,0 +1,82 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 Viewport; +uniform int xraymode; + +layout(points) in; +layout(triangle_strip, max_vertices = 4) out; + +in vec4 finalColor[1]; +in float finalThickness[1]; +in vec2 finaluvdata[1]; + +out vec4 mColor; +out vec2 mTexCoord; + +#define GP_XRAY_FRONT 0 +#define GP_XRAY_3DSPACE 1 +#define GP_XRAY_BACK 2 + +/* project 3d point to 2d on screen space */ +vec2 toScreenSpace(vec4 vertex) +{ + return vec2(vertex.xy / vertex.w) * Viewport; +} + +/* get zdepth value */ +float getZdepth(vec4 point) +{ + if (xraymode == GP_XRAY_FRONT) { + return 0.0; + } + if (xraymode == GP_XRAY_3DSPACE) { + return (point.z / point.w); + } + if (xraymode == GP_XRAY_BACK) { + return 0.999999; + } + + /* in front by default */ + return 0.0; +} + +vec2 rotateUV(vec2 uv, float angle) +{ + /* translate center of rotation to the center of texture */ + vec2 new_uv = uv - vec2(0.5f, 0.5f); + vec2 rot_uv; + rot_uv.x = new_uv.x * cos(angle) - new_uv.y * sin(angle); + rot_uv.y = new_uv.y * cos(angle) + new_uv.x * sin(angle); + return rot_uv + vec2(0.5f, 0.5f); +} + +void main(void) +{ + /* receive 4 points */ + vec4 P0 = gl_in[0].gl_Position; + vec2 sp0 = toScreenSpace(P0); + + float size = finalThickness[0]; + float aspect = 1.0; + /* generate the triangle strip */ + mTexCoord = rotateUV(vec2(0, 1), finaluvdata[0].y); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x - size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0); + EmitVertex(); + + mTexCoord = rotateUV(vec2(0, 0), finaluvdata[0].y); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x - size, sp0.y - size * aspect) / Viewport, getZdepth(P0), 1.0); + EmitVertex(); + + mTexCoord = rotateUV(vec2(1, 1), finaluvdata[0].y); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x + size, sp0.y + size * aspect) / Viewport, getZdepth(P0), 1.0); + EmitVertex(); + + mTexCoord = rotateUV(vec2(1, 0), finaluvdata[0].y); + mColor = finalColor[0]; + gl_Position = vec4(vec2(sp0.x + size, sp0.y - size * aspect) / Viewport, getZdepth(P0), 1.0); + EmitVertex(); + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl new file mode 100644 index 00000000000..5e89bf8e5ce --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl @@ -0,0 +1,37 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ProjectionMatrix; + +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform int keep_size; +uniform float objscale; +uniform float pixfactor; + +in vec3 pos; +in vec4 color; +in float thickness; +in vec2 uvdata; + +out vec4 finalColor; +out float finalThickness; +out vec2 finaluvdata; + +#define TRUE 1 + +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 ); + finalColor = color; + + if (keep_size == TRUE) { + finalThickness = thickness; + } + else { + float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : (thickness / defaultpixsize); + finalThickness = max(size * objscale, 4.0); /* minimum 4 pixels */ + } + + finaluvdata = uvdata; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl new file mode 100644 index 00000000000..dd54e38c3d0 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl @@ -0,0 +1,15 @@ +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + float stroke_depth = texelFetch(strokeDepth, uv, 0).r; + vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba; + + FragColor = stroke_color; + gl_FragDepth = stroke_depth; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl new file mode 100644 index 00000000000..d57921c1629 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl @@ -0,0 +1,46 @@ +uniform int color_type; +uniform sampler2D myTexture; + +in vec4 mColor; +in vec2 mTexCoord; +in float uvfac; + +out vec4 fragColor; + +#define texture2D texture + +/* keep this list synchronized with list in gpencil_engine.h */ +#define GPENCIL_COLOR_SOLID 0 +#define GPENCIL_COLOR_TEXTURE 1 +#define GPENCIL_COLOR_PATTERN 2 + +void main() +{ + vec4 tColor = vec4(mColor); + /* if alpha < 0, then encap (only solid mode ) */ + if ((mColor.a < 0) && (color_type == GPENCIL_COLOR_SOLID)) { + vec2 center = vec2(uvfac, 1.0); + tColor.a = tColor.a * -1.0; + float dist = length(mTexCoord - center); + if (dist > 0.50) { + discard; + } + } + /* Solid */ + if (color_type == GPENCIL_COLOR_SOLID) { + fragColor = tColor; + } + /* texture */ + if (color_type == GPENCIL_COLOR_TEXTURE) { + fragColor = texture2D(myTexture, mTexCoord); + /* mult both alpha factor to use strength factor */ + fragColor.a = min(fragColor.a * tColor.a, fragColor.a); + } + /* pattern */ + if (color_type == GPENCIL_COLOR_PATTERN) { + vec4 text_color = texture2D(myTexture, mTexCoord); + fragColor = tColor; + /* mult both alpha factor to use strength factor with color alpha limit */ + fragColor.a = min(text_color.a * tColor.a, tColor.a); + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl new file mode 100644 index 00000000000..0bcfe8cddb7 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl @@ -0,0 +1,208 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 Viewport; +uniform int xraymode; +uniform int color_type; + +layout(lines_adjacency) in; +layout(triangle_strip, max_vertices = 13) out; + +in vec4 finalColor[4]; +in float finalThickness[4]; +in vec2 finaluvdata[4]; + +out vec4 mColor; +out vec2 mTexCoord; +out float uvfac; + +#define GP_XRAY_FRONT 0 +#define GP_XRAY_3DSPACE 1 +#define GP_XRAY_BACK 2 + +/* keep this list synchronized with list in gpencil_engine.h */ +#define GPENCIL_COLOR_SOLID 0 +#define GPENCIL_COLOR_TEXTURE 1 +#define GPENCIL_COLOR_PATTERN 2 + +/* project 3d point to 2d on screen space */ +vec2 toScreenSpace(vec4 vertex) +{ + return vec2(vertex.xy / vertex.w) * Viewport; +} + +/* get zdepth value */ +float getZdepth(vec4 point) +{ + if (xraymode == GP_XRAY_FRONT) { + return 0.0; + } + if (xraymode == GP_XRAY_3DSPACE) { + return (point.z / point.w); + } + if (xraymode == GP_XRAY_BACK) { + return 0.999999; + } + + /* in front by default */ + return 0.0; +} +void main(void) +{ + float MiterLimit = 0.75; + uvfac = 0; + + /* receive 4 points */ + vec4 P0 = gl_in[0].gl_Position; + vec4 P1 = gl_in[1].gl_Position; + vec4 P2 = gl_in[2].gl_Position; + vec4 P3 = gl_in[3].gl_Position; + + /* get the four vertices passed to the shader */ + vec2 sp0 = toScreenSpace(P0); // start of previous segment + vec2 sp1 = toScreenSpace(P1); // end of previous segment, start of current segment + vec2 sp2 = toScreenSpace(P2); // end of current segment, start of next segment + vec2 sp3 = toScreenSpace(P3); // end of next segment + + /* culling outside viewport */ + vec2 area = Viewport * 4.0; + if (sp1.x < -area.x || sp1.x > area.x) return; + if (sp1.y < -area.y || sp1.y > area.y) return; + if (sp2.x < -area.x || sp2.x > area.x) return; + if (sp2.y < -area.y || sp2.y > area.y) return; + + /* determine the direction of each of the 3 segments (previous, current, next) */ + vec2 v0 = normalize(sp1 - sp0); + vec2 v1 = normalize(sp2 - sp1); + vec2 v2 = normalize(sp3 - sp2); + + /* determine the normal of each of the 3 segments (previous, current, next) */ + vec2 n0 = vec2(-v0.y, v0.x); + vec2 n1 = vec2(-v1.y, v1.x); + vec2 n2 = vec2(-v2.y, v2.x); + + /* determine miter lines by averaging the normals of the 2 segments */ + vec2 miter_a = normalize(n0 + n1); // miter at start of current segment + vec2 miter_b = normalize(n1 + n2); // miter at end of current segment + + /* determine the length of the miter by projecting it onto normal and then inverse it */ + float an1 = dot(miter_a, n1); + float bn1 = dot(miter_b, n2); + if (an1 == 0) an1 = 1; + if (bn1 == 0) bn1 = 1; + float length_a = finalThickness[1] / an1; + float length_b = finalThickness[2] / bn1; + if (length_a <= 0.0) length_a = 0.01; + if (length_b <= 0.0) length_b = 0.01; + + /* prevent excessively long miters at sharp corners */ + if (dot(v0, v1) < -MiterLimit) { + miter_a = n1; + length_a = finalThickness[1]; + + /* close the gap */ + if (dot(v0, n1) > 0) { + mTexCoord = vec2(0, 0); + mColor = finalColor[1]; + gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0); + mColor = finalColor[1]; + gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0.5); + mColor = finalColor[1]; + gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + EndPrimitive(); + } + else { + mTexCoord = vec2(0, 1); + mColor = finalColor[1]; + gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 1); + mColor = finalColor[1]; + gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0.5); + mColor = finalColor[1]; + gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + EndPrimitive(); + } + } + + if (dot(v1, v2) < -MiterLimit) { + miter_b = n1; + length_b = finalThickness[2]; + } + + /* generate the start endcap (alpha < 0 used as endcap flag)*/ + if ((P0 == P2) && (color_type == GPENCIL_COLOR_SOLID)){ + mTexCoord = vec2(2, 1); + mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; + vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0; + gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0); + mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; + gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 2); + mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; + gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + } + + /* generate the triangle strip */ + mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 0) : vec2(finaluvdata[1].x, 0); + mColor = finalColor[1]; + gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 1) : vec2(finaluvdata[1].x, 1); + mColor = finalColor[1]; + gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 0) : vec2(finaluvdata[2].x, 0); + mColor = finalColor[2]; + gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 1) : vec2(finaluvdata[2].x, 1); + mColor = finalColor[2]; + gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + /* generate the end endcap (alpha < 0 used as endcap flag)*/ + if ((P1 == P3) && (color_type == GPENCIL_COLOR_SOLID)){ + mTexCoord = vec2(finaluvdata[2].x, 2); + mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; + uvfac = finaluvdata[2].x; + gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + mTexCoord = vec2(finaluvdata[2].x, 0); + mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; + uvfac = finaluvdata[2].x; + gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + mTexCoord = vec2(finaluvdata[2].x + 2, 1); + mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; + uvfac = finaluvdata[2].x; + vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0; + gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl new file mode 100644 index 00000000000..2f9a105e911 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl @@ -0,0 +1,37 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ProjectionMatrix; + +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform int keep_size; +uniform float objscale; +uniform float pixfactor; + +in vec3 pos; +in vec4 color; +in float thickness; +in vec2 uvdata; + +out vec4 finalColor; +out float finalThickness; +out vec2 finaluvdata; + +#define TRUE 1 + +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); + +void main(void) +{ + gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 ); + finalColor = color; + + if (keep_size == TRUE) { + finalThickness = thickness; + } + else { + float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : (thickness / defaultpixsize); + finalThickness = max(size * objscale, 1.0); + } + + finaluvdata = uvdata; +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl new file mode 100644 index 00000000000..0983e6c4d87 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl @@ -0,0 +1,45 @@ +in vec4 uvcoordsvar; + +out vec4 FragColor; + +uniform sampler2D strokeColor; +uniform sampler2D strokeDepth; +uniform int tonemapping; + +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045) + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); + else + return pow((c + 0.055) * (1.0 / 1.055), 2.4); +} + +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) + return (c < 0.0) ? 0.0 : c * 12.92; + else + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; +} + +void main() +{ + ivec2 uv = ivec2(gl_FragCoord.xy); + float stroke_depth = texelFetch(strokeDepth, uv, 0).r; + vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba; + + /* premult alpha factor to remove double blend effects */ + if (stroke_color.a > 0) { + stroke_color = vec4(vec3(stroke_color.rgb / stroke_color.a), stroke_color.a); + } + + /* apply color correction for render only */ + if (tonemapping == 1) { + stroke_color.r = srgb_to_linearrgb(stroke_color.r); + stroke_color.g = srgb_to_linearrgb(stroke_color.g); + stroke_color.b = srgb_to_linearrgb(stroke_color.b); + } + + FragColor = stroke_color; + gl_FragDepth = stroke_depth; +} diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 0db16ab5472..abba8d3ce91 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -136,6 +136,7 @@ typedef char DRWViewportEmptyList; + typedef struct DrawEngineDataSize { int fbl_len; int txl_len; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index bdfa3211f7c..ac84a847a1b 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -107,6 +107,7 @@ static struct DRWShapeCache { GPUBatch *drw_particle_cross; GPUBatch *drw_particle_circle; GPUBatch *drw_particle_axis; + GPUBatch *drw_gpencil_axes; } SHC = {NULL}; void DRW_shape_cache_free(void) @@ -551,12 +552,67 @@ GPUBatch *DRW_cache_screenspace_circle_get(void) #undef CIRCLE_RESOL } -/** \} */ +/* Grease Pencil object */ +GPUBatch *DRW_cache_gpencil_axes_get(void) +{ + if (!SHC.drw_gpencil_axes) { + int axis; + float v1[3] = { 0.0f, 0.0f, 0.0f }; + float v2[3] = { 0.0f, 0.0f, 0.0f }; + + /* cube data */ + const GLfloat verts[8][3] = { + { -0.25f, -0.25f, -0.25f }, + { -0.25f, -0.25f, 0.25f }, + { -0.25f, 0.25f, -0.25f }, + { -0.25f, 0.25f, 0.25f }, + { 0.25f, -0.25f, -0.25f }, + { 0.25f, -0.25f, 0.25f }, + { 0.25f, 0.25f, -0.25f }, + { 0.25f, 0.25f, 0.25f } + }; + + const GLubyte indices[24] = { 0, 1, 1, 3, 3, 2, 2, 0, 0, 4, 4, 5, 5, 7, 7, 6, 6, 4, 1, 5, 3, 7, 2, 6 }; + + /* Position Only 3D format */ + static GPUVertFormat format = { 0 }; + static uint pos_id; + if (format.attr_len == 0) { + pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + } + + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + + /* alloc 30 elements for cube and 3 axis */ + GPU_vertbuf_data_alloc(vbo, ARRAY_SIZE(indices) + 6); + + /* draw axis */ + for (axis = 0; axis < 3; axis++) { + v1[axis] = 1.0f; + v2[axis] = -1.0f; + + GPU_vertbuf_attr_set(vbo, pos_id, axis * 2, v1); + GPU_vertbuf_attr_set(vbo, pos_id, axis * 2 + 1, v2); + + /* reset v1 & v2 to zero for next axis */ + v1[axis] = v2[axis] = 0.0f; + } + + /* draw cube */ + for (int i = 0; i < 24; ++i) { + GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]); + } + + SHC.drw_gpencil_axes = GPU_batch_create(GPU_PRIM_LINES, vbo, NULL); + } + return SHC.drw_gpencil_axes; +} + /* -------------------------------------------------------------------- */ /** \name Common Object API - * \{ */ +* \{ */ GPUBatch *DRW_cache_object_wire_outline_get(Object *ob) { diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 129c0252f30..7d0996b3059 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -82,6 +82,9 @@ struct GPUBatch *DRW_cache_field_vortex_get(void); struct GPUBatch *DRW_cache_field_tube_limit_get(void); struct GPUBatch *DRW_cache_field_cone_limit_get(void); +/* Grease Pencil */ +struct GPUBatch *DRW_cache_gpencil_axes_get(void); + /* Lamps */ struct GPUBatch *DRW_cache_lamp_get(void); struct GPUBatch *DRW_cache_lamp_shadows_get(void); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index eeb7b1c41ee..d4dbe5db80d 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -41,6 +41,7 @@ struct Curve; struct Lattice; struct Mesh; struct MetaBall; +struct bGPdata; /* Expose via BKE callbacks */ void DRW_mball_batch_cache_dirty(struct MetaBall *mb, int mode); @@ -58,6 +59,9 @@ void DRW_lattice_batch_cache_free(struct Lattice *lt); void DRW_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode); void DRW_particle_batch_cache_free(struct ParticleSystem *psys); +void DRW_gpencil_batch_cache_dirty(struct bGPdata *gpd); +void DRW_gpencil_batch_cache_free(struct bGPdata *gpd); + /* Curve */ struct GPUBatch *DRW_curve_batch_cache_get_wire_edge(struct Curve *cu, struct CurveCache *ob_curve_cache); struct GPUBatch *DRW_curve_batch_cache_get_normal_edge( diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 714edc23719..e6e20934283 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -48,6 +48,7 @@ #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_gpencil.h" #include "ED_particle.h" #include "ED_view3d.h" @@ -1222,10 +1223,17 @@ static void drw_engines_enable_from_mode(int mode) break; case CTX_MODE_OBJECT: break; + case CTX_MODE_GPENCIL_PAINT: + case CTX_MODE_GPENCIL_EDIT: + case CTX_MODE_GPENCIL_SCULPT: + case CTX_MODE_GPENCIL_WEIGHT: + break; default: BLI_assert(!"Draw mode invalid"); break; } + /* grease pencil */ + use_drw_engine(&draw_engine_gpencil_type); } static void drw_engines_enable_from_overlays(int overlay_flag) @@ -1258,6 +1266,10 @@ static void drw_engines_enable(ViewLayer *view_layer, RenderEngineType *engine_t drw_engines_enable_from_object_mode(); drw_engines_enable_from_mode(mode); } + else { + /* if gpencil must draw the strokes, but not the object */ + drw_engines_enable_from_mode(mode); + } } static void drw_engines_disable(void) @@ -1377,6 +1389,7 @@ void DRW_draw_render_loop_ex( Scene *scene = DEG_get_evaluated_scene(depsgraph); ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); RegionView3D *rv3d = ar->regiondata; + bool do_annotations = (((v3d->flag2 & V3D_SHOW_ANNOTATION) != 0) && ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0)); DST.draw_ctx.evil_C = evil_C; DST.viewport = viewport; @@ -1471,6 +1484,17 @@ void DRW_draw_render_loop_ex( drw_engines_draw_scene(); + /* annotations - temporary drawing buffer (3d space) */ + /* XXX: Or should we use a proper draw/overlay engine for this case? */ + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (do_annotations)) + { + glDisable(GL_DEPTH_TEST); + /* XXX: as scene->gpd is not copied for COW yet */ + ED_gpencil_draw_view3d_annotations(DEG_get_input_scene(depsgraph), depsgraph, v3d, ar, true); + glEnable(GL_DEPTH_TEST); + } + DRW_draw_callbacks_post_scene(); if (DST.draw_ctx.evil_C) { ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_POST_VIEW); @@ -1495,6 +1519,17 @@ void DRW_draw_render_loop_ex( DRW_draw_region_info(); + /* annotations - temporary drawing buffer (screenspace) */ + /* XXX: Or should we use a proper draw/overlay engine for this case? */ + if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (do_annotations)) + { + glDisable(GL_DEPTH_TEST); + /* XXX: as scene->gpd is not copied for COW yet */ + ED_gpencil_draw_view3d_annotations(DEG_get_input_scene(depsgraph), depsgraph, v3d, ar, false); + glEnable(GL_DEPTH_TEST); + } + if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { /* Draw 2D after region info so we can draw on top of the camera passepartout overlay. * 'DRW_draw_region_info' sets the projection in pixel-space. */ @@ -1583,6 +1618,105 @@ void DRW_draw_render_loop_offscreen( GPU_offscreen_bind(ofs, false); } +/* helper to check if exit object type to render */ +static bool DRW_render_check_object_type(struct Depsgraph *depsgraph, short obtype) +{ + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob) + { + if ((ob->type == obtype) && (DRW_check_object_visible_within_active_context(ob))) { + return true; + } + } + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END + + return false; +} + +static void DRW_render_gpencil_to_image(RenderEngine *engine, struct Depsgraph *depsgraph, struct RenderLayer *render_layer, const rcti *rect) +{ + if (draw_engine_gpencil_type.render_to_image) { + if (DRW_render_check_object_type(depsgraph, OB_GPENCIL)) { + ViewportEngineData *gpdata = drw_viewport_engine_data_ensure(&draw_engine_gpencil_type); + draw_engine_gpencil_type.render_to_image(gpdata, engine, render_layer, rect); + } + } +} + +void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph) +{ + /* This function is only valid for Cycles + * Eevee done all work in the Eevee render directly. + * Maybe it can be done equal for both engines? + */ + if (STREQ(engine->type->name, "Eevee")) { + return; + } + + Scene *scene = DEG_get_evaluated_scene(depsgraph); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + RenderEngineType *engine_type = engine->type; + RenderData *r = &scene->r; + Render *render = engine->re; + /* Changing Context */ + /* GPXX Review this context */ + DRW_opengl_context_enable(); + /* Reset before using it. */ + drw_state_prepare_clean_for_draw(&DST); + DST.options.is_image_render = true; + DST.options.is_scene_render = true; + DST.options.draw_background = scene->r.alphamode == R_ADDSKY; + DST.buffer_finish_called = true; + + DST.draw_ctx = (DRWContextState) { + .scene = scene, .view_layer = view_layer, + .engine_type = engine_type, + .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT, + }; + drw_context_state_init(); + + DST.viewport = GPU_viewport_create(); + const int size[2] = { (r->size * r->xsch) / 100, (r->size * r->ysch) / 100 }; + GPU_viewport_size_set(DST.viewport, size); + + drw_viewport_var_init(); + + /* set default viewport */ + gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); + glDisable(GL_SCISSOR_TEST); + glViewport(0, 0, size[0], size[1]); + + /* Main rendering. */ + rctf view_rect; + rcti render_rect; + RE_GetViewPlane(render, &view_rect, &render_rect); + if (BLI_rcti_is_empty(&render_rect)) { + BLI_rcti_init(&render_rect, 0, size[0], 0, size[1]); + } + + RenderResult *render_result = RE_engine_get_result(engine); + RenderLayer *render_layer = render_result->layers.first; + + DRW_render_gpencil_to_image(engine, depsgraph, render_layer, &render_rect); + + /* Force cache to reset. */ + drw_viewport_cache_resize(); + GPU_viewport_free(DST.viewport); + DRW_state_reset(); + + glDisable(GL_DEPTH_TEST); + + /* Restore Drawing area. */ + gpuPopAttrib(); + glEnable(GL_SCISSOR_TEST); + GPU_framebuffer_restore(); + + /* Changing Context */ + /* GPXX Review this context */ + DRW_opengl_context_disable(); + + DST.buffer_finish_called = false; +} + void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) { Scene *scene = DEG_get_evaluated_scene(depsgraph); @@ -1663,6 +1797,8 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) { RE_SetActiveRenderView(render, render_view->name); engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); + /* grease pencil: render result is merged in the previous render result. */ + DRW_render_gpencil_to_image(engine, depsgraph, render_layer, &render_rect); DST.buffer_finish_called = false; } @@ -1671,8 +1807,6 @@ void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) /* Force cache to reset. */ drw_viewport_cache_resize(); - /* TODO grease pencil */ - GPU_viewport_free(DST.viewport); GPU_framebuffer_restore(); @@ -2286,6 +2420,7 @@ void DRW_engines_register(void) DRW_engine_register(&draw_engine_particle_type); DRW_engine_register(&draw_engine_pose_type); DRW_engine_register(&draw_engine_sculpt_type); + DRW_engine_register(&draw_engine_gpencil_type); /* setup callbacks */ { @@ -2304,6 +2439,9 @@ void DRW_engines_register(void) /* BKE: particle.c */ extern void *BKE_particle_batch_cache_dirty_cb; extern void *BKE_particle_batch_cache_free_cb; + /* BKE: gpencil.c */ + extern void *BKE_gpencil_batch_cache_dirty_cb; + extern void *BKE_gpencil_batch_cache_free_cb; BKE_mball_batch_cache_dirty_cb = DRW_mball_batch_cache_dirty; BKE_mball_batch_cache_free_cb = DRW_mball_batch_cache_free; @@ -2319,6 +2457,9 @@ void DRW_engines_register(void) BKE_particle_batch_cache_dirty_cb = DRW_particle_batch_cache_dirty; BKE_particle_batch_cache_free_cb = DRW_particle_batch_cache_free; + + BKE_gpencil_batch_cache_dirty_cb = DRW_gpencil_batch_cache_dirty; + BKE_gpencil_batch_cache_free_cb = DRW_gpencil_batch_cache_free; } } diff --git a/source/blender/draw/modes/draw_mode_engines.h b/source/blender/draw/modes/draw_mode_engines.h index f88d49dfa96..8e8ddfef5a4 100644 --- a/source/blender/draw/modes/draw_mode_engines.h +++ b/source/blender/draw/modes/draw_mode_engines.h @@ -42,5 +42,6 @@ extern DrawEngineType draw_engine_particle_type; extern DrawEngineType draw_engine_pose_type; extern DrawEngineType draw_engine_sculpt_type; extern DrawEngineType draw_engine_overlay_type; +extern DrawEngineType draw_engine_gpencil_type; #endif /* __DRAW_MODE_ENGINES_H__ */ diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index db906714dd5..675a2a02db8 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -165,6 +165,9 @@ typedef struct OBJECT_PrivateData { DRWShadingGroup *field_tube_limit; DRWShadingGroup *field_cone_limit; + /* Grease Pencil */ + DRWShadingGroup *gpencil_axes; + /* Speaker */ DRWShadingGroup *speaker; @@ -1136,6 +1139,10 @@ static void OBJECT_cache_init(void *vedata) geom = DRW_cache_screenspace_circle_get(); stl->g_data->field_curve_sta = shgroup_instance_screen_aligned(psl->non_meshes, geom); + /* Grease Pencil */ + geom = DRW_cache_gpencil_axes_get(); + stl->g_data->gpencil_axes = shgroup_instance(psl->non_meshes, geom); + /* Speaker */ geom = DRW_cache_speaker_get(); stl->g_data->speaker = shgroup_instance(psl->non_meshes, geom); @@ -1820,6 +1827,14 @@ static void volumes_free_smoke_textures(void) BLI_freelistN(&e_data.smoke_domains); } +static void DRW_shgroup_gpencil(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer) +{ + float *color; + DRW_object_wire_theme_get(ob, view_layer, &color); + + DRW_shgroup_call_dynamic_add(stl->g_data->gpencil_axes, color, &ob->empty_drawsize, ob->obmat); +} + static void DRW_shgroup_speaker(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer) { float *color; @@ -2445,6 +2460,9 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) } DRW_shgroup_empty(stl, psl, ob, view_layer); break; + case OB_GPENCIL: + DRW_shgroup_gpencil(stl, ob, view_layer); + break; case OB_SPEAKER: if (hide_object_extra) { break; diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 3c10cda6456..2431bd50e1b 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -64,6 +64,7 @@ #include "BKE_animsys.h" #include "BKE_curve.h" +#include "BKE_gpencil.h" #include "BKE_key.h" #include "BKE_main.h" #include "BKE_nla.h" @@ -83,6 +84,8 @@ #include "BIF_gl.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "WM_types.h" @@ -661,6 +664,8 @@ static int acf_object_icon(bAnimListElem *ale) return ICON_OUTLINER_OB_SURFACE; case OB_EMPTY: return ICON_OUTLINER_OB_EMPTY; + case OB_GPENCIL: + return ICON_OUTLINER_OB_GREASEPENCIL; default: return ICON_OBJECT_DATA; } @@ -4048,8 +4053,16 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void return; } - if (ale_setting->type == ANIMTYPE_GPLAYER) + if (ale_setting->type == ANIMTYPE_GPLAYER) { + /* draw cache updates for settings that affect the visible strokes */ + if (setting == ACHANNEL_SETTING_VISIBLE) { + bGPdata *gpd = (bGPdata *)ale_setting->id; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + } + + /* UI updates */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + } /* tag copy-on-write flushing (so that the settings will have an effect) */ if (ale_setting->id) { diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index d768be49ad4..3f22ac6fa3a 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1727,8 +1727,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) bGPDlayer *gpl = (bGPDlayer *)ale->data; /* try to delete the layer's data and the layer itself */ - BKE_gpencil_free_frames(gpl); - BLI_freelinkN(&gpd->layers, gpl); + BKE_gpencil_layer_delete(gpd, gpl); break; } case ANIMTYPE_MASKLAYER: diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index adb5a10c19d..898c8b6464a 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -435,6 +435,16 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data) ANIM_list_elem_update(ac->bmain, ac->scene, ale); } } + else if (ale->update) { +#if 0 + if (G.debug & G_DEBUG) { + printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n", + __func__, ale->update, ale->type, ale->data); + } +#endif + /* Prevent crashes in cases where it can't be handled */ + ale->update = 0; + } BLI_assert(ale->update == 0); } diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 780e984f870..05ea3fd6314 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -552,11 +552,11 @@ static bool find_prev_next_keyframes(struct bContext *C, int *nextfra, int *prev /* populate tree with keyframe nodes */ scene_to_keylist(&ads, scene, &keys, NULL); - gpencil_to_keylist(&ads, scene->gpd, &keys); + gpencil_to_keylist(&ads, scene->gpd, &keys, false); if (ob) { ob_to_keylist(&ads, ob, &keys, NULL); - gpencil_to_keylist(&ads, ob->gpd, &keys); + gpencil_to_keylist(&ads, ob->data, &keys, false); } if (mask) { diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index c59d24bbdf8..1981814eb02 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -72,6 +72,7 @@ #include "DNA_speaker_types.h" #include "DNA_world_types.h" #include "DNA_gpencil_types.h" +#include "DNA_brush_types.h" #include "DNA_object_types.h" #include "DNA_userdef_types.h" #include "DNA_layer_types.h" @@ -1660,7 +1661,7 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data, bDopeSheet *ads, */ if (filter_mode & ANIMFILTER_ANIMDATA) { /* just add GPD as a channel - this will add everything needed */ - ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL); + ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd); } else { ListBase tmp_data = {NULL, NULL}; @@ -1711,7 +1712,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi /* Objects in the scene */ for (base = view_layer->object_bases.first; base; base = base->next) { /* Only consider this object if it has got some GP data (saving on all the other tests) */ - if (base->object && base->object->gpd) { + if (base->object && (base->object->type == OB_GPENCIL)) { Object *ob = base->object; /* firstly, check if object can be included, by the following factors: @@ -1748,7 +1749,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, ListBase *anim_data, voi /* finally, include this object's grease pencil datablock */ /* XXX: Should we store these under expanders per item? */ - items += animdata_filter_gpencil_data(anim_data, ads, ob->gpd, filter_mode); + items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode); } } } @@ -2613,8 +2614,10 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data } /* grease pencil */ - if ((ob->gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { - tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->gpd, filter_mode); + if ((ob->type == OB_GPENCIL) && + (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) + { + tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode); } } END_ANIMFILTER_SUBCHANNELS; diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 30130ce4dac..a8b63e01ac1 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -48,6 +48,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_gpencil_types.h" +#include "DNA_brush_types.h" #include "DNA_mask_types.h" #include "BKE_fcurve.h" @@ -783,7 +784,7 @@ void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos BLI_dlrbTree_init(&keys); - gpencil_to_keylist(ads, gpd, &keys); + gpencil_to_keylist(ads, gpd, &keys, false); BLI_dlrbTree_linkedlist_sync(&keys); @@ -1019,7 +1020,7 @@ void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree } -void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys) +void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys, const bool active) { bGPDlayer *gpl; @@ -1027,7 +1028,9 @@ void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys) /* for now, just aggregate out all the frames, but only for visible layers */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { if ((gpl->flag & GP_LAYER_HIDE) == 0) { - gpl_to_keylist(ads, gpl, keys); + if ((!active) || ((active) && (gpl->flag & GP_LAYER_SELECT))) { + gpl_to_keylist(ads, gpl, keys); + } } } } diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 0e09ef6f583..0698282c4e5 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -536,6 +536,16 @@ set(ICON_NAMES # This section is maintained by the updating script, keep BEGIN/END comments. set_property(GLOBAL PROPERTY ICON_GEOM_NAMES # BEGIN ICON_GEOM_NAMES + brush.gpencil.draw.eraser_hard + brush.gpencil.draw.eraser_soft + brush.gpencil.draw.eraser_stroke + brush.gpencil.draw_block + brush.gpencil.draw_fill + brush.gpencil.draw_ink + brush.gpencil.draw_marker + brush.gpencil.draw_noise + brush.gpencil.draw_pen + brush.gpencil.draw_pencil brush.paint_texture.airbrush brush.paint_texture.clone brush.paint_texture.draw @@ -583,6 +593,24 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES ops.generic.select_border ops.generic.select_circle ops.generic.select_lasso + ops.gpencil.draw + ops.gpencil.draw.eraser + ops.gpencil.draw.line + ops.gpencil.draw.poly + ops.gpencil.edit_bend + ops.gpencil.edit_mirror + ops.gpencil.edit_shear + ops.gpencil.edit_to_sphere + ops.gpencil.sculpt_clone + ops.gpencil.sculpt_grab + ops.gpencil.sculpt_pinch + ops.gpencil.sculpt_push + ops.gpencil.sculpt_randomize + ops.gpencil.sculpt_smooth + ops.gpencil.sculpt_strength + ops.gpencil.sculpt_thickness + ops.gpencil.sculpt_twist + ops.gpencil.sculpt_weight ops.mesh.bevel ops.mesh.bisect ops.mesh.dupli_extrude_cursor @@ -634,6 +662,7 @@ if(WITH_BLENDER) # blends data_to_c_simple(../../../../release/datafiles/preview.blend SRC) data_to_c_simple(../../../../release/datafiles/preview_cycles.blend SRC) + data_to_c_simple(../../../../release/datafiles/preview_grease_pencil.blend SRC) # images data_to_c_simple(../../../../release/datafiles/splash.png SRC) @@ -689,6 +718,29 @@ if(WITH_BLENDER) data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC) data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC) + # grease pencil sculpt + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_smooth.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_thickness.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_strength.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_grab.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_push.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_twist.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pinch.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_randomize.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_clone.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_weight.png SRC) + + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pencil.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_pen.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_ink.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_inknoise.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_block.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_marker.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_fill.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_soft.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC) + data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC) + endif() data_to_c_simple(../../../../release/datafiles/startup.blend SRC) diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 587c25031ab..f9f196f6634 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -39,18 +39,24 @@ set(INC_SYS ) set(SRC + annotate_draw.c + annotate_paint.c drawgpencil.c editaction_gpencil.c + gpencil_add_monkey.c gpencil_brush.c gpencil_convert.c gpencil_data.c gpencil_edit.c gpencil_interpolate.c + gpencil_primitive.c gpencil_ops.c gpencil_paint.c + gpencil_fill.c gpencil_select.c gpencil_undo.c gpencil_utils.c + gpencil_old.c gpencil_intern.h ) diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c new file mode 100644 index 00000000000..dad5af7379c --- /dev/null +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -0,0 +1,1065 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Joshua Leung, Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/gpencil/annotate_draw.c + * \ingroup edgpencil + */ + + +#include +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_sys_types.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "BLI_polyfill_2d.h" + +#include "BLF_api.h" +#include "BLT_translation.h" + +#include "DNA_gpencil_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" +#include "DNA_userdef_types.h" +#include "DNA_object_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" + +#include "WM_api.h" + +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_draw.h" +#include "GPU_state.h" + +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_space_api.h" + +#include "UI_interface_icons.h" +#include "UI_resources.h" + +/* ************************************************** */ +/* GREASE PENCIL DRAWING */ + +/* ----- General Defines ------ */ +/* flags for sflag */ +typedef enum eDrawStrokeFlags { + GP_DRAWDATA_NOSTATUS = (1 << 0), /* don't draw status info */ + GP_DRAWDATA_ONLY3D = (1 << 1), /* only draw 3d-strokes */ + GP_DRAWDATA_ONLYV2D = (1 << 2), /* only draw 'canvas' strokes */ + GP_DRAWDATA_ONLYI2D = (1 << 3), /* only draw 'image' strokes */ + GP_DRAWDATA_IEDITHACK = (1 << 4), /* special hack for drawing strokes in Image Editor (weird coordinates) */ + GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */ + GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */ +} eDrawStrokeFlags; + + +/* ----- Tool Buffer Drawing ------ */ + +/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ +static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short thickness, + short dflag, short sflag, float ink[4]) +{ + int draw_points = 0; + + /* error checking */ + if ((points == NULL) || (totpoints <= 0)) + return; + + /* check if buffer can be drawn */ + if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D)) + return; + + if (sflag & GP_STROKE_ERASER) { + /* don't draw stroke at all! */ + return; + } + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + + const tGPspoint *pt = points; + + if (totpoints == 1) { + /* if drawing a single point, draw it larger */ + GPU_point_size((float)(thickness + 2) * points->pressure); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA); + immUniformColor3fvAlpha(ink, ink[3]); + immBegin(GPU_PRIM_POINTS, 1); + immVertex2iv(pos, &pt->x); + } + else { + float oldpressure = points[0].pressure; + + /* draw stroke curve */ + GPU_line_width(max_ff(oldpressure * thickness, 1.0)); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(ink, ink[3]); + + /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */ + immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints); + + for (int i = 0; i < totpoints; i++, pt++) { + /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, + * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) + */ + if (fabsf(pt->pressure - oldpressure) > 0.2f) { + /* need to have 2 points to avoid immEnd assert error */ + if (draw_points < 2) { + immVertex2iv(pos, &(pt - 1)->x); + } + + immEnd(); + draw_points = 0; + + GPU_line_width(max_ff(pt->pressure * thickness, 1.0f)); + immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1); + + /* need to roll-back one point to ensure that there are no gaps in the stroke */ + if (i != 0) { + immVertex2iv(pos, &(pt - 1)->x); + draw_points++; + } + + oldpressure = pt->pressure; /* reset our threshold */ + } + + /* now the point we want */ + immVertex2iv(pos, &pt->x); + draw_points++; + } + /* need to have 2 points to avoid immEnd assert error */ + if (draw_points < 2) { + immVertex2iv(pos, &(pt - 1)->x); + } + } + + immEnd(); + immUnbindProgram(); +} + +/* --------- 2D Stroke Drawing Helpers --------- */ +/* change in parameter list */ +static void gp_calc_2d_stroke_fxy(const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2]) +{ + if (sflag & GP_STROKE_2DSPACE) { + r_co[0] = pt[0]; + r_co[1] = pt[1]; + } + else if (sflag & GP_STROKE_2DIMAGE) { + const float x = (float)((pt[0] * winx) + offsx); + const float y = (float)((pt[1] * winy) + offsy); + + r_co[0] = x; + r_co[1] = y; + } + else { + const float x = (float)(pt[0] / 100 * winx) + offsx; + const float y = (float)(pt[1] / 100 * winy) + offsy; + + r_co[0] = x; + r_co[1] = y; + } +} + +/* ----- Existing Strokes Drawing (3D and Point) ------ */ + +/* draw a given stroke - just a single dot (only one point) */ +static void gp_draw_stroke_point( + const bGPDspoint *points, short thickness, short UNUSED(dflag), short sflag, + int offsx, int offsy, int winx, int winy, const float ink[4]) +{ + const bGPDspoint *pt = points; + + /* get final position using parent matrix */ + float fpt[3]; + copy_v3_v3(fpt, &pt->x); + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + if (sflag & GP_STROKE_3DSPACE) { + immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA); + } + else { + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA); + + /* get 2D coordinates of point */ + float co[3] = { 0.0f }; + gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co); + copy_v3_v3(fpt, co); + } + + /* set color */ + immUniformColor3fvAlpha(ink, ink[3]); + + /* set point thickness (since there's only one of these) */ + immUniform1f("size", (float)(thickness + 2) * pt->pressure); + + immBegin(GPU_PRIM_POINTS, 1); + immVertex3fv(pos, fpt); + immEnd(); + + immUnbindProgram(); +} + +/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ +static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thickness, bool UNUSED(debug), + short UNUSED(sflag), const float ink[4], bool cyclic) +{ + float curpressure = points[0].pressure; + float cyclic_fpt[3]; + int draw_points = 0; + + /* if cyclic needs one vertex more */ + int cyclic_add = 0; + if (cyclic) { + cyclic_add++; + } + + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + immUniformColor3fvAlpha(ink, ink[3]); + + /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */ + + /* draw stroke curve */ + GPU_line_width(max_ff(curpressure * thickness, 1.0f)); + immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add); + const bGPDspoint *pt = points; + for (int i = 0; i < totpoints; i++, pt++) { + /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, + * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) + * Note: we want more visible levels of pressures when thickness is bigger. + */ + if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) { + /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */ + if (draw_points < 2) { + const bGPDspoint *pt2 = pt - 1; + immVertex3fv(pos, &pt2->x); + } + immEnd(); + draw_points = 0; + + curpressure = pt->pressure; + GPU_line_width(max_ff(curpressure * thickness, 1.0f)); + immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add); + + /* need to roll-back one point to ensure that there are no gaps in the stroke */ + if (i != 0) { + const bGPDspoint *pt2 = pt - 1; + immVertex3fv(pos, &pt2->x); + draw_points++; + } + } + + /* now the point we want */ + immVertex3fv(pos, &pt->x); + draw_points++; + + if (cyclic && i == 0) { + /* save first point to use in cyclic */ + copy_v3_v3(cyclic_fpt, &pt->x); + } + } + + if (cyclic) { + /* draw line to first point to complete the cycle */ + immVertex3fv(pos, cyclic_fpt); + draw_points++; + } + + /* if less of two points, need to repeat last point to avoid assert in immEnd() */ + if (draw_points < 2) { + const bGPDspoint *pt2 = pt - 1; + immVertex3fv(pos, &pt2->x); + } + + immEnd(); + immUnbindProgram(); +} + +/* ----- Fancy 2D-Stroke Drawing ------ */ + +/* draw a given stroke in 2d */ +static void gp_draw_stroke_2d(const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, + bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float ink[4]) +{ + /* otherwise thickness is twice that of the 3D view */ + float thickness = (float)thickness_s * 0.5f; + + /* strokes in Image Editor need a scale factor, since units there are not pixels! */ + float scalefac = 1.0f; + if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) { + scalefac = 0.001f; + } + + /* TODO: fancy++ with the magic of shaders */ + + /* tessellation code - draw stroke as series of connected quads (triangle strips in fact) with connection + * edges rotated to minimize shrinking artifacts, and rounded endcaps + */ + { + const bGPDspoint *pt1, *pt2; + float s0[2], s1[2]; /* segment 'center' points */ + float pm[2]; /* normal from previous segment. */ + int i; + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor3fvAlpha(ink, ink[3]); + immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4); + + /* get x and y coordinates from first point */ + gp_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, s0); + + for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) { + float t0[2], t1[2]; /* tessellated coordinates */ + float m1[2], m2[2]; /* gradient and normal */ + float mt[2], sc[2]; /* gradient for thickness, point for end-cap */ + float pthick; /* thickness at segment point */ + + /* get x and y coordinates from point2 (point1 has already been computed in previous iteration). */ + gp_calc_2d_stroke_fxy(&pt2->x, sflag, offsx, offsy, winx, winy, s1); + + /* calculate gradient and normal - 'angle'=(ny/nx) */ + m1[1] = s1[1] - s0[1]; + m1[0] = s1[0] - s0[0]; + normalize_v2(m1); + m2[1] = -m1[0]; + m2[0] = m1[1]; + + /* always use pressure from first point here */ + pthick = (pt1->pressure * thickness * scalefac); + + /* if the first segment, start of segment is segment's normal */ + if (i == 0) { + /* draw start cap first + * - make points slightly closer to center (about halfway across) + */ + mt[0] = m2[0] * pthick * 0.5f; + mt[1] = m2[1] * pthick * 0.5f; + sc[0] = s0[0] - (m1[0] * pthick * 0.75f); + sc[1] = s0[1] - (m1[1] * pthick * 0.75f); + + t0[0] = sc[0] - mt[0]; + t0[1] = sc[1] - mt[1]; + t1[0] = sc[0] + mt[0]; + t1[1] = sc[1] + mt[1]; + + /* First two points of cap. */ + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + + /* calculate points for start of segment */ + mt[0] = m2[0] * pthick; + mt[1] = m2[1] * pthick; + + t0[0] = s0[0] - mt[0]; + t0[1] = s0[1] - mt[1]; + t1[0] = s0[0] + mt[0]; + t1[1] = s0[1] + mt[1]; + + /* Last two points of start cap (and first two points of first segment). */ + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + } + /* if not the first segment, use bisector of angle between segments */ + else { + float mb[2]; /* bisector normal */ + float athick, dfac; /* actual thickness, difference between thicknesses */ + + /* calculate gradient of bisector (as average of normals) */ + mb[0] = (pm[0] + m2[0]) / 2; + mb[1] = (pm[1] + m2[1]) / 2; + normalize_v2(mb); + + /* calculate gradient to apply + * - as basis, use just pthick * bisector gradient + * - if cross-section not as thick as it should be, add extra padding to fix it + */ + mt[0] = mb[0] * pthick; + mt[1] = mb[1] * pthick; + athick = len_v2(mt); + dfac = pthick - (athick * 2); + + if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) { + mt[0] += (mb[0] * dfac); + mt[1] += (mb[1] * dfac); + } + + /* calculate points for start of segment */ + t0[0] = s0[0] - mt[0]; + t0[1] = s0[1] - mt[1]; + t1[0] = s0[0] + mt[0]; + t1[1] = s0[1] + mt[1]; + + /* Last two points of previous segment, and first two points of current segment. */ + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + } + + /* if last segment, also draw end of segment (defined as segment's normal) */ + if (i == totpoints - 2) { + /* for once, we use second point's pressure (otherwise it won't be drawn) */ + pthick = (pt2->pressure * thickness * scalefac); + + /* calculate points for end of segment */ + mt[0] = m2[0] * pthick; + mt[1] = m2[1] * pthick; + + t0[0] = s1[0] - mt[0]; + t0[1] = s1[1] - mt[1]; + t1[0] = s1[0] + mt[0]; + t1[1] = s1[1] + mt[1]; + + /* Last two points of last segment (and first two points of end cap). */ + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + + /* draw end cap as last step + * - make points slightly closer to center (about halfway across) + */ + mt[0] = m2[0] * pthick * 0.5f; + mt[1] = m2[1] * pthick * 0.5f; + sc[0] = s1[0] + (m1[0] * pthick * 0.75f); + sc[1] = s1[1] + (m1[1] * pthick * 0.75f); + + t0[0] = sc[0] - mt[0]; + t0[1] = sc[1] - mt[1]; + t1[0] = sc[0] + mt[0]; + t1[1] = sc[1] + mt[1]; + + /* Last two points of end cap. */ + immVertex2fv(pos, t0); + immVertex2fv(pos, t1); + } + + /* store computed point2 coordinates as point1 ones of next segment. */ + copy_v2_v2(s0, s1); + /* store stroke's 'natural' normal for next stroke to use */ + copy_v2_v2(pm, m2); + } + + immEnd(); + immUnbindProgram(); + } +} + +/* ----- Strokes Drawing ------ */ + +/* Helper for doing all the checks on whether a stroke can be drawn */ +static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) +{ + /* skip stroke if it isn't in the right display space for this drawing context */ + /* 1) 3D Strokes */ + if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE)) + return false; + + /* 2) Screen Space 2D Strokes */ + if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE)) + return false; + + /* 3) Image Space (2D) */ + if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE)) + return false; + if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE)) + return false; + + /* skip stroke if it doesn't have any valid data */ + if ((gps->points == NULL) || (gps->totpoints < 1)) + return false; + + /* stroke can be drawn */ + return true; +} + +/* draw a set of strokes */ +static void gp_draw_strokes( + bGPdata *UNUSED(gpd), bGPDlayer *UNUSED(gpl), const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, + int dflag, bool debug, short lthick, const float color[4]) +{ + GPU_enable_program_point_size(); + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* check if stroke can be drawn */ + if (gp_can_draw_stroke(gps, dflag) == false) { + continue; + } + + /* check which stroke-drawer to use */ + if (dflag & GP_DRAWDATA_ONLY3D) { + const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY); + int mask_orig = 0; + + if (no_xray) { + glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + glDepthMask(0); + GPU_depth_test(true); + + /* first arg is normally rv3d->dist, but this isn't + * available here and seems to work quite well without */ + bglPolygonOffset(1.0f, 1.0f); + } + + /* 3D Lines - OpenGL primitives-based */ + if (gps->totpoints == 1) { + gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color); + } + else { + gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag, + color, gps->flag & GP_STROKE_CYCLIC); + } + + if (no_xray) { + glDepthMask(mask_orig); + GPU_depth_test(false); + + bglPolygonOffset(0.0, 0.0); + } + } + else { + /* 2D Strokes... */ + if (gps->totpoints == 1) { + gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color); + } + else { + gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, + offsx, offsy, winx, winy, color); + } + } + } + + GPU_disable_program_point_size(); +} + +/* Draw selected verts for strokes being edited */ +static void gp_draw_strokes_edit( + bGPdata *gpd, bGPDlayer *gpl, const bGPDframe *gpf, + int offsx, int offsy, int winx, int winy, + short dflag, short UNUSED(lflag), float alpha) +{ + /* if alpha 0 do not draw */ + if (alpha == 0.0f) + return; + + const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0; + int mask_orig = 0; + + /* set up depth masks... */ + if (dflag & GP_DRAWDATA_ONLY3D) { + if (no_xray) { + glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); + glDepthMask(0); + GPU_depth_test(true); + + /* first arg is normally rv3d->dist, but this isn't + * available here and seems to work quite well without */ + bglPolygonOffset(1.0f, 1.0f); + } + } + + GPU_enable_program_point_size(); + + /* draw stroke verts */ + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* check if stroke can be drawn */ + if (gp_can_draw_stroke(gps, dflag) == false) + continue; + + /* Optimisation: only draw points for selected strokes + * We assume that selected points can only occur in + * strokes that are selected too. + */ + if ((gps->flag & GP_STROKE_SELECT) == 0) + continue; + + /* Get size of verts: + * - The selected state needs to be larger than the unselected state so that + * they stand out more. + * - We use the theme setting for size of the unselected verts + */ + float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); + float vsize; + if ((int)bsize > 8) { + vsize = 10.0f; + bsize = 8.0f; + } + else { + vsize = bsize + 2; + } + + float selectColor[4]; + UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); + selectColor[3] = alpha; + + GPUVertFormat *format = immVertexFormat(); + uint pos; /* specified later */ + uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + + if (gps->flag & GP_STROKE_3DSPACE) { + pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); + } + else { + pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR); + } + + immBegin(GPU_PRIM_POINTS, gps->totpoints); + + /* Draw start and end point differently if enabled stroke direction hint */ + bool show_direction_hint = (gpd->flag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1); + + /* Draw all the stroke points (selected or not) */ + bGPDspoint *pt = gps->points; + for (int i = 0; i < gps->totpoints; i++, pt++) { + /* size and color first */ + if (show_direction_hint && i == 0) { + /* start point in green bigger */ + immAttrib3f(color, 0.0f, 1.0f, 0.0f); + immAttrib1f(size, vsize + 4); + } + else if (show_direction_hint && (i == gps->totpoints - 1)) { + /* end point in red smaller */ + immAttrib3f(color, 1.0f, 0.0f, 0.0f); + immAttrib1f(size, vsize + 1); + } + else if (pt->flag & GP_SPOINT_SELECT) { + immAttrib3fv(color, selectColor); + immAttrib1f(size, vsize); + } + else { + immAttrib3fv(color, gpl->color); + immAttrib1f(size, bsize); + } + + /* then position */ + if (gps->flag & GP_STROKE_3DSPACE) { + immVertex3fv(pos, &pt->x); + } + else { + float co[2]; + gp_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co); + immVertex2fv(pos, co); + } + } + + immEnd(); + immUnbindProgram(); + } + + GPU_disable_program_point_size(); + + /* clear depth mask */ + if (dflag & GP_DRAWDATA_ONLY3D) { + if (no_xray) { + glDepthMask(mask_orig); + GPU_depth_test(false); + + bglPolygonOffset(0.0, 0.0); +#if 0 + glDisable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(0, 0); +#endif + } + } +} + +/* ----- General Drawing ------ */ + +/* loop over gpencil data layers, drawing them */ +static void gp_draw_data_layers( + bGPdata *gpd, int offsx, int offsy, int winx, int winy, + int cfra, int dflag, float alpha) +{ + float ink[4]; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG); + short lthick = gpl->thickness; + + /* apply layer opacity */ + copy_v3_v3(ink, gpl->color); + ink[3] = gpl->opacity; + + /* don't draw layer if hidden */ + if (gpl->flag & GP_LAYER_HIDE) + continue; + + /* get frame to draw */ + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, 0); + if (gpf == NULL) + continue; + + /* set basic stroke thickness */ + GPU_line_width(lthick); + + /* Add layer drawing settings to the set of "draw flags" + * NOTE: If the setting doesn't apply, it *must* be cleared, + * as dflag's carry over from the previous layer + */ +#define GP_DRAWFLAG_APPLY(condition, draw_flag_value) { \ + if (condition) dflag |= (draw_flag_value); \ + else dflag &= ~(draw_flag_value); \ + } (void)0 + + /* xray... */ + GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_NO_XRAY), GP_DRAWDATA_NO_XRAY); + +#undef GP_DRAWFLAG_APPLY + + + /* draw the strokes already in active frame */ + gp_draw_strokes(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, debug, lthick, ink); + + /* Draw verts of selected strokes + * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering + * - locked layers can't be edited, so there's no point showing these verts + * as they will have no bearings on what gets edited + * - only show when in editmode, since operators shouldn't work otherwise + * (NOTE: doing it this way means that the toggling editmode shows visible change immediately) + */ + /* XXX: perhaps we don't want to show these when users are drawing... */ + if ((G.f & G_RENDER_OGL) == 0 && + (gpl->flag & GP_LAYER_LOCKED) == 0 && + (gpd->flag & GP_DATA_STROKE_EDITMODE)) + { + gp_draw_strokes_edit(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, alpha); + } + + /* Check if may need to draw the active stroke cache, only if this layer is the active layer + * that is being edited. (Stroke buffer is currently stored in gp-data) + */ + if (ED_gpencil_session_active() && (gpl->flag & GP_LAYER_ACTIVE) && + (gpf->flag & GP_FRAME_PAINT)) + { + /* Buffer stroke needs to be drawn with a different linestyle + * to help differentiate them from normal strokes. + * + * It should also be noted that sbuffer contains temporary point types + * i.e. tGPspoints NOT bGPDspoints + */ + gp_draw_stroke_buffer(gpd->runtime.sbuffer, + gpd->runtime.sbuffer_size, lthick, + dflag, gpd->runtime.sbuffer_sflag, ink); + } + } +} + +/* draw a short status message in the top-right corner */ +static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar) +{ + rcti rect; + + /* Cannot draw any status text when drawing OpenGL Renders */ + if (G.f & G_RENDER_OGL) + return; + + /* Get bounds of region - Necessary to avoid problems with region overlap */ + ED_region_visible_rect(ar, &rect); + + /* for now, this should only be used to indicate when we are in stroke editmode */ + if (gpd->flag & GP_DATA_STROKE_EDITMODE) { + const char *printable = IFACE_("GPencil Stroke Editing"); + float printable_size[2]; + + int font_id = BLF_default(); + + BLF_width_and_height(font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); + + int xco = (rect.xmax - U.widget_unit) - (int)printable_size[0]; + int yco = (rect.ymax - U.widget_unit); + + /* text label */ + UI_FontThemeColor(font_id, TH_TEXT_HI); +#ifdef WITH_INTERNATIONAL + BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); +#else + BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); +#endif + + /* grease pencil icon... */ + // XXX: is this too intrusive? + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + + xco -= U.widget_unit; + yco -= (int)printable_size[1] / 2; + + UI_icon_draw(xco, yco, ICON_GREASEPENCIL); + + GPU_blend(false); + } +} + +/* draw grease-pencil datablock */ +static void gp_draw_data( + bGPdata *gpd, int offsx, int offsy, int winx, int winy, + int cfra, int dflag, float alpha) +{ + /* turn on smooth lines (i.e. anti-aliasing) */ + GPU_line_smooth(true); + + /* turn on alpha-blending */ + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + GPU_blend(true); + + /* draw! */ + gp_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha); + + /* turn off alpha blending, then smooth lines */ + GPU_blend(false); // alpha blending + GPU_line_smooth(false); // smooth lines +} + +/* if we have strokes for scenes (3d view)/clips (movie clip editor) + * and objects/tracks, multiple data blocks have to be drawn */ +static void gp_draw_data_all( + Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy, + int cfra, int dflag, const char spacetype) +{ + bGPdata *gpd_source = NULL; + float alpha = 1.0f; + + if (scene) { + if (spacetype == SPACE_VIEW3D) { + gpd_source = (scene->gpd ? scene->gpd : NULL); + } + else if (spacetype == SPACE_CLIP && scene->clip) { + /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */ + gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL); + } + + if (gpd_source) { + gp_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha); + } + } + + /* scene/clip data has already been drawn, only object/track data is drawn here + * if gpd_source == gpd, we don't have any object/track data and we can skip */ + if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { + gp_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha); + } +} + +/* ----- Grease Pencil Sketches Drawing API ------ */ + +/* ............................ + * XXX + * We need to review the calls below, since they may be/are not that suitable for + * the new ways that we intend to be drawing data... + * ............................ */ + +/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */ +void ED_gpencil_draw_2dimage(const bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + + int offsx, offsy, sizex, sizey; + int dflag = GP_DRAWDATA_NOSTATUS; + + bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX + if (gpd == NULL) return; + + /* calculate rect */ + switch (sa->spacetype) { + case SPACE_IMAGE: /* image */ + case SPACE_CLIP: /* clip */ + { + /* just draw using standard scaling (settings here are currently ignored anyways) */ + /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ + offsx = 0; + offsy = 0; + sizex = ar->winx; + sizey = ar->winy; + + wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax); + + dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK; + break; + } + case SPACE_SEQ: /* sequence */ + { + /* just draw using standard scaling (settings here are currently ignored anyways) */ + offsx = 0; + offsy = 0; + sizex = ar->winx; + sizey = ar->winy; + + /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated + * and everything moved to standard View2d + */ + dflag |= GP_DRAWDATA_ONLYV2D; + break; + } + default: /* for spacetype not yet handled */ + offsx = 0; + offsy = 0; + sizex = ar->winx; + sizey = ar->winy; + + dflag |= GP_DRAWDATA_ONLYI2D; + break; + } + + if (ED_screen_animation_playing(wm)) { + /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses) + * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) + */ + dflag |= GP_DRAWDATA_NO_ONIONS; + } + + /* draw it! */ + gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype); +} + +/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly + * Note: this gets called twice - first time with onlyv2d=true to draw 'canvas' strokes, + * second time with onlyv2d=false for screen-aligned strokes */ +void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) +{ + wmWindowManager *wm = CTX_wm_manager(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + int dflag = 0; + + /* check that we have grease-pencil stuff to draw */ + if (sa == NULL) return; + bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX + if (gpd == NULL) return; + + /* special hack for Image Editor */ + /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ + if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) + dflag |= GP_DRAWDATA_IEDITHACK; + + /* draw it! */ + if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS); + if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS; + + gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype); + + /* draw status text (if in screen/pixel-space) */ + if (!onlyv2d) { + gp_draw_status_text(gpd, ar); + } +} + + +/* draw annotations sketches to specified 3d-view assuming that matrices are already set correctly + * Note: this gets called twice - first time with only3d=true to draw 3d-strokes, + * second time with only3d=false for screen-aligned strokes */ +void ED_gpencil_draw_view3d_annotations( + Scene *scene, struct Depsgraph *depsgraph, + View3D *v3d, ARegion *ar, + bool only3d) +{ + int dflag = 0; + RegionView3D *rv3d = ar->regiondata; + int offsx, offsy, winx, winy; + + /* check that we have grease-pencil stuff to draw */ + /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data */ + bGPdata *gpd = scene->gpd; + if (gpd == NULL) return; + + /* when rendering to the offscreen buffer we don't want to + * deal with the camera border, otherwise map the coords to the camera border. */ + if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { + rctf rectf; + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */ + + offsx = round_fl_to_int(rectf.xmin); + offsy = round_fl_to_int(rectf.ymin); + winx = round_fl_to_int(rectf.xmax - rectf.xmin); + winy = round_fl_to_int(rectf.ymax - rectf.ymin); + } + else { + offsx = 0; + offsy = 0; + winx = ar->winx; + winy = ar->winy; + } + + /* set flags */ + if (only3d) { + /* 3D strokes/3D space: + * - only 3D space points + * - don't status text either (as it's the wrong space) + */ + dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); + } + + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + /* don't draw status text when "only render" flag is set */ + dflag |= GP_DRAWDATA_NOSTATUS; + } + + /* draw it! */ + gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); +} + +#if 0 // XXX: Reinstate, after renaming the functions + +void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype) +{ + int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D; + + gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype); +} + +#endif + +/* ************************************************** */ diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c new file mode 100644 index 00000000000..6325052fccd --- /dev/null +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -0,0 +1,2382 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008/2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/gpencil/annotate_paint.c + * \ingroup edgpencil + */ + + +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" +#include "BLI_math_geom.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_report.h" +#include "BKE_screen.h" +#include "BKE_tracking.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_windowmanager_types.h" + +#include "UI_view2d.h" + +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_clip.h" + +#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_state.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DEG_depsgraph.h" + +#include "gpencil_intern.h" + +/* ******************************************* */ +/* 'Globals' and Defines */ + +/* values for tGPsdata->status */ +typedef enum eGPencil_PaintStatus { + GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */ + GP_STATUS_PAINTING, /* a stroke is in progress */ + GP_STATUS_ERROR, /* something wasn't correctly set up */ + GP_STATUS_DONE /* painting done */ +} eGPencil_PaintStatus; + +/* Return flags for adding points to stroke buffer */ +typedef enum eGP_StrokeAdd_Result { + GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */ + GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */ + GP_STROKEADD_NORMAL, /* point was successfully added */ + GP_STROKEADD_FULL /* cannot add any more points to buffer */ +} eGP_StrokeAdd_Result; + +/* Runtime flags */ +typedef enum eGPencil_PaintFlags { + GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */ + GP_PAINTFLAG_STROKEADDED = (1 << 1), + GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2), + GP_PAINTFLAG_SELECTMASK = (1 << 3), +} eGPencil_PaintFlags; + + +/* Temporary 'Stroke' Operation data + * "p" = op->customdata + */ +typedef struct tGPsdata { + Main *bmain; + Scene *scene; /* current scene from context */ + struct Depsgraph *depsgraph; + + wmWindow *win; /* window where painting originated */ + ScrArea *sa; /* area where painting originated */ + ARegion *ar; /* region where painting originated */ + View2D *v2d; /* needed for GP_STROKE_2DSPACE */ + rctf *subrect; /* for using the camera rect within the 3d view */ + rctf subrect_data; + + GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */ + + PointerRNA ownerPtr; /* pointer to owner of gp-datablock */ + bGPdata *gpd; /* gp-datablock layer comes from */ + bGPDlayer *gpl; /* layer we're working on */ + bGPDframe *gpf; /* frame we're working on */ + + char *align_flag; /* projection-mode flags (toolsettings - eGPencil_Placement_Flags) */ + + eGPencil_PaintStatus status; /* current status of painting */ + eGPencil_PaintModes paintmode; /* mode for painting */ + eGPencil_PaintFlags flags; /* flags that can get set during runtime (eGPencil_PaintFlags) */ + + short radius; /* radius of influence for eraser */ + + int mval[2]; /* current mouse-position */ + int mvalo[2]; /* previous recorded mouse-position */ + + float pressure; /* current stylus pressure */ + float opressure; /* previous stylus pressure */ + + /* These need to be doubles, as (at least under unix) they are in seconds since epoch, + * float (and its 7 digits precision) is definitively not enough here! + * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least. + */ + double inittime; /* Used when converting to path */ + double curtime; /* Used when converting to path */ + double ocurtime; /* Used when converting to path */ + + float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space + * to region space */ + float mat[4][4]; + + float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */ + + void *erasercursor; /* radial cursor data for drawing eraser */ + + short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */ + int lock_axis; /* lock drawing to one axis */ + + short keymodifier; /* key used for invoking the operator */ +} tGPsdata; + +/* ------ */ + +/* Macros for accessing sensitivity thresholds... */ +/* minimum number of pixels mouse should move before new point created */ +#define MIN_MANHATTEN_PX (U.gp_manhattendist) +/* minimum length of new segment before new point can be added */ +#define MIN_EUCLIDEAN_PX (U.gp_euclideandist) + +static bool gp_stroke_added_check(tGPsdata *p) +{ + return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED); +} + +static void gp_stroke_added_enable(tGPsdata *p) +{ + BLI_assert(p->gpf->strokes.last != NULL); + p->flags |= GP_PAINTFLAG_STROKEADDED; +} + +/* ------ */ +/* Forward defines for some functions... */ + +static void gp_session_validatebuffer(tGPsdata *p); + +/* ******************************************* */ +/* Context Wrangling... */ + +/* check if context is suitable for drawing */ +static bool gpencil_draw_poll(bContext *C) +{ + if (ED_operator_regionactive(C)) { + /* check if current context can support GPencil data */ + if (ED_gpencil_data_get_pointers(C, NULL) != NULL) { + /* check if Grease Pencil isn't already running */ + if (ED_gpencil_session_active() == 0) + return 1; + else + CTX_wm_operator_poll_msg_set(C, "Annotation operator is already active"); + } + else { + CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into"); + } + } + else { + CTX_wm_operator_poll_msg_set(C, "Active region not set"); + } + + return 0; +} + +/* check if projecting strokes into 3d-geometry in the 3D-View */ +static bool gpencil_project_check(tGPsdata *p) +{ + bGPdata *gpd = p->gpd; + return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE))); +} + +/* ******************************************* */ +/* Calculations/Conversions */ + +/* Utilities --------------------------------- */ + +/* get the reference point for stroke-point conversions */ +static void gp_get_3d_reference(tGPsdata *p, float vec[3]) +{ + View3D *v3d = p->sa->spacedata.first; + const float *fp = ED_view3d_cursor3d_get(p->scene, v3d)->location; + + /* use 3D-cursor */ + copy_v3_v3(vec, fp); +} + +/* Stroke Editing ---------------------------- */ + +/* check if the current mouse position is suitable for adding a new point */ +static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) +{ + int dx = abs(mval[0] - pmval[0]); + int dy = abs(mval[1] - pmval[1]); + + /* if buffer is empty, just let this go through (i.e. so that dots will work) */ + if (p->gpd->runtime.sbuffer_size == 0) + return true; + + /* check if mouse moved at least certain distance on both axes (best case) + * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand + */ + else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) + return true; + + /* check if the distance since the last point is significant enough + * - prevents points being added too densely + * - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though + */ + else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX) + return true; + + /* mouse 'didn't move' */ + else + return false; +} + +/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */ +static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis) +{ + float plane_normal[3]; + float vn[3]; + + float ray[3]; + float rpoint[3]; + + /* normal vector for a plane locked to axis */ + zero_v3(plane_normal); + plane_normal[axis] = 1.0f; + + /* Reproject the points in the plane */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + + /* get a vector from the point with the current view direction of the viewport */ + ED_view3d_global_to_vector(rv3d, &pt->x, vn); + + /* calculate line extrem point to create a ray that cross the plane */ + mul_v3_fl(vn, -50.0f); + add_v3_v3v3(ray, &pt->x, vn); + + /* if the line never intersect, the point is not changed */ + if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) { + copy_v3_v3(&pt->x, rpoint); + } + } +} + +/* reproject stroke to plane locked to axis in 3d cursor location */ +static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) +{ + bGPdata *gpd = p->gpd; + float origin[3]; + float cursor[3]; + RegionView3D *rv3d = p->ar->regiondata; + + /* verify the stroke mode is CURSOR 3d space mode */ + if ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) == 0) { + return; + } + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { + return; + } + if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) { + return; + } + + /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */ + gp_get_3d_reference(p, cursor); + zero_v3(origin); + origin[p->lock_axis - 1] = cursor[p->lock_axis - 1]; + + gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1); +} + +/* convert screen-coordinates to buffer-coordinates */ +/* XXX this method needs a total overhaul! */ +static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth) +{ + bGPdata *gpd = p->gpd; + + /* in 3d-space - pt->x/y/z are 3 side-by-side floats */ + if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) { + if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval, out, 0, depth))) { + /* projecting onto 3D-Geometry + * - nothing more needs to be done here, since view_autodist_simple() has already done it + */ + } + else { + float mval_prj[2]; + float rvec[3], dvec[3]; + float mval_f[2] = {UNPACK2(mval)}; + float zfac; + + /* Current method just converts each point in screen-coordinates to + * 3D-coordinates using the 3D-cursor as reference. In general, this + * works OK, but it could of course be improved. + * + * TODO: + * - investigate using nearest point(s) on a previous stroke as + * reference point instead or as offset, for easier stroke matching + */ + + gp_get_3d_reference(p, rvec); + zfac = ED_view3d_calc_zfac(p->ar->regiondata, rvec, NULL); + + if (ED_view3d_project_float_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + sub_v2_v2v2(mval_f, mval_prj, mval_f); + ED_view3d_win_to_delta(p->ar, mval_f, dvec, zfac); + sub_v3_v3v3(out, rvec, dvec); + } + else { + zero_v3(out); + } + } + } + + /* 2d - on 'canvas' (assume that p->v2d is set) */ + else if ((gpd->runtime.sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) { + UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]); + mul_v3_m4v3(out, p->imat, out); + } + + /* 2d - relative to screen (viewport area) */ + else { + if (p->subrect == NULL) { /* normal 3D view */ + out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100; + out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100; + } + else { /* camera view, use subrect */ + out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100; + out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100; + } + } +} + +/* add current stroke-point to buffer (returns whether point was successfully added) */ +static short gp_stroke_addpoint( + tGPsdata *p, const int mval[2], float pressure, double curtime) +{ + bGPdata *gpd = p->gpd; + tGPspoint *pt; + ToolSettings *ts = p->scene->toolsettings; + + /* check painting mode */ + if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { + /* straight lines only - i.e. only store start and end point in buffer */ + if (gpd->runtime.sbuffer_size == 0) { + /* first point in buffer (start point) */ + pt = (tGPspoint *)(gpd->runtime.sbuffer); + + /* store settings */ + copy_v2_v2_int(&pt->x, mval); + pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */ + pt->strength = 1.0f; + pt->time = (float)(curtime - p->inittime); + + /* increment buffer size */ + gpd->runtime.sbuffer_size++; + } + else { + /* just reset the endpoint to the latest value + * - assume that pointers for this are always valid... + */ + pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1); + + /* store settings */ + copy_v2_v2_int(&pt->x, mval); + pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */ + pt->strength = 1.0f; + pt->time = (float)(curtime - p->inittime); + + /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */ + gpd->runtime.sbuffer_size = 2; + } + + /* can keep carrying on this way :) */ + return GP_STROKEADD_NORMAL; + } + else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */ + /* check if still room in buffer */ + if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX) + return GP_STROKEADD_OVERFLOW; + + /* get pointer to destination point */ + pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size); + + /* store settings */ + copy_v2_v2_int(&pt->x, mval); + pt->pressure = pressure; + pt->strength = 1.0f; /* unused for annotations, but initialise for easier conversions to GP Object */ + + /* point time */ + pt->time = (float)(curtime - p->inittime); + + /* increment counters */ + gpd->runtime.sbuffer_size++; + + /* check if another operation can still occur */ + if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX) + return GP_STROKEADD_FULL; + else + return GP_STROKEADD_NORMAL; + } + else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { + /* get pointer to destination point */ + pt = (tGPspoint *)(gpd->runtime.sbuffer); + + /* store settings */ + copy_v2_v2_int(&pt->x, mval); + pt->pressure = 1.0f; /* T44932 - Pressure vals are unreliable, so ignore for now */ + pt->strength = 1.0f; + pt->time = (float)(curtime - p->inittime); + + /* if there's stroke for this poly line session add (or replace last) point + * to stroke. This allows to draw lines more interactively (see new segment + * during mouse slide, e.g.) + */ + if (gp_stroke_added_check(p)) { + bGPDstroke *gps = p->gpf->strokes.last; + bGPDspoint *pts; + + /* first time point is adding to temporary buffer -- need to allocate new point in stroke */ + if (gpd->runtime.sbuffer_size == 0) { + gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); + gps->totpoints++; + } + + pts = &gps->points[gps->totpoints - 1]; + + /* special case for poly lines: normally, + * depth is needed only when creating new stroke from buffer, + * but poly lines are converting to stroke instantly, + * so initialize depth buffer before converting coordinates + */ + if (gpencil_project_check(p)) { + View3D *v3d = p->sa->spacedata.first; + + view3d_region_operator_needs_opengl(p->win, p->ar); + ED_view3d_autodist_init( + p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); + } + + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } + + /* copy pressure and time */ + pts->pressure = pt->pressure; + pts->strength = pt->strength; + pts->time = pt->time; + + /* force fill recalc */ + gps->flag |= GP_STROKE_RECALC_CACHES; + } + + /* increment counters */ + if (gpd->runtime.sbuffer_size == 0) + gpd->runtime.sbuffer_size++; + + return GP_STROKEADD_NORMAL; + } + + /* return invalid state for now... */ + return GP_STROKEADD_INVALID; +} + +/* simplify a stroke (in buffer) before storing it + * - applies a reverse Chaikin filter + * - code adapted from etch-a-ton branch + */ +static void gp_stroke_simplify(tGPsdata *p) +{ + bGPdata *gpd = p->gpd; + tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer; + short num_points = gpd->runtime.sbuffer_size; + short flag = gpd->runtime.sbuffer_sflag; + short i, j; + + /* only simplify if simplification is enabled, and we're not doing a straight line */ + if (!(U.gp_settings & GP_PAINT_DOSIMPLIFY) || (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)) + return; + + /* don't simplify if less than 4 points in buffer */ + if ((num_points <= 4) || (old_points == NULL)) + return; + + /* clear buffer (but don't free mem yet) so that we can write to it + * - firstly set sbuffer to NULL, so a new one is allocated + * - secondly, reset flag after, as it gets cleared auto + */ + gpd->runtime.sbuffer = NULL; + gp_session_validatebuffer(p); + gpd->runtime.sbuffer_sflag = flag; + +/* macro used in loop to get position of new point + * - used due to the mixture of datatypes in use here + */ +#define GP_SIMPLIFY_AVPOINT(offs, sfac) \ + { \ + co[0] += (float)(old_points[offs].x * sfac); \ + co[1] += (float)(old_points[offs].y * sfac); \ + pressure += old_points[offs].pressure * sfac; \ + time += old_points[offs].time * sfac; \ + } (void)0 + + /* XXX Here too, do not lose start and end points! */ + gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time); + for (i = 0, j = 0; i < num_points; i++) { + if (i - j == 3) { + float co[2], pressure, time; + int mco[2]; + + /* initialize values */ + co[0] = 0.0f; + co[1] = 0.0f; + pressure = 0.0f; + time = 0.0f; + + /* using macro, calculate new point */ + GP_SIMPLIFY_AVPOINT(j, -0.25f); + GP_SIMPLIFY_AVPOINT(j + 1, 0.75f); + GP_SIMPLIFY_AVPOINT(j + 2, 0.75f); + GP_SIMPLIFY_AVPOINT(j + 3, -0.25f); + + /* set values for adding */ + mco[0] = (int)co[0]; + mco[1] = (int)co[1]; + + /* ignore return values on this... assume to be ok for now */ + gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time); + + j += 2; + } + } + gp_stroke_addpoint(p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure, + p->inittime + (double)old_points[num_points - 1].time); + + /* free old buffer */ + MEM_freeN(old_points); +} + +/* make a new stroke from the buffer data */ +static void gp_stroke_newfrombuffer(tGPsdata *p) +{ + bGPdata *gpd = p->gpd; + bGPDlayer *gpl = p->gpl; + bGPDstroke *gps; + bGPDspoint *pt; + tGPspoint *ptc; + ToolSettings *ts = p->scene->toolsettings; + + int i, totelem; + /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ + int depth_margin = (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; + + /* get total number of points to allocate space for + * - drawing straight-lines only requires the endpoints + */ + if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) + totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size; + else + totelem = gpd->runtime.sbuffer_size; + + /* exit with error if no valid points from this stroke */ + if (totelem == 0) { + if (G.debug & G_DEBUG) + printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size); + return; + } + + /* special case for poly line -- for already added stroke during session + * coordinates are getting added to stroke immediately to allow more + * interactive behavior + */ + if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { + if (gp_stroke_added_check(p)) { + return; + } + } + + /* allocate memory for a new stroke */ + gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); + + /* copy appropriate settings for stroke */ + gps->totpoints = totelem; + gps->thickness = gpl->thickness; + gps->flag = gpd->runtime.sbuffer_sflag; + gps->inittime = p->inittime; + + /* enable recalculation flag by default (only used if hq fill) */ + gps->flag |= GP_STROKE_RECALC_CACHES; + + /* allocate enough memory for a continuous array for storage points */ + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->tot_triangles = 0; + + /* set pointer to first non-initialized point */ + pt = gps->points + (gps->totpoints - totelem); + + /* copy points from the buffer to the stroke */ + if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { + /* straight lines only -> only endpoints */ + { + /* first point */ + ptc = gpd->runtime.sbuffer; + + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } + /* copy pressure and time */ + pt->pressure = ptc->pressure; + pt->strength = ptc->strength; + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + pt->time = ptc->time; + + pt++; + } + + if (totelem == 2) { + /* last point if applicable */ + ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1); + + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } + + /* copy pressure and time */ + pt->pressure = ptc->pressure; + pt->strength = ptc->strength; + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + pt->time = ptc->time; + } + } + else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { + /* first point */ + ptc = gpd->runtime.sbuffer; + + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } + /* copy pressure and time */ + pt->pressure = ptc->pressure; + pt->strength = ptc->strength; + pt->time = ptc->time; + } + else { + float *depth_arr = NULL; + + /* get an array of depths, far depths are blended */ + if (gpencil_project_check(p)) { + int mval[2], mval_prev[2] = { 0 }; + int interp_depth = 0; + int found_depth = 0; + + depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points"); + + for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) { + copy_v2_v2_int(mval, &ptc->x); + + if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) && + (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0))) + { + interp_depth = true; + } + else { + found_depth = true; + } + + copy_v2_v2_int(mval_prev, mval); + } + + if (found_depth == false) { + /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */ + for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) + depth_arr[i] = 0.9999f; + } + else { + if (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) { + /* remove all info between the valid endpoints */ + int first_valid = 0; + int last_valid = 0; + + for (i = 0; i < gpd->runtime.sbuffer_size; i++) { + if (depth_arr[i] != FLT_MAX) + break; + } + first_valid = i; + + for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) { + if (depth_arr[i] != FLT_MAX) + break; + } + last_valid = i; + + /* invalidate non-endpoints, so only blend between first and last */ + for (i = first_valid + 1; i < last_valid; i++) + depth_arr[i] = FLT_MAX; + + interp_depth = true; + } + + if (interp_depth) { + interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX); + } + } + } + + + pt = gps->points; + + /* convert all points (normal behavior) */ + for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size && ptc; i++, ptc++, pt++) { + /* convert screen-coordinates to appropriate coordinates (and store them) */ + gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); + + /* copy pressure and time */ + pt->pressure = ptc->pressure; + pt->strength = ptc->strength; + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + pt->time = ptc->time; + } + + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } + + if (depth_arr) + MEM_freeN(depth_arr); + } + + /* add stroke to frame */ + BLI_addtail(&p->gpf->strokes, gps); + gp_stroke_added_enable(p); +} + +/* --- 'Eraser' for 'Paint' Tool ------ */ + +/* helper to free a stroke + * NOTE: gps->dvert and gps->triangles should be NULL, but check anyway for good measure + */ +static void gp_free_stroke(bGPdata *UNUSED(gpd), bGPDframe *gpf, bGPDstroke *gps) +{ + if (gps->points) { + MEM_freeN(gps->points); + } + + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + + if (gps->triangles) { + MEM_freeN(gps->triangles); + } + + BLI_freelinkN(&gpf->strokes, gps); +} + + +/* which which point is infront (result should only be used for comparison) */ +static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) +{ + if (rv3d->is_persp) { + return ED_view3d_calc_zfac(rv3d, co, NULL); + } + else { + return -dot_v3v3(rv3d->viewinv[2], co); + } +} + +/* only erase stroke points that are visible (3d view) */ +static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y) +{ + if ((p->sa->spacetype == SPACE_VIEW3D) && + (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) + { + RegionView3D *rv3d = p->ar->regiondata; + const int mval[2] = {x, y}; + float mval_3d[3]; + + if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) { + const float depth_mval = view3d_point_depth(rv3d, mval_3d); + const float depth_pt = view3d_point_depth(rv3d, &pt->x); + + if (depth_pt > depth_mval) { + return true; + } + } + } + return false; +} + +/* eraser tool - evaluation per stroke */ +/* TODO: this could really do with some optimization (KD-Tree/BVH?) */ +static void gp_stroke_eraser_dostroke(tGPsdata *p, + bGPDframe *gpf, bGPDstroke *gps, + const int mval[2], const int mvalo[2], + const int radius, const rcti *rect) +{ + bGPDspoint *pt1, *pt2; + int pc1[2] = {0}; + int pc2[2] = {0}; + int i; + + if (gps->totpoints == 0) { + /* just free stroke */ + gp_free_stroke(p->gpd, gpf, gps); + } + else if (gps->totpoints == 1) { + /* only process if it hasn't been masked out... */ + if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { + gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); + + /* do boundbox check first */ + if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { + /* only check if point is inside */ + if (len_v2v2_int(mval, pc1) <= radius) { + /* free stroke */ + gp_free_stroke(p->gpd, gpf, gps); + } + } + } + } + else { + /* Perform culling? */ + bool do_cull = false; + + /* Clear Tags + * + * Note: It's better this way, as we are sure that + * we don't miss anything, though things will be + * slightly slower as a result + */ + for (i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + pt->flag &= ~GP_SPOINT_TAG; + } + + /* First Pass: Loop over the points in the stroke + * 1) Thin out parts of the stroke under the brush + * 2) Tag "too thin" parts for removal (in second pass) + */ + for (i = 0; (i + 1) < gps->totpoints; i++) { + /* get points to work with */ + pt1 = gps->points + i; + pt2 = gps->points + i + 1; + + /* only process if it hasn't been masked out... */ + if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) + continue; + + gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); + gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); + + /* Check that point segment of the boundbox of the eraser stroke */ + if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || + ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) + { + /* Check if point segment of stroke had anything to do with + * eraser region (either within stroke painted, or on its lines) + * - this assumes that linewidth is irrelevant + */ + if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) { + if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) || + (gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) + { + /* Edge is affected - Check individual points now */ + if (len_v2v2_int(mval, pc1) <= radius) { + pt1->flag |= GP_SPOINT_TAG; + } + if (len_v2v2_int(mval, pc2) <= radius) { + pt2->flag |= GP_SPOINT_TAG; + } + do_cull = true; + } + } + } + } + + /* Second Pass: Remove any points that are tagged */ + if (do_cull) { + gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false); + } + } +} + +/* erase strokes which fall under the eraser strokes */ +static void gp_stroke_doeraser(tGPsdata *p) +{ + bGPDframe *gpf = p->gpf; + bGPDstroke *gps, *gpn; + rcti rect; + + /* rect is rectangle of eraser */ + rect.xmin = p->mval[0] - p->radius; + rect.ymin = p->mval[1] - p->radius; + rect.xmax = p->mval[0] + p->radius; + rect.ymax = p->mval[1] + p->radius; + + if (p->sa->spacetype == SPACE_VIEW3D) { + if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) { + View3D *v3d = p->sa->spacedata.first; + view3d_region_operator_needs_opengl(p->win, p->ar); + ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, 0); + } + } + + /* loop over strokes of active layer only (session init already took care of ensuring validity), + * checking segments for intersections to remove + */ + for (gps = gpf->strokes.first; gps; gps = gpn) { + gpn = gps->next; + /* Not all strokes in the datablock may be valid in the current editor/context + * (e.g. 2D space strokes in the 3D view, if the same datablock is shared) + */ + if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) { + gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, p->radius, &rect); + } + } +} + +/* ******************************************* */ +/* Sketching Operator */ + +/* clear the session buffers (call this before AND after a paint operation) */ +static void gp_session_validatebuffer(tGPsdata *p) +{ + bGPdata *gpd = p->gpd; + + /* clear memory of buffer (or allocate it if starting a new session) */ + if (gpd->runtime.sbuffer) { + /* printf("\t\tGP - reset sbuffer\n"); */ + memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX); + } + else { + /* printf("\t\tGP - allocate sbuffer\n"); */ + gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); + } + + /* reset indices */ + gpd->runtime.sbuffer_size = 0; + + /* reset flags */ + gpd->runtime.sbuffer_sflag = 0; + + /* reset inittime */ + p->inittime = 0.0; +} + +/* (re)init new painting data */ +static bool gp_session_initdata(bContext *C, tGPsdata *p) +{ + Main *bmain = CTX_data_main(C); + bGPdata **gpd_ptr = NULL; + ScrArea *curarea = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + /* make sure the active view (at the starting time) is a 3d-view */ + if (curarea == NULL) { + p->status = GP_STATUS_ERROR; + if (G.debug & G_DEBUG) + printf("Error: No active view for painting\n"); + return 0; + } + + /* pass on current scene and window */ + p->bmain = CTX_data_main(C); + p->scene = CTX_data_scene(C); + p->depsgraph = CTX_data_depsgraph(C); + p->win = CTX_wm_window(C); + + unit_m4(p->imat); + unit_m4(p->mat); + + switch (curarea->spacetype) { + /* supported views first */ + case SPACE_VIEW3D: + { + /* View3D *v3d = curarea->spacedata.first; */ + /* RegionView3D *rv3d = ar->regiondata; */ + + /* set current area + * - must verify that region data is 3D-view (and not something else) + */ + /* CAUTION: If this is the "toolbar", then this will change on the first stroke */ + p->sa = curarea; + p->ar = ar; + p->align_flag = &ts->annotate_v3d_align; + + if (ar->regiondata == NULL) { + p->status = GP_STATUS_ERROR; + if (G.debug & G_DEBUG) + printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n"); + return 0; + } + break; + } + case SPACE_NODE: + { + /* SpaceNode *snode = curarea->spacedata.first; */ + + /* set current area */ + p->sa = curarea; + p->ar = ar; + p->v2d = &ar->v2d; + p->align_flag = &ts->gpencil_v2d_align; + break; + } + case SPACE_SEQ: + { + SpaceSeq *sseq = curarea->spacedata.first; + + /* set current area */ + p->sa = curarea; + p->ar = ar; + p->v2d = &ar->v2d; + p->align_flag = &ts->gpencil_seq_align; + + /* check that gpencil data is allowed to be drawn */ + if (sseq->mainb == SEQ_DRAW_SEQUENCE) { + p->status = GP_STATUS_ERROR; + if (G.debug & G_DEBUG) + printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n"); + return 0; + } + break; + } + case SPACE_IMAGE: + { + /* SpaceImage *sima = curarea->spacedata.first; */ + + /* set the current area */ + p->sa = curarea; + p->ar = ar; + p->v2d = &ar->v2d; + p->align_flag = &ts->gpencil_ima_align; + break; + } + case SPACE_CLIP: + { + SpaceClip *sc = curarea->spacedata.first; + MovieClip *clip = ED_space_clip_get_clip(sc); + + if (clip == NULL) { + p->status = GP_STATUS_ERROR; + return false; + } + + /* set the current area */ + p->sa = curarea; + p->ar = ar; + p->v2d = &ar->v2d; + p->align_flag = &ts->gpencil_v2d_align; + + invert_m4_m4(p->imat, sc->unistabmat); + + /* custom color for new layer */ + p->custom_color[0] = 1.0f; + p->custom_color[1] = 0.0f; + p->custom_color[2] = 0.5f; + p->custom_color[3] = 0.9f; + + if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { + int framenr = ED_space_clip_get_clip_frame_number(sc); + MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking); + MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL; + + if (marker) { + p->imat[3][0] -= marker->pos[0]; + p->imat[3][1] -= marker->pos[1]; + } + else { + p->status = GP_STATUS_ERROR; + return false; + } + } + + invert_m4_m4(p->mat, p->imat); + copy_m4_m4(p->gsc.mat, p->mat); + break; + } + /* unsupported views */ + default: + { + p->status = GP_STATUS_ERROR; + if (G.debug & G_DEBUG) + printf("Error: Annotations are not supported in this editor\n"); + return 0; + } + } + + /* get gp-data */ + gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr); + if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) { + p->status = GP_STATUS_ERROR; + if (G.debug & G_DEBUG) + printf("Error: Current context doesn't allow for any Annotation data\n"); + return 0; + } + else { + /* if no existing GPencil block exists, add one */ + if (*gpd_ptr == NULL) { + bGPdata *gpd = BKE_gpencil_data_addnew(bmain, "Annotations"); + *gpd_ptr = gpd; + + /* mark datablock as being used for annotations */ + gpd->flag |= GP_DATA_ANNOTATIONS; + + /* annotations always in front of all objects */ + gpd->xray_mode = GP_XRAY_FRONT; + } + p->gpd = *gpd_ptr; + } + + if (ED_gpencil_session_active() == 0) { + /* initialize undo stack, + * also, existing undo stack would make buffer drawn + */ + gpencil_undo_init(p->gpd); + } + + /* clear out buffer (stored in gp-data), in case something contaminated it */ + gp_session_validatebuffer(p); + + /* lock axis */ + p->lock_axis = ts->gp_sculpt.lock_axis; + + return 1; +} + +/* init new painting session */ +static tGPsdata *gp_session_initpaint(bContext *C) +{ + tGPsdata *p = NULL; + + /* create new context data */ + p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data"); + + gp_session_initdata(C, p); + + /* radius for eraser circle is defined in userprefs now */ + /* NOTE: we do this here, so that if we exit immediately, + * erase size won't get lost + */ + p->radius = U.gp_eraser; + + /* return context data for running paint operator */ + return p; +} + +/* cleanup after a painting session */ +static void gp_session_cleanup(tGPsdata *p) +{ + bGPdata *gpd = (p) ? p->gpd : NULL; + + /* error checking */ + if (gpd == NULL) + return; + + /* free stroke buffer */ + if (gpd->runtime.sbuffer) { + /* printf("\t\tGP - free sbuffer\n"); */ + MEM_freeN(gpd->runtime.sbuffer); + gpd->runtime.sbuffer = NULL; + } + + /* clear flags */ + gpd->runtime.sbuffer_size = 0; + gpd->runtime.sbuffer_sflag = 0; + p->inittime = 0.0; +} + +static void gp_session_free(tGPsdata *p) +{ + MEM_freeN(p); +} + + +/* init new stroke */ +static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph) +{ + Scene *scene = p->scene; + ToolSettings *ts = scene->toolsettings; + + /* get active layer (or add a new one if non-existent) */ + p->gpl = BKE_gpencil_layer_getactive(p->gpd); + if (p->gpl == NULL) { + p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true); + + if (p->custom_color[3]) + copy_v3_v3(p->gpl->color, p->custom_color); + } + if (p->gpl->flag & GP_LAYER_LOCKED) { + p->status = GP_STATUS_ERROR; + if (G.debug & G_DEBUG) + printf("Error: Cannot paint on locked layer\n"); + return; + } + + /* get active frame (add a new one if not matching frame) */ + if (paintmode == GP_PAINTMODE_ERASER) { + /* Eraser mode: + * 1) Only allow erasing on the active layer (unlike for 3d-art Grease Pencil), + * since we won't be exposing layer locking in the UI + * 2) Ensure that p->gpf refers to the frame used for the active layer + * (to avoid problems with other tools which expect it to exist) + */ + bool has_layer_to_erase = false; + + if (gpencil_layer_is_editable(p->gpl)) { + /* Ensure that there's stuff to erase here (not including selection mask below)... */ + if (p->gpl->actframe && p->gpl->actframe->strokes.first) { + has_layer_to_erase = true; + } + } + + /* Ensure active frame is set correctly... */ + p->gpf = p->gpl->actframe; + + /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on + * (though this is only available in editmode) + */ + if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) { + if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { + p->flags |= GP_PAINTFLAG_SELECTMASK; + } + } + + if (has_layer_to_erase == false) { + p->status = GP_STATUS_ERROR; + //if (G.debug & G_DEBUG) + printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n"); + return; + } + } + else { + /* Drawing Modes - Add a new frame if needed on the active layer */ + short add_frame_mode = GP_GETFRAME_ADD_NEW; + + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) + add_frame_mode = GP_GETFRAME_ADD_COPY; + else + add_frame_mode = GP_GETFRAME_ADD_NEW; + + p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode); + + if (p->gpf == NULL) { + p->status = GP_STATUS_ERROR; + if (G.debug & G_DEBUG) + printf("Error: No frame created (gpencil_paint_init)\n"); + return; + } + else { + p->gpf->flag |= GP_FRAME_PAINT; + } + } + + /* set 'eraser' for this stroke if using eraser */ + p->paintmode = paintmode; + if (p->paintmode == GP_PAINTMODE_ERASER) { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER; + + /* check if we should respect depth while erasing */ + if (p->sa->spacetype == SPACE_VIEW3D) { + if (p->gpl->flag & GP_LAYER_NO_XRAY) { + p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH; + } + } + } + else { + /* disable eraser flags - so that we can switch modes during a session */ + p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER; + + if (p->sa->spacetype == SPACE_VIEW3D) { + if (p->gpl->flag & GP_LAYER_NO_XRAY) { + p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH; + } + } + } + + /* set 'initial run' flag, which is only used to denote when a new stroke is starting */ + p->flags |= GP_PAINTFLAG_FIRSTRUN; + + + /* when drawing in the camera view, in 2D space, set the subrect */ + p->subrect = NULL; + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { + if (p->sa->spacetype == SPACE_VIEW3D) { + View3D *v3d = p->sa->spacedata.first; + RegionView3D *rv3d = p->ar->regiondata; + + /* for camera view set the subrect */ + if (rv3d->persp == RV3D_CAMOB) { + ED_view3d_calc_camera_border(p->scene, depsgraph, p->ar, v3d, rv3d, &p->subrect_data, true); /* no shift */ + p->subrect = &p->subrect_data; + } + } + } + + /* init stroke point space-conversion settings... */ + p->gsc.gpd = p->gpd; + p->gsc.gpl = p->gpl; + + p->gsc.sa = p->sa; + p->gsc.ar = p->ar; + p->gsc.v2d = p->v2d; + + p->gsc.subrect_data = p->subrect_data; + p->gsc.subrect = p->subrect; + + copy_m4_m4(p->gsc.mat, p->mat); + + + /* check if points will need to be made in view-aligned space */ + if (*p->align_flag & GP_PROJECT_VIEWSPACE) { + switch (p->sa->spacetype) { + case SPACE_VIEW3D: + { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE; + break; + } + case SPACE_NODE: + { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE; + break; + } + case SPACE_SEQ: + { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE; + break; + } + case SPACE_IMAGE: + { + SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first; + + /* only set these flags if the image editor doesn't have an image active, + * otherwise user will be confused by strokes not appearing after they're drawn + * + * Admittedly, this is a bit hacky, but it works much nicer from an ergonomic standpoint! + */ + if (ELEM(NULL, sima, sima->image)) { + /* make strokes be drawn in screen space */ + p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_2DSPACE; + *(p->align_flag) &= ~GP_PROJECT_VIEWSPACE; + } + else { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE; + } + break; + } + case SPACE_CLIP: + { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_2DSPACE; + break; + } + } + } +} + +/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */ +static void gp_paint_strokeend(tGPsdata *p) +{ + ToolSettings *ts = p->scene->toolsettings; + /* for surface sketching, need to set the right OpenGL context stuff so that + * the conversions will project the values correctly... + */ + if (gpencil_project_check(p)) { + View3D *v3d = p->sa->spacedata.first; + + /* need to restore the original projection settings before packing up */ + view3d_region_operator_needs_opengl(p->win, p->ar); + ED_view3d_autodist_init(p->depsgraph, p->ar, v3d, (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); + } + + /* check if doing eraser or not */ + if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { + /* simplify stroke before transferring? */ + gp_stroke_simplify(p); + + /* transfer stroke to frame */ + gp_stroke_newfrombuffer(p); + } + + /* clean up buffer now */ + gp_session_validatebuffer(p); +} + +/* finish off stroke painting operation */ +static void gp_paint_cleanup(tGPsdata *p) +{ + /* p->gpd==NULL happens when stroke failed to initialize, + * for example when GP is hidden in current space (sergey) + */ + if (p->gpd) { + /* finish off a stroke */ + gp_paint_strokeend(p); + } + + /* "unlock" frame */ + if (p->gpf) + p->gpf->flag &= ~GP_FRAME_PAINT; +} + +/* ------------------------------- */ + +/* Helper callback for drawing the cursor itself */ +static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr) +{ + tGPsdata *p = (tGPsdata *)p_ptr; + + if (p->paintmode == GP_PAINTMODE_ERASER) { + GPUVertFormat *format = immVertexFormat(); + const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + GPU_line_smooth(true); + GPU_blend(true); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + immUniformColor4ub(255, 100, 100, 20); + imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40); + + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + GPU_viewport_size_get_f(viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f); + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniform1f("dash_width", 12.0f); + immUniform1f("dash_factor", 0.5f); + + imm_draw_circle_wire_2d(shdr_pos, x, y, p->radius, + /* XXX Dashed shader gives bad results with sets of small segments currently, + * temp hack around the issue. :( */ + max_ii(8, p->radius / 2)); /* was fixed 40 */ + + immUnbindProgram(); + + GPU_blend(false); + GPU_line_smooth(false); + } +} + +/* Turn brush cursor in 3D view on/off */ +static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable) +{ + if (p->erasercursor && !enable) { + /* clear cursor */ + WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor); + p->erasercursor = NULL; + } + else if (enable && !p->erasercursor) { + /* enable cursor */ + p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), + NULL, /* XXX */ + gpencil_draw_eraser, p); + } +} + +/* Check if tablet eraser is being used (when processing events) */ +static bool gpencil_is_tablet_eraser_active(const wmEvent *event) +{ + if (event->tablet_data) { + const wmTabletData *wmtab = event->tablet_data; + return (wmtab->Active == EVT_TABLET_ERASER); + } + + return false; +} + +/* ------------------------------- */ + +static void gpencil_draw_exit(bContext *C, wmOperator *op) +{ + tGPsdata *p = op->customdata; + + /* clear undo stack */ + gpencil_undo_finish(); + + /* restore cursor to indicate end of drawing */ + WM_cursor_modal_restore(CTX_wm_window(C)); + + /* don't assume that operator data exists at all */ + if (p) { + /* check size of buffer before cleanup, to determine if anything happened here */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + /* turn off radial brush cursor */ + gpencil_draw_toggle_eraser_cursor(C, p, false); + } + + /* always store the new eraser size to be used again next time + * NOTE: Do this even when not in eraser mode, as eraser may + * have been toggled at some point. + */ + U.gp_eraser = p->radius; + + /* cleanup */ + gp_paint_cleanup(p); + gp_session_cleanup(p); + gp_session_free(p); + } + + op->customdata = NULL; +} + +static void gpencil_draw_cancel(bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + gpencil_draw_exit(C, op); +} + +/* ------------------------------- */ + + +static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) +{ + tGPsdata *p; + eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode"); + + /* check context */ + p = op->customdata = gp_session_initpaint(C); + if ((p == NULL) || (p->status == GP_STATUS_ERROR)) { + /* something wasn't set correctly in context */ + gpencil_draw_exit(C, op); + return 0; + } + + /* init painting data */ + gp_paint_initstroke(p, paintmode, CTX_data_depsgraph(C)); + if (p->status == GP_STATUS_ERROR) { + gpencil_draw_exit(C, op); + return 0; + } + + if (event != NULL) { + p->keymodifier = event->keymodifier; + } + else { + p->keymodifier = -1; + } + + /* everything is now setup ok */ + return 1; +} + + +/* ------------------------------- */ + +/* ensure that the correct cursor icon is set */ +static void gpencil_draw_cursor_set(tGPsdata *p) +{ + if (p->paintmode == GP_PAINTMODE_ERASER) + WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */ + else + WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR); +} + +/* update UI indicators of status, including cursor and header prints */ +static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) +{ + /* header prints */ + switch (p->status) { + case GP_STATUS_PAINTING: + switch (p->paintmode) { + case GP_PAINTMODE_DRAW_POLY: + /* Provide usage tips, since this is modal, and unintuitive without hints */ + ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | " + "ESC/Enter to end (or click outside this area)")); + break; + default: + /* Do nothing - the others are self explanatory, exit quickly once the mouse is released + * Showing any text would just be annoying as it would flicker. + */ + break; + } + break; + + case GP_STATUS_IDLING: + /* print status info */ + switch (p->paintmode) { + case GP_PAINTMODE_ERASER: + ED_workspace_status_text(C, IFACE_("Annotation Eraser: Hold and drag LMB or RMB to erase | " + "ESC/Enter to end (or click outside this area)")); + break; + case GP_PAINTMODE_DRAW_STRAIGHT: + ED_workspace_status_text(C, IFACE_("Annotation Line Draw: Hold and drag LMB to draw | " + "ESC/Enter to end (or click outside this area)")); + break; + case GP_PAINTMODE_DRAW: + ED_workspace_status_text(C, IFACE_("Annotation Freehand Draw: Hold and drag LMB to draw | " + "E/ESC/Enter to end (or click outside this area)")); + break; + case GP_PAINTMODE_DRAW_POLY: + ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | " + "ESC/Enter to end (or click outside this area)")); + break; + + default: /* unhandled future cases */ + ED_workspace_status_text(C, IFACE_("Annotation Session: ESC/Enter to end (or click outside this area)")); + break; + } + break; + + case GP_STATUS_ERROR: + case GP_STATUS_DONE: + /* clear status string */ + ED_workspace_status_text(C, NULL); + break; + } +} + +/* ------------------------------- */ + +/* create a new stroke point at the point indicated by the painting context */ +static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph) +{ + /* handle drawing/erasing -> test for erasing first */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + /* do 'live' erasing now */ + gp_stroke_doeraser(p); + + /* store used values */ + p->mvalo[0] = p->mval[0]; + p->mvalo[1] = p->mval[1]; + p->opressure = p->pressure; + } + /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */ + else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) { + /* try to add point */ + short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + + /* handle errors while adding point */ + if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) { + /* finish off old stroke */ + gp_paint_strokeend(p); + /* And start a new one!!! Else, projection errors! */ + gp_paint_initstroke(p, p->paintmode, depsgraph); + + /* start a new stroke, starting from previous point */ + /* XXX Must manually reset inittime... */ + /* XXX We only need to reuse previous point if overflow! */ + if (ok == GP_STROKEADD_OVERFLOW) { + p->inittime = p->ocurtime; + gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime); + } + else { + p->inittime = p->curtime; + } + gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); + } + else if (ok == GP_STROKEADD_INVALID) { + /* the painting operation cannot continue... */ + BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke"); + p->status = GP_STATUS_ERROR; + + if (G.debug & G_DEBUG) + printf("Error: Grease-Pencil Paint - Add Point Invalid\n"); + return; + } + + /* store used values */ + p->mvalo[0] = p->mval[0]; + p->mvalo[1] = p->mval[1]; + p->opressure = p->pressure; + p->ocurtime = p->curtime; + } +} + +/* handle draw event */ +static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsgraph *depsgraph) +{ + tGPsdata *p = op->customdata; + PointerRNA itemptr; + float mousef[2]; + int tablet = 0; + + /* convert from window-space to area-space mouse coordinates + * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding... + */ + p->mval[0] = event->mval[0] + 1; + p->mval[1] = event->mval[1] + 1; + + /* verify key status for straight lines */ + if ((event->ctrl > 0) || (event->alt > 0)) { + if (p->straight[0] == 0) { + int dx = abs(p->mval[0] - p->mvalo[0]); + int dy = abs(p->mval[1] - p->mvalo[1]); + if ((dx > 0) || (dy > 0)) { + /* check mouse direction to replace the other coordinate with previous values */ + if (dx >= dy) { + /* horizontal */ + p->straight[0] = 1; + p->straight[1] = p->mval[1]; /* save y */ + } + else { + /* vertical */ + p->straight[0] = 2; + p->straight[1] = p->mval[0]; /* save x */ + } + } + } + } + else { + p->straight[0] = 0; + } + + p->curtime = PIL_check_seconds_timer(); + + /* handle pressure sensitivity (which is supplied by tablets) */ + if (event->tablet_data) { + const wmTabletData *wmtab = event->tablet_data; + + tablet = (wmtab->Active != EVT_TABLET_NONE); + p->pressure = wmtab->Pressure; + + /* Hack for pressure sensitive eraser on D+RMB when using a tablet: + * The pen has to float over the tablet surface, resulting in + * zero pressure (T47101). Ignore pressure values if floating + * (i.e. "effectively zero" pressure), and only when the "active" + * end is the stylus (i.e. the default when not eraser) + */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + if ((wmtab->Active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) { + p->pressure = 1.0f; + } + } + } + else { + /* No tablet data -> No pressure info is available */ + p->pressure = 1.0f; + } + + /* special exception for start of strokes (i.e. maybe for just a dot) */ + if (p->flags & GP_PAINTFLAG_FIRSTRUN) { + p->flags &= ~GP_PAINTFLAG_FIRSTRUN; + + p->mvalo[0] = p->mval[0]; + p->mvalo[1] = p->mval[1]; + p->opressure = p->pressure; + p->inittime = p->ocurtime = p->curtime; + p->straight[0] = 0; + p->straight[1] = 0; + + /* special exception here for too high pressure values on first touch in + * windows for some tablets, then we just skip first touch... + */ + if (tablet && (p->pressure >= 0.99f)) + return; + } + + /* check if alt key is pressed and limit to straight lines */ + if (p->straight[0] != 0) { + if (p->straight[0] == 1) { + /* horizontal */ + p->mval[1] = p->straight[1]; /* replace y */ + } + else { + /* vertical */ + p->mval[0] = p->straight[1]; /* replace x */ + } + } + + /* fill in stroke data (not actually used directly by gpencil_draw_apply) */ + RNA_collection_add(op->ptr, "stroke", &itemptr); + + mousef[0] = p->mval[0]; + mousef[1] = p->mval[1]; + RNA_float_set_array(&itemptr, "mouse", mousef); + RNA_float_set(&itemptr, "pressure", p->pressure); + RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0); + + RNA_float_set(&itemptr, "time", p->curtime - p->inittime); + + /* apply the current latest drawing point */ + gpencil_draw_apply(op, p, depsgraph); + + /* force refresh */ + ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */ +} + +/* ------------------------------- */ + +/* operator 'redo' (i.e. after changing some properties, but also for repeat last) */ +static int gpencil_draw_exec(bContext *C, wmOperator *op) +{ + tGPsdata *p = NULL; + Depsgraph *depsgraph = CTX_data_depsgraph(C); + + /* printf("GPencil - Starting Re-Drawing\n"); */ + + /* try to initialize context data needed while drawing */ + if (!gpencil_draw_init(C, op, NULL)) { + if (op->customdata) MEM_freeN(op->customdata); + /* printf("\tGP - no valid data\n"); */ + return OPERATOR_CANCELLED; + } + else + p = op->customdata; + + /* printf("\tGP - Start redrawing stroke\n"); */ + + /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement), + * setting the relevant values in context at each step, then applying + */ + RNA_BEGIN (op->ptr, itemptr, "stroke") + { + float mousef[2]; + + /* printf("\t\tGP - stroke elem\n"); */ + + /* get relevant data for this point from stroke */ + RNA_float_get_array(&itemptr, "mouse", mousef); + p->mval[0] = (int)mousef[0]; + p->mval[1] = (int)mousef[1]; + p->pressure = RNA_float_get(&itemptr, "pressure"); + p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime; + + if (RNA_boolean_get(&itemptr, "is_start")) { + /* if first-run flag isn't set already (i.e. not true first stroke), + * then we must terminate the previous one first before continuing + */ + if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) { + /* TODO: both of these ops can set error-status, but we probably don't need to worry */ + gp_paint_strokeend(p); + gp_paint_initstroke(p, p->paintmode, depsgraph); + } + } + + /* if first run, set previous data too */ + if (p->flags & GP_PAINTFLAG_FIRSTRUN) { + p->flags &= ~GP_PAINTFLAG_FIRSTRUN; + + p->mvalo[0] = p->mval[0]; + p->mvalo[1] = p->mval[1]; + p->opressure = p->pressure; + p->ocurtime = p->curtime; + } + + /* apply this data as necessary now (as per usual) */ + gpencil_draw_apply(op, p, depsgraph); + } + RNA_END; + + /* printf("\tGP - done\n"); */ + + /* cleanup */ + gpencil_draw_exit(C, op); + + /* refreshes */ + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + + /* done */ + return OPERATOR_FINISHED; +} + +/* ------------------------------- */ + +/* start of interactive drawing part of operator */ +static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *ob = CTX_data_active_object(C); + tGPsdata *p = NULL; + + /* GPXX Need a better solution */ + if ((ob != NULL) && (ob->type == OB_GPENCIL)) { + BKE_report(op->reports, RPT_ERROR, "Cannot draw annotation with a Grease Pencil object active"); + return OPERATOR_CANCELLED; + } + + if (G.debug & G_DEBUG) + printf("GPencil - Starting Drawing\n"); + + /* try to initialize context data needed while drawing */ + if (!gpencil_draw_init(C, op, event)) { + if (op->customdata) + MEM_freeN(op->customdata); + if (G.debug & G_DEBUG) + printf("\tGP - no valid data\n"); + return OPERATOR_CANCELLED; + } + else + p = op->customdata; + + /* TODO: set any additional settings that we can take from the events? + * TODO? if tablet is erasing, force eraser to be on? */ + + /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */ + + /* if eraser is on, draw radial aid */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + gpencil_draw_toggle_eraser_cursor(C, p, true); + } + /* set cursor + * NOTE: This may change later (i.e. intentionally via brush toggle, + * or unintentionally if the user scrolls outside the area)... + */ + gpencil_draw_cursor_set(p); + + /* only start drawing immediately if we're allowed to do so... */ + if (RNA_boolean_get(op->ptr, "wait_for_input") == false) { + /* hotkey invoked - start drawing */ + /* printf("\tGP - set first spot\n"); */ + p->status = GP_STATUS_PAINTING; + + /* handle the initial drawing - i.e. for just doing a simple dot */ + gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); + op->flag |= OP_IS_MODAL_CURSOR_REGION; + } + else { + /* toolbar invoked - don't start drawing yet... */ + /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */ + op->flag |= OP_IS_MODAL_CURSOR_REGION; + } + + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + /* add a modal handler for this operator, so that we can then draw continuous strokes */ + WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; +} + +/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ +static bool gpencil_area_exists(bContext *C, ScrArea *sa_test) +{ + bScreen *sc = CTX_wm_screen(C); + return (BLI_findindex(&sc->areabase, sa_test) != -1); +} + +static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) +{ + tGPsdata *p = op->customdata; + + /* we must check that we're still within the area that we're set up to work from + * otherwise we could crash (see bug #20586) + */ + if (CTX_wm_area(C) != p->sa) { + printf("\t\t\tGP - wrong area execution abort!\n"); + p->status = GP_STATUS_ERROR; + } + + /* printf("\t\tGP - start stroke\n"); */ + + /* we may need to set up paint env again if we're resuming */ + /* XXX: watch it with the paintmode! in future, + * it'd be nice to allow changing paint-mode when in sketching-sessions */ + + if (gp_session_initdata(C, p)) + gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C)); + + if (p->status != GP_STATUS_ERROR) { + p->status = GP_STATUS_PAINTING; + op->flag &= ~OP_IS_MODAL_CURSOR_REGION; + } + + return op->customdata; +} + +static void gpencil_stroke_end(wmOperator *op) +{ + tGPsdata *p = op->customdata; + + gp_paint_cleanup(p); + + gpencil_undo_push(p->gpd); + + gp_session_cleanup(p); + + p->status = GP_STATUS_IDLING; + op->flag |= OP_IS_MODAL_CURSOR_REGION; + + p->gpd = NULL; + p->gpl = NULL; + p->gpf = NULL; +} + +/* events handling during interactive drawing part of operator */ +static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + tGPsdata *p = op->customdata; + int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */ + + /* if (event->type == NDOF_MOTION) + * return OPERATOR_PASS_THROUGH; + * ------------------------------- + * [mce] Not quite what I was looking + * for, but a good start! GP continues to + * draw on the screen while the 3D mouse + * moves the viewpoint. Problem is that + * the stroke is converted to 3D only after + * it is finished. This approach should work + * better in tools that immediately apply + * in 3D space. + */ + + if (p->status == GP_STATUS_IDLING) { + ARegion *ar = CTX_wm_region(C); + p->ar = ar; + } + + /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */ + if (ISKEYBOARD(event->type)) { + if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY, ZKEY)) { + /* allow some keys: + * - for frame changing [#33412] + * - for undo (during sketching sessions) + */ + } + else if (ELEM(event->type, PAD0, PAD1, PAD2, PAD3, PAD4, PAD5, PAD6, PAD7, PAD8, PAD9)) { + /* allow numpad keys so that camera/view manipulations can still take place + * - PAD0 in particular is really important for Grease Pencil drawing, + * as animators may be working "to camera", so having this working + * is essential for ensuring that they can quickly return to that view + */ + } + else if ((event->type == BKEY) && (event->val == KM_RELEASE)) { + /* Add Blank Frame + * - Since this operator is non-modal, we can just call it here, and keep going... + * - This operator is especially useful when animating + */ + WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL); + estate = OPERATOR_RUNNING_MODAL; + } + else { + estate = OPERATOR_RUNNING_MODAL; + } + } + + //printf("\tGP - handle modal event...\n"); + + /* exit painting mode (and/or end current stroke) + * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] + */ + if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) { + /* exit() ends the current stroke before cleaning up */ + /* printf("\t\tGP - end of paint op + end of stroke\n"); */ + p->status = GP_STATUS_DONE; + estate = OPERATOR_FINISHED; + } + + /* toggle painting mode upon mouse-button movement + * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only) + * - RIGHTMOUSE = polyline (hotkey) / eraser (all) + * (Disabling RIGHTMOUSE case here results in bugs like [#32647]) + * also making sure we have a valid event value, to not exit too early + */ + if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) { + /* if painting, end stroke */ + if (p->status == GP_STATUS_PAINTING) { + int sketch = 0; + + /* basically, this should be mouse-button up = end stroke + * BUT, polyline drawing is an exception -- all knots should be added during one session + */ + sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY); + + if (sketch) { + /* end stroke only, and then wait to resume painting soon */ + /* printf("\t\tGP - end stroke only\n"); */ + gpencil_stroke_end(op); + + /* If eraser mode is on, turn it off after the stroke finishes + * NOTE: This just makes it nicer to work with drawing sessions + */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + p->paintmode = RNA_enum_get(op->ptr, "mode"); + + /* if the original mode was *still* eraser, + * we'll let it say for now, since this gives + * users an opportunity to have visual feedback + * when adjusting eraser size + */ + if (p->paintmode != GP_PAINTMODE_ERASER) { + /* turn off cursor... + * NOTE: this should be enough for now + * Just hiding this makes it seem like + * you can paint again... + */ + gpencil_draw_toggle_eraser_cursor(C, p, false); + } + } + + /* we've just entered idling state, so this event was processed (but no others yet) */ + estate = OPERATOR_RUNNING_MODAL; + + /* stroke could be smoothed, send notifier to refresh screen */ + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + } + else { + /* printf("\t\tGP - end of stroke + op\n"); */ + p->status = GP_STATUS_DONE; + estate = OPERATOR_FINISHED; + } + } + else if (event->val == KM_PRESS) { + bool in_bounds = false; + + /* Check if we're outside the bounds of the active region + * NOTE: An exception here is that if launched from the toolbar, + * whatever region we're now in should become the new region + */ + if ((p->ar) && (p->ar->regiontype == RGN_TYPE_TOOLS)) { + /* Change to whatever region is now under the mouse */ + ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y); + + if (G.debug & G_DEBUG) { + printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n", + current_region, p->ar, event->x, event->y, + p->sa->totrct.xmin, p->sa->totrct.ymin, p->sa->totrct.xmax, p->sa->totrct.ymax); + } + + if (current_region) { + /* Assume that since we found the cursor in here, it is in bounds + * and that this should be the region that we begin drawing in + */ + p->ar = current_region; + in_bounds = true; + } + else { + /* Out of bounds, or invalid in some other way */ + p->status = GP_STATUS_ERROR; + estate = OPERATOR_CANCELLED; + + if (G.debug & G_DEBUG) + printf("%s: Region under cursor is out of bounds, so cannot be drawn on\n", __func__); + } + } + else if (p->ar) { + rcti region_rect; + + /* Perform bounds check using */ + ED_region_visible_rect(p->ar, ®ion_rect); + in_bounds = BLI_rcti_isect_pt_v(®ion_rect, event->mval); + } + else { + /* No region */ + p->status = GP_STATUS_ERROR; + estate = OPERATOR_CANCELLED; + + if (G.debug & G_DEBUG) + printf("%s: No active region found in GP Paint session data\n", __func__); + } + + if (in_bounds) { + /* Switch paintmode (temporarily if need be) based on which button was used + * NOTE: This is to make it more convenient to erase strokes when using drawing sessions + */ + if ((event->type == RIGHTMOUSE) || gpencil_is_tablet_eraser_active(event)) { + /* turn on eraser */ + p->paintmode = GP_PAINTMODE_ERASER; + } + else if (event->type == LEFTMOUSE) { + /* restore drawmode to default */ + p->paintmode = RNA_enum_get(op->ptr, "mode"); + } + + gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER); + + /* not painting, so start stroke (this should be mouse-button down) */ + p = gpencil_stroke_begin(C, op); + + if (p->status == GP_STATUS_ERROR) { + estate = OPERATOR_CANCELLED; + } + } + else if (p->status != GP_STATUS_ERROR) { + /* User clicked outside bounds of window while idling, so exit paintmode + * NOTE: Don't enter this case if an error occurred while finding the + * region (as above) + */ + p->status = GP_STATUS_DONE; + estate = OPERATOR_FINISHED; + } + } + else if (event->val == KM_RELEASE) { + p->status = GP_STATUS_IDLING; + op->flag |= OP_IS_MODAL_CURSOR_REGION; + } + } + + /* handle mode-specific events */ + if (p->status == GP_STATUS_PAINTING) { + /* handle painting mouse-movements? */ + if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { + /* handle drawing event */ + /* printf("\t\tGP - add point\n"); */ + gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); + + /* finish painting operation if anything went wrong just now */ + if (p->status == GP_STATUS_ERROR) { + printf("\t\t\t\tGP - add error done!\n"); + estate = OPERATOR_CANCELLED; + } + else { + /* event handled, so just tag as running modal */ + /* printf("\t\t\t\tGP - add point handled!\n"); */ + estate = OPERATOR_RUNNING_MODAL; + } + } + /* eraser size */ + else if ((p->paintmode == GP_PAINTMODE_ERASER) && + ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS)) + { + /* just resize the brush (local version) + * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys + */ + /* printf("\t\tGP - resize eraser\n"); */ + switch (event->type) { + case WHEELDOWNMOUSE: /* larger */ + case PADPLUSKEY: + p->radius += 5; + break; + + case WHEELUPMOUSE: /* smaller */ + case PADMINUS: + p->radius -= 5; + + if (p->radius <= 0) + p->radius = 1; + break; + } + + /* force refresh */ + ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */ + + /* event handled, so just tag as running modal */ + estate = OPERATOR_RUNNING_MODAL; + } + /* there shouldn't be any other events, but just in case there are, let's swallow them + * (i.e. to prevent problems with undo) + */ + else { + /* swallow event to save ourselves trouble */ + estate = OPERATOR_RUNNING_MODAL; + } + } + + /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */ + if (0 == gpencil_area_exists(C, p->sa)) + estate = OPERATOR_CANCELLED; + else { + /* update status indicators - cursor, header, etc. */ + gpencil_draw_status_indicators(C, p); + gpencil_draw_cursor_set(p); /* cursor may have changed outside our control - T44084 */ + } + + /* process last operations before exiting */ + switch (estate) { + case OPERATOR_FINISHED: + /* one last flush before we're done */ + gpencil_draw_exit(C, op); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + break; + + case OPERATOR_CANCELLED: + gpencil_draw_exit(C, op); + break; + + case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH: + /* event doesn't need to be handled */ +#if 0 + printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n", + event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE); +#endif + break; + } + + /* return status code */ + return estate; +} + +/* ------------------------------- */ + +static const EnumPropertyItem prop_gpencil_drawmodes[] = { + {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"}, + {GP_PAINTMODE_DRAW_STRAIGHT, "DRAW_STRAIGHT", 0, "Draw Straight Lines", "Draw straight line segment(s)"}, + {GP_PAINTMODE_DRAW_POLY, "DRAW_POLY", 0, "Draw Poly Line", "Click to place endpoints of straight line segments (connected)"}, + {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Annotation strokes"}, + {0, NULL, 0, NULL, NULL} +}; + +void GPENCIL_OT_annotate(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Annotation Draw"; + ot->idname = "GPENCIL_OT_annotate"; + ot->description = "Make annotations on the active data"; + + /* api callbacks */ + ot->exec = gpencil_draw_exec; + ot->invoke = gpencil_draw_invoke; + ot->modal = gpencil_draw_modal; + ot->cancel = gpencil_draw_cancel; + ot->poll = gpencil_draw_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* settings for drawing */ + ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements"); + + prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + /* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */ + prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 29b24886017..5c56877cbe6 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -46,6 +46,7 @@ #include "BLF_api.h" #include "BLT_translation.h" +#include "DNA_brush_types.h" #include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -55,8 +56,13 @@ #include "DNA_object_types.h" #include "BKE_context.h" +#include "BKE_brush.h" #include "BKE_global.h" +#include "BKE_paint.h" #include "BKE_gpencil.h" +#include "BKE_image.h" + +#include "DEG_depsgraph.h" #include "WM_api.h" @@ -74,6 +80,10 @@ #include "UI_interface_icons.h" #include "UI_resources.h" +#include "IMB_imbuf_types.h" + +#include "gpencil_intern.h" + /* ************************************************** */ /* GREASE PENCIL DRAWING */ @@ -88,8 +98,7 @@ typedef enum eDrawStrokeFlags { GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */ GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */ GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */ - GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */ - GP_DRAWDATA_HQ_FILL = (1 << 9) /* Use high quality fill */ + GP_DRAWDATA_FILL = (1 << 8) /* fill insides/bounded-regions of strokes */ } eDrawStrokeFlags; @@ -100,12 +109,12 @@ typedef enum eDrawStrokeFlags { #endif /* conversion utility (float --> normalized unsigned byte) */ -#define F2UB(x) (unsigned char)(255.0f * x) +#define F2UB(x) (uchar)(255.0f * x) /* ----- Tool Buffer Drawing ------ */ /* helper functions to set color of buffer point */ -static void gp_set_tpoint_varying_color(const tGPspoint *pt, const float ink[4], unsigned attrib_id) +static void gp_set_tpoint_varying_color(const tGPspoint *pt, const float ink[4], uint attrib_id) { float alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); @@ -119,7 +128,7 @@ static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4]) immUniformColor3fvAlpha(ink, alpha); } -static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], unsigned attrib_id) +static void gp_set_point_varying_color(const bGPDspoint *pt, const float ink[4], uint attrib_id) { float alpha = ink[3] * pt->strength; CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f); @@ -134,7 +143,7 @@ static void gp_draw_stroke_buffer_fill(const tGPspoint *points, int totpoints, f } int tot_triangles = totpoints - 2; /* allocate memory for temporary areas */ - unsigned int(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, "GP Stroke buffer temp triangulation"); + uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, "GP Stroke buffer temp triangulation"); float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, "GP Stroke buffer temp 2d points"); /* Convert points to array and triangulate @@ -146,7 +155,7 @@ static void gp_draw_stroke_buffer_fill(const tGPspoint *points, int totpoints, f points2d[i][0] = pt->x; points2d[i][1] = pt->y; } - BLI_polyfill_calc((const float(*)[2])points2d, (unsigned int)totpoints, 0, (unsigned int(*)[3])tmp_triangles); + BLI_polyfill_calc((const float(*)[2])points2d, (uint)totpoints, 0, (uint(*)[3])tmp_triangles); /* draw triangulation data */ if (tot_triangles > 0) { @@ -253,7 +262,7 @@ static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short if (i != 0) { gp_set_tpoint_varying_color(pt - 1, ink, color); immVertex2iv(pos, &(pt - 1)->x); - ++draw_points; + draw_points++; } oldpressure = pt->pressure; /* reset our threshold */ @@ -262,7 +271,7 @@ static void gp_draw_stroke_buffer(const tGPspoint *points, int totpoints, short /* now the point we want */ gp_set_tpoint_varying_color(pt, ink, color); immVertex2iv(pos, &pt->x); - ++draw_points; + draw_points++; } /* need to have 2 points to avoid immEnd assert error */ if (draw_points < 2) { @@ -402,6 +411,50 @@ static void gp_draw_stroke_volumetric_3d( /* --------------- Stroke Fills ----------------- */ +/* calc bounding box in 2d using flat projection data */ +static void gp_calc_2d_bounding_box(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], bool expand) +{ + copy_v2_v2(minv, points2d[0]); + copy_v2_v2(maxv, points2d[0]); + + for (int i = 1; i < totpoints; i++) { + /* min */ + if (points2d[i][0] < minv[0]) { + minv[0] = points2d[i][0]; + } + if (points2d[i][1] < minv[1]) { + minv[1] = points2d[i][1]; + } + /* max */ + if (points2d[i][0] > maxv[0]) { + maxv[0] = points2d[i][0]; + } + if (points2d[i][1] > maxv[1]) { + maxv[1] = points2d[i][1]; + } + } + /* If not expanded, use a perfect square */ + if (expand == false) { + if (maxv[0] > maxv[1]) { + maxv[1] = maxv[0]; + } + else { + maxv[0] = maxv[1]; + } + } +} + +/* calc texture coordinates using flat projected points */ +static void gp_calc_stroke_text_coordinates(const float(*points2d)[2], int totpoints, float minv[2], float maxv[2], float(*r_uv)[2]) +{ + float d[2]; + d[0] = maxv[0] - minv[0]; + d[1] = maxv[1] - minv[1]; + for (int i = 0; i < totpoints; i++) { + r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0]; + r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1]; + } +} /* Get points of stroke always flat to view not affected by camera view or view position */ static void gp_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*points2d)[2], int *r_direction) @@ -447,7 +500,6 @@ static void gp_stroke_2d_flat(const bGPDspoint *points, int totpoints, float(*po *r_direction = (int)locy[2]; } - /* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */ static void gp_triangulate_stroke_fill(bGPDstroke *gps) { @@ -455,14 +507,23 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) /* allocate memory for temporary areas */ gps->tot_triangles = gps->totpoints - 2; - unsigned int (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); + uint (*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); float (*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points"); + float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data"); int direction = 0; /* convert to 2d and triangulate */ gp_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); - BLI_polyfill_calc(points2d, (unsigned int)gps->totpoints, direction, tmp_triangles); + BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles); + + /* calc texture coordinates automatically */ + float minv[2]; + float maxv[2]; + /* first needs bounding box data */ + gp_calc_2d_bounding_box((const float(*)[2])points2d, gps->totpoints, minv, maxv, false); + /* calc uv data */ + gp_calc_stroke_text_coordinates((const float(*)[2])points2d, gps->totpoints, minv, maxv, uv); /* Number of triangles */ gps->tot_triangles = gps->totpoints - 2; @@ -476,7 +537,12 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) } for (int i = 0; i < gps->tot_triangles; i++) { - memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); + bGPDtriangle *stroke_triangle = &gps->triangles[i]; + memcpy(stroke_triangle->verts, tmp_triangles[i], sizeof(uint[3])); + /* copy texture coordinates */ + copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]); + copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]); + copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]); } } else { @@ -493,73 +559,128 @@ static void gp_triangulate_stroke_fill(bGPDstroke *gps) } /* clear memory */ - if (tmp_triangles) MEM_freeN(tmp_triangles); - if (points2d) MEM_freeN(points2d); + MEM_SAFE_FREE(tmp_triangles); + MEM_SAFE_FREE(points2d); + MEM_SAFE_FREE(uv); } - -/* draw fills for shapes */ -static void gp_draw_stroke_fill( - bGPdata *gpd, bGPDstroke *gps, - int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4]) +/* add a new fill point and texture coordinates to vertex buffer */ +static void gp_add_filldata_tobuffer( + const bGPDspoint *pt, const float uv[2], uint pos, uint texcoord, short flag, + int offsx, int offsy, int winx, int winy, const float diff_mat[4][4]) { float fpt[3]; + float co[2]; - BLI_assert(gps->totpoints >= 3); + mul_v3_m4v3(fpt, diff_mat, &pt->x); + /* if 2d, need conversion */ + if (!flag & GP_STROKE_3DSPACE) { + gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co); + copy_v2_v2(fpt, co); + fpt[2] = 0.0f; /* 2d always is z=0.0f */ + } - bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); + immAttrib2f(texcoord, uv[0], uv[1]); /* texture coordinates */ + immVertex3fv(pos, fpt); /* position */ +} - /* Triangulation fill if high quality flag is enabled */ - if (palcolor->flag & PC_COLOR_HQ_FILL) { - /* Calculate triangles cache for filling area (must be done only after changes) */ - if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { - gp_triangulate_stroke_fill(gps); - } - BLI_assert(gps->tot_triangles >= 1); +#if 0 /* GPXX disabled, not used in annotations */ +/* assign image texture for filling stroke */ +static int gp_set_filling_texture(Image *image, short flag) +{ + ImBuf *ibuf; + uint *bind = &image->bindcode[TEXTARGET_TEXTURE_2D]; + int error = GL_NO_ERROR; + ImageUser iuser = { NULL }; + void *lock; - uint pos; - if (gps->flag & GP_STROKE_3DSPACE) { - pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - } - else { - pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - } + iuser.ok = true; - immUniformColor4fv(color); + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); - /* Draw all triangles for filling the polygon (cache must be calculated before) */ - immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3); - /* TODO: use batch instead of immediate mode, to share vertices */ + if (ibuf == NULL || ibuf->rect == NULL) { + BKE_image_release_ibuf(image, ibuf, NULL); + return (int)GL_INVALID_OPERATION; + } - bGPDtriangle *stroke_triangle = gps->triangles; - bGPDspoint *pt; + GPU_create_gl_tex(bind, ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, GL_TEXTURE_2D, + false, false, image); - if (gps->flag & GP_STROKE_3DSPACE) { - for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { - for (int j = 0; j < 3; j++) { - pt = &gps->points[stroke_triangle->verts[j]]; - mul_v3_m4v3(fpt, diff_mat, &pt->x); - immVertex3fv(pos, fpt); - } - } - } - else { - for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { - for (int j = 0; j < 3; j++) { - float co[2]; - pt = &gps->points[stroke_triangle->verts[j]]; - mul_v3_m4v3(fpt, diff_mat, &pt->x); - gp_calc_2d_stroke_fxy(fpt, gps->flag, offsx, offsy, winx, winy, co); - immVertex3fv(pos, fpt); - } - } - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (flag & GP_STYLE_COLOR_TEX_CLAMP) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + BKE_image_release_ibuf(image, ibuf, NULL); - immEnd(); - immUnbindProgram(); + return error; +} +#endif + +/* draw fills for shapes */ +static void gp_draw_stroke_fill( + bGPdata *gpd, bGPDstroke *gps, + int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float color[4]) +{ + BLI_assert(gps->totpoints >= 3); + Material *ma = gpd->mat[gps->mat_nr]; + MaterialGPencilStyle *gp_style = ma->gp_style; + + /* Calculate triangles cache for filling area (must be done only after changes) */ + if ((gps->flag & GP_STROKE_RECALC_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { + gp_triangulate_stroke_fill(gps); + } + BLI_assert(gps->tot_triangles >= 1); + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_GPENCIL_FILL); + + immUniformColor4fv(color); + immUniform4fv("color2", gp_style->mix_rgba); + immUniform1i("fill_type", gp_style->fill_style); + immUniform1f("mix_factor", gp_style->mix_factor); + + immUniform1f("gradient_angle", gp_style->gradient_angle); + immUniform1f("gradient_radius", gp_style->gradient_radius); + immUniform1f("pattern_gridsize", gp_style->pattern_gridsize); + immUniform2fv("gradient_scale", gp_style->gradient_scale); + immUniform2fv("gradient_shift", gp_style->gradient_shift); + + immUniform1f("texture_angle", gp_style->texture_angle); + immUniform2fv("texture_scale", gp_style->texture_scale); + immUniform2fv("texture_offset", gp_style->texture_offset); + immUniform1f("texture_opacity", gp_style->texture_opacity); + immUniform1i("t_mix", gp_style->flag & GP_STYLE_COLOR_TEX_MIX ? 1 : 0); + immUniform1i("t_flip", gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 0); +#if 0 /* GPXX disabled, not used in annotations */ + /* image texture */ + if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_TEXTURE) || (gp_style->flag & GP_STYLE_COLOR_TEX_MIX)) { + gp_set_filling_texture(gp_style->ima, gp_style->flag); } +#endif + /* Draw all triangles for filling the polygon (cache must be calculated before) */ + immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3); + /* TODO: use batch instead of immediate mode, to share vertices */ + + const bGPDtriangle *stroke_triangle = gps->triangles; + for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { + for (int j = 0; j < 3; j++) { + gp_add_filldata_tobuffer( + &gps->points[stroke_triangle->verts[j]], stroke_triangle->uv[j], + pos, texcoord, gps->flag, + offsx, offsy, winx, winy, diff_mat); + } + } + + immEnd(); + immUnbindProgram(); } /* ----- Existing Strokes Drawing (3D and Point) ------ */ @@ -601,87 +722,81 @@ static void gp_draw_stroke_point( immUnbindProgram(); } -/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */ -static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thickness, bool UNUSED(debug), - short UNUSED(sflag), const float diff_mat[4][4], const float ink[4], bool cyclic) +/* draw a given stroke in 3d (i.e. in 3d-space) */ +static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic) { + bGPDspoint *points = tgpw->gps->points; + int totpoints = tgpw->gps->totpoints; + + const float viewport[2] = { (float)tgpw->winx, (float)tgpw->winy }; float curpressure = points[0].pressure; float fpt[3]; - float cyclic_fpt[3]; - int draw_points = 0; - - /* if cyclic needs one vertex more */ - int cyclic_add = 0; - if (cyclic) { - ++cyclic_add; - } + /* if cyclic needs more vertex */ + int cyclic_add = (cyclic) ? 1 : 0; GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + uint thickattrib = GPU_vertformat_attr_add(format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_SMOOTH_COLOR); + immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE); + immUniform2fv("Viewport", viewport); + immUniform1f("pixsize", tgpw->rv3d->pixsize); + immUniform1f("pixelsize", U.pixelsize); + float obj_scale = (tgpw->ob->size[0] + tgpw->ob->size[1] + tgpw->ob->size[2]) / 3.0f; - /* TODO: implement this with a geometry shader to draw one continuous tapered stroke */ + immUniform1f("objscale", obj_scale); + int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS)); + immUniform1i("keep_size", keep_size); + immUniform1i("pixfactor", tgpw->gpd->pixfactor); + immUniform1i("xraymode", tgpw->gpd->xray_mode); /* draw stroke curve */ GPU_line_width(max_ff(curpressure * thickness, 1.0f)); - immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add); + immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2); const bGPDspoint *pt = points; - for (int i = 0; i < totpoints; i++, pt++) { - gp_set_point_varying_color(pt, ink, color); - /* if there was a significant pressure change, stop the curve, change the thickness of the stroke, - * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP) - * Note: we want more visible levels of pressures when thickness is bigger. - */ - if (fabsf(pt->pressure - curpressure) > 0.2f / (float)thickness) { - /* if the pressure changes before get at least 2 vertices, need to repeat last point to avoid assert in immEnd() */ - if (draw_points < 2) { - const bGPDspoint *pt2 = pt - 1; - mul_v3_m4v3(fpt, diff_mat, &pt2->x); - immVertex3fv(pos, fpt); + for (int i = 0; i < totpoints; i++, pt++) { + /* first point for adjacency (not drawn) */ + if (i == 0) { + gp_set_point_varying_color(points, ink, color); + immAttrib1f(thickattrib, max_ff(curpressure * thickness, 1.0f)); + if ((cyclic) && (totpoints > 2)) { + mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x); } - immEnd(); - draw_points = 0; - - curpressure = pt->pressure; - GPU_line_width(max_ff(curpressure * thickness, 1.0f)); - immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1 + cyclic_add); - - /* need to roll-back one point to ensure that there are no gaps in the stroke */ - if (i != 0) { - const bGPDspoint *pt2 = pt - 1; - mul_v3_m4v3(fpt, diff_mat, &pt2->x); - gp_set_point_varying_color(pt2, ink, color); - immVertex3fv(pos, fpt); - ++draw_points; + else { + mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x); } + mul_v3_fl(fpt, -1.0f); + immVertex3fv(pos, fpt); } - - /* now the point we want */ - mul_v3_m4v3(fpt, diff_mat, &pt->x); + /* set point */ + gp_set_point_varying_color(pt, ink, color); + immAttrib1f(thickattrib, max_ff(curpressure * thickness, 1.0f)); + mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x); immVertex3fv(pos, fpt); - ++draw_points; - if (cyclic && i == 0) { - /* save first point to use in cyclic */ - copy_v3_v3(cyclic_fpt, fpt); - } + curpressure = pt->pressure; } - if (cyclic) { + if (cyclic && totpoints > 2) { /* draw line to first point to complete the cycle */ - immVertex3fv(pos, cyclic_fpt); - ++draw_points; - } + immAttrib1f(thickattrib, max_ff(points->pressure * thickness, 1.0f)); + mul_v3_m4v3(fpt, tgpw->diff_mat, &points->x); + immVertex3fv(pos, fpt); - /* if less of two points, need to repeat last point to avoid assert in immEnd() */ - if (draw_points < 2) { - const bGPDspoint *pt2 = pt - 1; - mul_v3_m4v3(fpt, diff_mat, &pt2->x); - gp_set_point_varying_color(pt2, ink, color); + /* now add adjacency point (not drawn) */ + immAttrib1f(thickattrib, max_ff((points + 1)->pressure * thickness, 1.0f)); + mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x); + immVertex3fv(pos, fpt); + } + /* last adjacency point (not drawn) */ + else { + gp_set_point_varying_color(points + totpoints - 1, ink, color); + immAttrib1f(thickattrib, max_ff(curpressure * thickness, 1.0f)); + mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 2)->x); + mul_v3_fl(fpt, -1.0f); immVertex3fv(pos, fpt); } @@ -692,8 +807,9 @@ static void gp_draw_stroke_3d(const bGPDspoint *points, int totpoints, short thi /* ----- Fancy 2D-Stroke Drawing ------ */ /* draw a given stroke in 2d */ -static void gp_draw_stroke_2d(const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, - bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4]) +static void gp_draw_stroke_2d( + const bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag, + bool UNUSED(debug), int offsx, int offsy, int winx, int winy, const float diff_mat[4][4], const float ink[4]) { /* otherwise thickness is twice that of the 3D view */ float thickness = (float)thickness_s * 0.5f; @@ -900,10 +1016,7 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag) } /* draw a set of strokes */ -static void gp_draw_strokes( - bGPdata *gpd, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag, - bool debug, short lthick, const float opacity, const float tintcolor[4], - const bool onion, const bool custonion, const float diff_mat[4][4]) +static void gp_draw_strokes(tGPDdraw *tgpw) { float tcolor[4]; float tfill[4]; @@ -912,31 +1025,41 @@ static void gp_draw_strokes( GPU_enable_program_point_size(); - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + for (bGPDstroke *gps = tgpw->t_gpf->strokes.first; gps; gps = gps->next) { /* check if stroke can be drawn */ - if (gp_can_draw_stroke(gps, dflag) == false) { + if (gp_can_draw_stroke(gps, tgpw->dflag) == false) { continue; } /* check if the color is visible */ - bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); - if ((palcolor == NULL) || - (palcolor->flag & PC_COLOR_HIDE) || + Material *ma = tgpw->gpd->mat[gps->mat_nr]; + MaterialGPencilStyle *gp_style = ma->gp_style; + + if ((gp_style == NULL) || + (gp_style->flag & GP_STYLE_COLOR_HIDE) || /* if onion and ghost flag do not draw*/ - (onion && (palcolor->flag & PC_COLOR_ONIONSKIN))) + (tgpw->onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) { continue; } + /* if disable fill, the colors with fill must be omitted too except fill boundary strokes */ + if ((tgpw->disable_fill == 1) && + (gp_style->fill_rgba[3] > 0.0f) && + ((gps->flag & GP_STROKE_NOFILL) == 0)) + { + continue; + } + /* calculate thickness */ - sthickness = gps->thickness + lthick; + sthickness = gps->thickness + tgpw->lthick; if (sthickness <= 0) { continue; } /* check which stroke-drawer to use */ - if (dflag & GP_DRAWDATA_ONLY3D) { - const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY); + if (tgpw->dflag & GP_DRAWDATA_ONLY3D) { + const int no_xray = (tgpw->dflag & GP_DRAWDATA_NO_XRAY); int mask_orig = 0; if (no_xray) { @@ -951,57 +1074,64 @@ static void gp_draw_strokes( /* 3D Fill */ //if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) { - if (gps->totpoints >= 3) { - /* set color using palette, tint color and opacity */ - interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]); - tfill[3] = palcolor->fill[3] * opacity; - if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + if ((gps->totpoints >= 3) && (tgpw->disable_fill != 1)) { + /* set color using material, tint color and opacity */ + interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]); + tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity; + if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) { const float *color; - if (!onion) { + if (!tgpw->onion) { color = tfill; } else { - if (custonion) { - color = tintcolor; + if (tgpw->custonion) { + color = tgpw->tintcolor; } else { - ARRAY_SET_ITEMS(tfill, UNPACK3(palcolor->fill), tintcolor[3]); + ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]); color = tfill; } } - gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color); + gp_draw_stroke_fill( + tgpw->gpd, gps, + tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color); } } /* 3D Stroke */ - /* set color using palette, tint color and opacity */ - if (!onion) { - interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]); - tcolor[3] = palcolor->color[3] * opacity; + /* set color using material tint color and opacity */ + if (!tgpw->onion) { + interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]); + tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity; copy_v4_v4(ink, tcolor); } else { - if (custonion) { - copy_v4_v4(ink, tintcolor); + if (tgpw->custonion) { + copy_v4_v4(ink, tgpw->tintcolor); } else { - ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity); + ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity); copy_v4_v4(ink, tcolor); } } - if (palcolor->flag & PC_COLOR_VOLUMETRIC) { + if (gp_style->mode == GP_STYLE_MODE_DOTS) { /* volumetric stroke drawing */ - gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink); + if (tgpw->disable_fill != 1) { + gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink); + } } else { /* 3D Lines - OpenGL primitives-based */ if (gps->totpoints == 1) { - gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy, - diff_mat, ink); + if (tgpw->disable_fill != 1) { + gp_draw_stroke_point(gps->points, sthickness, tgpw->dflag, gps->flag, + tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, + tgpw->diff_mat, ink); + } } else { - gp_draw_stroke_3d(gps->points, gps->totpoints, sthickness, debug, gps->flag, - diff_mat, ink, gps->flag & GP_STROKE_CYCLIC); + tgpw->gps = gps; + gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC); } } if (no_xray) { @@ -1014,58 +1144,63 @@ static void gp_draw_strokes( else { /* 2D - Fill */ if (gps->totpoints >= 3) { - /* set color using palette, tint color and opacity */ - interp_v3_v3v3(tfill, palcolor->fill, tintcolor, tintcolor[3]); - tfill[3] = palcolor->fill[3] * opacity; - if (tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) { + /* set color using material, tint color and opacity */ + interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]); + tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity; + if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) { const float *color; - if (!onion) { + if (!tgpw->onion) { color = tfill; } else { - if (custonion) { - color = tintcolor; + if (tgpw->custonion) { + color = tgpw->tintcolor; } else { - ARRAY_SET_ITEMS(tfill, palcolor->fill[0], palcolor->fill[1], palcolor->fill[2], - tintcolor[3]); + ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]); color = tfill; } } - gp_draw_stroke_fill(gpd, gps, offsx, offsy, winx, winy, diff_mat, color); + gp_draw_stroke_fill( + tgpw->gpd, gps, + tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, color); } } /* 2D Strokes... */ - /* set color using palette, tint color and opacity */ - if (!onion) { - interp_v3_v3v3(tcolor, palcolor->color, tintcolor, tintcolor[3]); - tcolor[3] = palcolor->color[3] * opacity; + /* set color using material, tint color and opacity */ + if (!tgpw->onion) { + interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]); + tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity; copy_v4_v4(ink, tcolor); } else { - if (custonion) { - copy_v4_v4(ink, tintcolor); + if (tgpw->custonion) { + copy_v4_v4(ink, tgpw->tintcolor); } else { - ARRAY_SET_ITEMS(tcolor, palcolor->color[0], palcolor->color[1], palcolor->color[2], opacity); + ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity); copy_v4_v4(ink, tcolor); } } - if (palcolor->flag & PC_COLOR_VOLUMETRIC) { + if (gp_style->mode == GP_STYLE_MODE_DOTS) { /* blob/disk-based "volumetric" drawing */ - gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, - offsx, offsy, winx, winy, diff_mat, ink); + gp_draw_stroke_volumetric_2d( + gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag, + tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink); } else { /* normal 2D strokes */ if (gps->totpoints == 1) { - gp_draw_stroke_point(gps->points, sthickness, dflag, gps->flag, offsx, offsy, winx, winy, - diff_mat, ink); + gp_draw_stroke_point( + gps->points, sthickness, tgpw->dflag, gps->flag, + tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, + tgpw->diff_mat, ink); } else { - gp_draw_stroke_2d(gps->points, gps->totpoints, sthickness, dflag, gps->flag, debug, - offsx, offsy, winx, winy, diff_mat, ink); + gp_draw_stroke_2d( + gps->points, gps->totpoints, sthickness, tgpw->dflag, gps->flag, false, + tgpw->offsx, tgpw->offsy, tgpw->winx, tgpw->winy, tgpw->diff_mat, ink); } } } @@ -1114,14 +1249,16 @@ static void gp_draw_strokes_edit( if ((gps->flag & GP_STROKE_SELECT) == 0) continue; - /* verify palette color lock */ + /* verify color lock */ { - bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); - if (palcolor != NULL) { - if (palcolor->flag & PC_COLOR_HIDE) { + Material *ma = gpd->mat[gps->mat_nr]; + MaterialGPencilStyle *gp_style = ma->gp_style; + + if (gp_style != NULL) { + if (gp_style->flag & GP_STYLE_COLOR_HIDE) { continue; } - if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) { + if (((lflag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED)) { continue; } } @@ -1143,8 +1280,9 @@ static void gp_draw_strokes_edit( } /* for now, we assume that the base color of the points is not too close to the real color */ - /* set color using palette */ - bGPDpalettecolor *palcolor = ED_gpencil_stroke_getcolor(gpd, gps); + /* set color using material */ + Material *ma = gpd->mat[gps->mat_nr]; + MaterialGPencilStyle *gp_style = ma->gp_style; float selectColor[4]; UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); @@ -1153,7 +1291,7 @@ static void gp_draw_strokes_edit( GPUVertFormat *format = immVertexFormat(); uint pos; /* specified later */ uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT); if (gps->flag & GP_STROKE_3DSPACE) { pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); @@ -1189,7 +1327,7 @@ static void gp_draw_strokes_edit( immAttrib1f(size, vsize); } else { - immAttrib3fv(color, palcolor->color); + immAttrib3fv(color, gp_style->stroke_rgba); immAttrib1f(size, bsize); } @@ -1229,98 +1367,75 @@ static void gp_draw_strokes_edit( /* ----- General Drawing ------ */ -/* draw onion-skinning for a layer */ -static void gp_draw_onionskins( - bGPdata *gpd, const bGPDlayer *gpl, const bGPDframe *gpf, int offsx, int offsy, int winx, int winy, - int UNUSED(cfra), int dflag, bool debug, const float diff_mat[4][4]) + +/* draw interpolate strokes (used only while operator is running) */ +void ED_gp_draw_interpolation(const bContext *C, tGPDinterpolate *tgpi, const int type) { - const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)}; - const float alpha = 1.0f; + tGPDdraw tgpw; + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + tGPDinterpolate_layer *tgpil; + Object *obact = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + float color[4]; - /* 1) Draw Previous Frames First */ - if (gpl->flag & GP_LAYER_GHOST_PREVCOL) { - copy_v3_v3(color, gpl->gcolor_prev); - } - else { - copy_v3_v3(color, default_color); + UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color); + color[3] = 0.6f; + int dflag = 0; + /* if 3d stuff, enable flags */ + if (type == REGION_DRAW_POST_VIEW) { + dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); } - if (gpl->gstep > 0) { - /* draw previous frames first */ - for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) { - /* check if frame is drawable */ - if ((gpf->framenum - gf->framenum) <= gpl->gstep) { - /* alpha decreases with distance from curframe index */ - float fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1)); - color[3] = alpha * fac * 0.66f; - gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, - true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat); - } - else - break; - } - } - else if (gpl->gstep == 0) { - /* draw the strokes for the ghost frames (at half of the alpha set by user) */ - if (gpf->prev) { - color[3] = (alpha / 7); - gp_draw_strokes(gpd, gpf->prev, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, - true, gpl->flag & GP_LAYER_GHOST_PREVCOL, diff_mat); - } - } - else { - /* don't draw - disabled */ - } + tgpw.rv3d = rv3d; + tgpw.depsgraph = depsgraph; + tgpw.ob = obact; + tgpw.gpd = tgpi->gpd; + tgpw.offsx = 0; + tgpw.offsy = 0; + tgpw.winx = tgpi->ar->winx; + tgpw.winy = tgpi->ar->winy; + tgpw.dflag = dflag; - /* 2) Now draw next frames */ - if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) { - copy_v3_v3(color, gpl->gcolor_next); - } - else { - copy_v3_v3(color, default_color); - } + /* turn on alpha-blending */ + glEnable(GL_BLEND); + for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { + /* calculate parent position */ + ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpil->gpl, tgpw.diff_mat); + if (tgpil->interFrame) { + tgpw.gpl = tgpil->gpl; + tgpw.gpf = tgpil->interFrame; + tgpw.t_gpf = tgpil->interFrame; - if (gpl->gstep_next > 0) { - /* now draw next frames */ - for (bGPDframe *gf = gpf->next; gf; gf = gf->next) { - /* check if frame is drawable */ - if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) { - /* alpha decreases with distance from curframe index */ - float fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1)); - color[3] = alpha * fac * 0.66f; - gp_draw_strokes(gpd, gf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, - true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat); - } - else - break; - } - } - else if (gpl->gstep_next == 0) { - /* draw the strokes for the ghost frames (at half of the alpha set by user) */ - if (gpf->next) { - color[3] = (alpha / 4); - gp_draw_strokes(gpd, gpf->next, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, 1.0f, color, - true, gpl->flag & GP_LAYER_GHOST_NEXTCOL, diff_mat); + tgpw.lthick = tgpil->gpl->line_change; + tgpw.opacity = 1.0; + copy_v4_v4(tgpw.tintcolor, color); + tgpw.onion = true; + tgpw.custonion = true; + + gp_draw_strokes(&tgpw); } } - else { - /* don't draw - disabled */ - } + glDisable(GL_BLEND); } /* draw interpolate strokes (used only while operator is running) */ -void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type) +void ED_gp_draw_primitives(const bContext *C, tGPDprimitive *tgpi, const int type) { - tGPDinterpolate_layer *tgpil; - float diff_mat[4][4]; - float color[4]; + tGPDdraw tgpw; + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + + /* if idle, do not draw */ + if (tgpi->flag == 0) { + return; + } - int offsx = 0; - int offsy = 0; - int winx = tgpi->ar->winx; - int winy = tgpi->ar->winy; + Object *obact = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ + float color[4]; UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color); color[3] = 0.6f; int dflag = 0; @@ -1329,32 +1444,71 @@ void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type) dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); } + tgpw.rv3d = rv3d; + tgpw.depsgraph = depsgraph; + tgpw.ob = obact; + tgpw.gpd = tgpi->gpd; + tgpw.offsx = 0; + tgpw.offsy = 0; + tgpw.winx = tgpi->ar->winx; + tgpw.winy = tgpi->ar->winy; + tgpw.dflag = dflag; + /* turn on alpha-blending */ GPU_blend(true); - for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - /* calculate parent position */ - ED_gpencil_parent_location(tgpil->gpl, diff_mat); - if (tgpil->interFrame) { - gp_draw_strokes(tgpi->gpd, tgpil->interFrame, offsx, offsy, winx, winy, dflag, false, - tgpil->gpl->thickness, 1.0f, color, true, true, diff_mat); + /* calculate parent position */ + ED_gpencil_parent_location(depsgraph, obact, tgpi->gpd, tgpi->gpl, tgpw.diff_mat); + if (tgpi->gpf) { + tgpw.gps = tgpi->gpf->strokes.first; + if (tgpw.gps->totpoints > 0) { + tgpw.gpl = tgpi->gpl; + tgpw.gpf = tgpi->gpf; + tgpw.t_gpf = tgpi->gpf; + + tgpw.lthick = tgpi->gpl->line_change; + tgpw.opacity = 1.0; + copy_v4_v4(tgpw.tintcolor, color); + tgpw.onion = true; + tgpw.custonion = true; + + gp_draw_strokes(&tgpw); } } GPU_blend(false); } +/* wrapper to draw strokes for filling operator */ +void ED_gp_draw_fill(tGPDdraw *tgpw) +{ + gp_draw_strokes(tgpw); +} + /* loop over gpencil data layers, drawing them */ -static void gp_draw_data_layers( - const bGPDbrush *brush, float alpha, bGPdata *gpd, +static void gp_draw_data_layers(RegionView3D *rv3d, + const Brush *brush, float alpha, Object *ob, bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { float diff_mat[4][4]; + tGPDdraw tgpw; + + tgpw.rv3d = rv3d; + tgpw.depsgraph = NULL; /* XXX: This is not used here */ + tgpw.ob = ob; + tgpw.gpd = gpd; + tgpw.gpl = NULL; + tgpw.gpf = NULL; + tgpw.t_gpf = NULL; + tgpw.offsx = offsx; + tgpw.offsy = offsy; + tgpw.winx = winx; + tgpw.winy = winy; + tgpw.dflag = dflag; for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* calculate parent position */ - ED_gpencil_parent_location(gpl, diff_mat); + ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, diff_mat); - bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG); - short lthick = brush->thickness + gpl->thickness; + short lthick = brush->size + gpl->line_change; /* don't draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) @@ -1383,30 +1537,20 @@ static void gp_draw_data_layers( /* volumetric strokes... */ GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_VOLUMETRIC), GP_DRAWDATA_VOLUMETRIC); - /* HQ fills... */ - GP_DRAWFLAG_APPLY((gpl->flag & GP_LAYER_HQ_FILL), GP_DRAWDATA_HQ_FILL); - #undef GP_DRAWFLAG_APPLY - /* Draw 'onionskins' (frame left + right) - * - It is only possible to show these if the option is enabled - * - The "no onions" flag prevents ghosts from appearing during animation playback/scrubbing - * and in renders - * - The per-layer "always show" flag however overrides the playback/render restriction, - * allowing artists to selectively turn onionskins on/off during playback - */ - if ((gpl->flag & GP_LAYER_ONIONSKIN) && - ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS))) - { - /* Drawing method - only immediately surrounding (gstep = 0), - * or within a frame range on either side (gstep > 0) - */ - gp_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, diff_mat); - } + tgpw.gpl = gpl; + tgpw.gpf = gpf; + tgpw.t_gpf = gpf; // XXX? + tgpw.lthick = gpl->line_change; + tgpw.opacity = gpl->opacity; + copy_v4_v4(tgpw.tintcolor, gpl->tintcolor); + tgpw.onion = false; + tgpw.custonion = false; + copy_m4_m4(tgpw.diff_mat, diff_mat); /* draw the strokes already in active frame */ - gp_draw_strokes(gpd, gpf, offsx, offsy, winx, winy, dflag, debug, gpl->thickness, - gpl->opacity, gpl->tintcolor, false, false, diff_mat); + gp_draw_strokes(&tgpw); /* Draw verts of selected strokes * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering @@ -1435,19 +1579,25 @@ static void gp_draw_data_layers( * It should also be noted that sbuffer contains temporary point types * i.e. tGPspoints NOT bGPDspoints */ - if (gpd->sflag & PC_COLOR_VOLUMETRIC) { - gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, - dflag, gpd->scolor); + if (gpd->runtime.mode == GP_STYLE_MODE_DOTS) { + gp_draw_stroke_volumetric_buffer( + gpd->runtime.sbuffer, + gpd->runtime.sbuffer_size, lthick, + dflag, gpd->runtime.scolor); } else { - gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag, gpd->scolor, gpd->sfill); + gp_draw_stroke_buffer( + gpd->runtime.sbuffer, + gpd->runtime.sbuffer_size, lthick, + dflag, gpd->runtime.sbuffer_sflag, + gpd->runtime.scolor, gpd->runtime.sfill); } } } } /* draw a short status message in the top-right corner */ -static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar) +static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *ar) { rcti rect; @@ -1493,8 +1643,8 @@ static void gp_draw_status_text(const bGPdata *gpd, ARegion *ar) } /* draw grease-pencil datablock */ -static void gp_draw_data( - const bGPDbrush *brush, float alpha, bGPdata *gpd, +static void gp_draw_data(RegionView3D *rv3d, + const Brush *brush, float alpha, Object *ob, bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { /* turn on smooth lines (i.e. anti-aliasing) */ @@ -1510,7 +1660,7 @@ static void gp_draw_data( GPU_blend(true); /* draw! */ - gp_draw_data_layers(brush, alpha, gpd, offsx, offsy, winx, winy, cfra, dflag); + gp_draw_data_layers(rv3d, brush, alpha, ob, gpd, offsx, offsy, winx, winy, cfra, dflag); /* turn off alpha blending, then smooth lines */ GPU_blend(false); // alpha blending @@ -1519,33 +1669,22 @@ static void gp_draw_data( /* if we have strokes for scenes (3d view)/clips (movie clip editor) * and objects/tracks, multiple data blocks have to be drawn */ -static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy, - int cfra, int dflag, const char spacetype) +static void gp_draw_data_all( + RegionView3D *rv3d, Scene *scene, bGPdata *gpd, int offsx, int offsy, int winx, int winy, + int cfra, int dflag, const char UNUSED(spacetype)) { bGPdata *gpd_source = NULL; - ToolSettings *ts; - bGPDbrush *brush = NULL; + ToolSettings *ts = NULL; + Brush *brush = NULL; if (scene) { ts = scene->toolsettings; - brush = BKE_gpencil_brush_getactive(ts); - /* if no brushes, create default set */ - if (brush == NULL) { - BKE_gpencil_brush_init_presets(ts); - brush = BKE_gpencil_brush_getactive(ts); - } - - if (spacetype == SPACE_VIEW3D) { - gpd_source = (scene->gpd ? scene->gpd : NULL); - } - else if (spacetype == SPACE_CLIP && scene->clip) { - /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */ - gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL); - } + brush = BKE_brush_getactive_gpencil(ts); if (gpd_source) { if (brush != NULL) { - gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source, - offsx, offsy, winx, winy, cfra, dflag); + gp_draw_data( + rv3d, brush, 1.0f, NULL, gpd_source, + offsx, offsy, winx, winy, cfra, dflag); } } } @@ -1554,76 +1693,70 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i * if gpd_source == gpd, we don't have any object/track data and we can skip */ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { if (brush != NULL) { - gp_draw_data(brush, ts->gp_sculpt.alpha, gpd, - offsx, offsy, winx, winy, cfra, dflag); + gp_draw_data( + rv3d, brush, 1.0f, NULL, gpd, + offsx, offsy, winx, winy, cfra, dflag); } } } /* ----- Grease Pencil Sketches Drawing API ------ */ -/* ............................ - * XXX - * We need to review the calls below, since they may be/are not that suitable for - * the new ways that we intend to be drawing data... - * ............................ */ -/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */ -void ED_gpencil_draw_2dimage(const bContext *C) +/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly + * Note: this gets called twice - first time with only3d=true to draw 3d-strokes, + * second time with only3d=false for screen-aligned strokes */ +void ED_gpencil_draw_view3d( + wmWindowManager *wm, + Scene *scene, + ViewLayer *view_layer, + struct Depsgraph *depsgraph, + View3D *v3d, + ARegion *ar, + bool only3d) { - wmWindowManager *wm = CTX_wm_manager(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - - int offsx, offsy, sizex, sizey; - int dflag = GP_DRAWDATA_NOSTATUS; + int dflag = 0; + RegionView3D *rv3d = ar->regiondata; + int offsx, offsy, winx, winy; - bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX + /* check that we have grease-pencil stuff to draw */ + // XXX: This is the only place that still uses this function + bGPdata *gpd = ED_gpencil_data_get_active_v3d(view_layer); if (gpd == NULL) return; - /* calculate rect */ - switch (sa->spacetype) { - case SPACE_IMAGE: /* image */ - case SPACE_CLIP: /* clip */ - { - /* just draw using standard scaling (settings here are currently ignored anyways) */ - /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ - offsx = 0; - offsy = 0; - sizex = ar->winx; - sizey = ar->winy; + /* when rendering to the offscreen buffer we don't want to + * deal with the camera border, otherwise map the coords to the camera border. */ + if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { + rctf rectf; + ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */ - wmOrtho2(ar->v2d.cur.xmin, ar->v2d.cur.xmax, ar->v2d.cur.ymin, ar->v2d.cur.ymax); + offsx = round_fl_to_int(rectf.xmin); + offsy = round_fl_to_int(rectf.ymin); + winx = round_fl_to_int(rectf.xmax - rectf.xmin); + winy = round_fl_to_int(rectf.ymax - rectf.ymin); + } + else { + offsx = 0; + offsy = 0; + winx = ar->winx; + winy = ar->winy; + } - dflag |= GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_IEDITHACK; - break; - } - case SPACE_SEQ: /* sequence */ - { - /* just draw using standard scaling (settings here are currently ignored anyways) */ - offsx = 0; - offsy = 0; - sizex = ar->winx; - sizey = ar->winy; - - /* NOTE: I2D was used in 2.4x, but the old settings for that have been deprecated - * and everything moved to standard View2d - */ - dflag |= GP_DRAWDATA_ONLYV2D; - break; - } - default: /* for spacetype not yet handled */ - offsx = 0; - offsy = 0; - sizex = ar->winx; - sizey = ar->winy; - - dflag |= GP_DRAWDATA_ONLYI2D; - break; + /* set flags */ + if (only3d) { + /* 3D strokes/3D space: + * - only 3D space points + * - don't status text either (as it's the wrong space) + */ + dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); } - if (ED_screen_animation_playing(wm)) { + if (v3d->flag2 & V3D_RENDER_OVERRIDE) { + /* don't draw status text when "only render" flag is set */ + dflag |= GP_DRAWDATA_NOSTATUS; + } + + if ((wm == NULL) || ED_screen_animation_playing(wm)) { /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses) * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) */ @@ -1631,85 +1764,46 @@ void ED_gpencil_draw_2dimage(const bContext *C) } /* draw it! */ - gp_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype); + gp_draw_data_all(rv3d, scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); } -/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly - * Note: this gets called twice - first time with onlyv2d=true to draw 'canvas' strokes, - * second time with onlyv2d=false for screen-aligned strokes */ -void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d) -{ - wmWindowManager *wm = CTX_wm_manager(C); - ScrArea *sa = CTX_wm_area(C); - ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - int dflag = 0; - - /* check that we have grease-pencil stuff to draw */ - if (sa == NULL) return; - bGPdata *gpd = ED_gpencil_data_get_active(C); // XXX - if (gpd == NULL) return; - - /* special hack for Image Editor */ - /* FIXME: the opengl poly-strokes don't draw at right thickness when done this way, so disabled */ - if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) - dflag |= GP_DRAWDATA_IEDITHACK; - - /* draw it! */ - if (onlyv2d) dflag |= (GP_DRAWDATA_ONLYV2D | GP_DRAWDATA_NOSTATUS); - if (ED_screen_animation_playing(wm)) dflag |= GP_DRAWDATA_NO_ONIONS; - - gp_draw_data_all(scene, gpd, 0, 0, ar->winx, ar->winy, CFRA, dflag, sa->spacetype); - - /* draw status text (if in screen/pixel-space) */ - if (!onlyv2d) { - gp_draw_status_text(gpd, ar); - } -} - -/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly - * Note: this gets called twice - first time with only3d=true to draw 3d-strokes, - * second time with only3d=false for screen-aligned strokes */ -void ED_gpencil_draw_view3d(wmWindowManager *wm, - Scene *scene, - ViewLayer *view_layer, - struct Depsgraph *depsgraph, - View3D *v3d, - ARegion *ar, - bool only3d) +/* draw grease-pencil sketches to specified 3d-view for gp object + * assuming that matrices are already set correctly + */ +void ED_gpencil_draw_view3d_object(wmWindowManager *wm, Scene *scene, Depsgraph *depsgraph, Object *ob, View3D *v3d, ARegion *ar, bool only3d) { int dflag = 0; RegionView3D *rv3d = ar->regiondata; - int offsx, offsy, winx, winy; + int offsx, offsy, winx, winy; /* check that we have grease-pencil stuff to draw */ - bGPdata *gpd = ED_gpencil_data_get_active_v3d(scene, view_layer); + bGPdata *gpd = ob->data; if (gpd == NULL) return; /* when rendering to the offscreen buffer we don't want to - * deal with the camera border, otherwise map the coords to the camera border. */ + * deal with the camera border, otherwise map the coords to the camera border. */ if ((rv3d->persp == RV3D_CAMOB) && !(G.f & G_RENDER_OGL)) { rctf rectf; ED_view3d_calc_camera_border(scene, depsgraph, ar, v3d, rv3d, &rectf, true); /* no shift */ offsx = round_fl_to_int(rectf.xmin); offsy = round_fl_to_int(rectf.ymin); - winx = round_fl_to_int(rectf.xmax - rectf.xmin); - winy = round_fl_to_int(rectf.ymax - rectf.ymin); + winx = round_fl_to_int(rectf.xmax - rectf.xmin); + winy = round_fl_to_int(rectf.ymax - rectf.ymin); } else { offsx = 0; offsy = 0; - winx = ar->winx; - winy = ar->winy; + winx = ar->winx; + winy = ar->winy; } /* set flags */ if (only3d) { /* 3D strokes/3D space: - * - only 3D space points - * - don't status text either (as it's the wrong space) - */ + * - only 3D space points + * - don't status text either (as it's the wrong space) + */ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS); } @@ -1720,20 +1814,23 @@ void ED_gpencil_draw_view3d(wmWindowManager *wm, if ((wm == NULL) || ED_screen_animation_playing(wm)) { /* don't show onionskins during animation playback/scrub (i.e. it obscures the poses) - * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) - */ + * OpenGL Renders (i.e. final output), or depth buffer (i.e. not real strokes) + */ dflag |= GP_DRAWDATA_NO_ONIONS; } /* draw it! */ - gp_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype); + ToolSettings *ts = scene->toolsettings; + Brush *brush = BKE_brush_getactive_gpencil(ts); + if (brush != NULL) { + gp_draw_data(rv3d, brush, 1.0f, ob, gpd, + offsx, offsy, winx, winy, CFRA, dflag); + } } -void ED_gpencil_draw_ex(Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype) +void ED_gpencil_draw_ex(RegionView3D *rv3d, Scene *scene, bGPdata *gpd, int winx, int winy, const int cfra, const char spacetype) { int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D; - gp_draw_data_all(scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype); + gp_draw_data_all(rv3d, scene, gpd, 0, 0, winx, winy, cfra, dflag, spacetype); } - -/* ************************************************** */ diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index 5e62a87caf3..88f935eb8bf 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -492,6 +492,8 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* make a copy of stroke, then of its points array */ gpsn = MEM_dupallocN(gps); gpsn->points = MEM_dupallocN(gps->points); + gpsn->dvert = MEM_dupallocN(gps->dvert); + BKE_gpencil_stroke_weights_duplicate(gps, gpsn); /* duplicate triangle information */ gpsn->triangles = MEM_dupallocN(gps->triangles); /* append stroke to frame */ diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c new file mode 100644 index 00000000000..8a7128adde1 --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -0,0 +1,1567 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez, Matias Mendiola + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/gpencil/gpencil_add_monkey.c + * \ingroup edgpencil + */ + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_main.h" +#include "BKE_material.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "ED_gpencil.h" + +/* Definition of the most important info from a color */ +typedef struct ColorTemplate { + const char *name; + float line[4]; + float fill[4]; +} ColorTemplate; + +/* Add color an ensure duplications (matched by name) */ +static int gpencil_monkey_color(Main *bmain, Object *ob, const ColorTemplate *pct) +{ + Material *ma = NULL; + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + if (STREQ(ma->id.name, pct->name)) { + return i; + } + } + + /* create a new one */ + BKE_object_material_slot_add(bmain, ob); + ma = BKE_material_add_gpencil(bmain, pct->name); + assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING); + + copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); + copy_v4_v4(ma->gp_style->fill_rgba, pct->fill); + + return BKE_object_material_slot_find_index(ob, ma) - 1; +} + +/* ***************************************************************** */ +/* Monkey Geometry */ + +static const float data0[538 * GP_PRIM_DATABUF_SIZE] = { + -0.509f, 0.0f, -0.156f, 0.267f, 0.362f, -0.522f, 0.0f, -0.159f, 0.31f, 0.407f, -0.531f, 0.0f, -0.16f, 0.347f, 0.426f, -0.543f, -0.0f, -0.162f, 0.38f, 0.439f, + -0.554f, -0.0f, -0.163f, 0.409f, 0.448f, -0.566f, -0.0f, -0.165f, 0.433f, 0.458f, -0.578f, -0.0f, -0.167f, 0.454f, 0.478f, -0.591f, -0.0f, -0.168f, 0.471f, 0.5f, + -0.604f, -0.0f, -0.169f, 0.485f, 0.51f, -0.619f, -0.0f, -0.171f, 0.496f, 0.516f, -0.634f, -0.0f, -0.171f, 0.504f, 0.519f, -0.649f, -0.0f, -0.171f, 0.511f, 0.519f, + -0.665f, -0.0f, -0.17f, 0.516f, 0.521f, -0.681f, -0.0f, -0.17f, 0.521f, 0.53f, -0.697f, -0.0f, -0.169f, 0.524f, 0.533f, -0.713f, -0.0f, -0.167f, 0.527f, 0.533f, + -0.729f, 0.0f, -0.165f, 0.53f, 0.534f, -0.745f, 0.0f, -0.161f, 0.531f, 0.534f, -0.761f, 0.0f, -0.157f, 0.533f, 0.535f, -0.777f, 0.0f, -0.153f, 0.534f, 0.535f, + -0.792f, 0.0f, -0.148f, 0.535f, 0.536f, -0.808f, 0.0f, -0.144f, 0.535f, 0.535f, -0.822f, 0.0f, -0.139f, 0.536f, 0.537f, -0.837f, 0.0f, -0.133f, 0.536f, 0.537f, + -0.852f, 0.0f, -0.128f, 0.536f, 0.537f, -0.866f, 0.0f, -0.122f, 0.536f, 0.537f, -0.88f, 0.0f, -0.115f, 0.536f, 0.537f, -0.894f, 0.0f, -0.109f, 0.536f, 0.537f, + -0.908f, 0.0f, -0.101f, 0.535f, 0.535f, -0.922f, 0.0f, -0.092f, 0.535f, 0.535f, -0.936f, 0.0f, -0.082f, 0.534f, 0.534f, -0.949f, 0.0f, -0.072f, 0.534f, 0.534f, + -0.963f, 0.0f, -0.061f, 0.534f, 0.534f, -0.976f, 0.0f, -0.05f, 0.534f, 0.534f, -0.988f, 0.0f, -0.039f, 0.534f, 0.534f, -1.0f, 0.0f, -0.028f, 0.533f, 0.534f, + -1.011f, 0.0f, -0.017f, 0.533f, 0.533f, -1.022f, 0.0f, -0.007f, 0.533f, 0.534f, -1.033f, 0.0f, 0.004f, 0.533f, 0.533f, -1.043f, 0.0f, 0.014f, 0.532f, 0.532f, + -1.053f, 0.0f, 0.025f, 0.532f, 0.532f, -1.062f, 0.0f, 0.036f, 0.531f, 0.531f, -1.071f, 0.0f, 0.046f, 0.531f, 0.531f, -1.078f, 0.0f, 0.057f, 0.531f, 0.531f, + -1.085f, 0.0f, 0.068f, 0.531f, 0.531f, -1.092f, 0.0f, 0.08f, 0.532f, 0.532f, -1.098f, 0.0f, 0.091f, 0.533f, 0.533f, -1.104f, 0.0f, 0.105f, 0.535f, 0.535f, + -1.11f, 0.0f, 0.119f, 0.539f, 0.539f, -1.115f, 0.0f, 0.133f, 0.54f, 0.54f, -1.118f, 0.0f, 0.148f, 0.541f, 0.541f, -1.121f, 0.0f, 0.162f, 0.542f, 0.542f, + -1.123f, 0.0f, 0.177f, 0.542f, 0.542f, -1.125f, 0.0f, 0.193f, 0.543f, 0.543f, -1.125f, 0.0f, 0.208f, 0.543f, 0.543f, -1.125f, 0.0f, 0.225f, 0.543f, 0.543f, + -1.124f, 0.0f, 0.241f, 0.545f, 0.545f, -1.122f, 0.0f, 0.258f, 0.546f, 0.546f, -1.119f, 0.0f, 0.274f, 0.548f, 0.548f, -1.116f, 0.0f, 0.29f, 0.549f, 0.549f, + -1.111f, 0.0f, 0.305f, 0.549f, 0.549f, -1.106f, 0.0f, 0.318f, 0.549f, 0.549f, -1.1f, 0.0f, 0.33f, 0.549f, 0.549f, -1.094f, 0.0f, 0.34f, 0.549f, 0.549f, + -1.087f, 0.0f, 0.349f, 0.55f, 0.55f, -1.08f, 0.0f, 0.357f, 0.549f, 0.549f, -1.072f, 0.0f, 0.365f, 0.55f, 0.55f, -1.063f, 0.0f, 0.372f, 0.551f, 0.551f, + -1.054f, 0.0f, 0.379f, 0.552f, 0.552f, -1.044f, 0.0f, 0.385f, 0.553f, 0.553f, -1.034f, 0.0f, 0.391f, 0.553f, 0.553f, -1.024f, 0.0f, 0.396f, 0.554f, 0.554f, + -1.013f, 0.0f, 0.401f, 0.554f, 0.554f, -1.003f, 0.0f, 0.405f, 0.554f, 0.554f, -0.991f, 0.0f, 0.409f, 0.554f, 0.554f, -0.978f, 0.0f, 0.412f, 0.555f, 0.555f, + -0.964f, -0.0f, 0.414f, 0.555f, 0.555f, -0.949f, -0.0f, 0.414f, 0.556f, 0.556f, -0.934f, -0.0f, 0.413f, 0.556f, 0.556f, -0.919f, -0.0f, 0.412f, 0.557f, 0.557f, + -0.905f, -0.0f, 0.41f, 0.557f, 0.557f, -0.892f, -0.0f, 0.406f, 0.557f, 0.557f, -0.879f, -0.0f, 0.402f, 0.557f, 0.558f, -0.867f, -0.0f, 0.398f, 0.557f, 0.557f, + -0.855f, -0.0f, 0.394f, 0.557f, 0.557f, -0.843f, -0.0f, 0.388f, 0.557f, 0.557f, -0.831f, -0.0f, 0.381f, 0.558f, 0.557f, -0.82f, -0.0f, 0.375f, 0.558f, 0.557f, + -0.81f, -0.0f, 0.368f, 0.558f, 0.558f, -0.801f, -0.0f, 0.362f, 0.558f, 0.558f, -0.793f, -0.0f, 0.357f, 0.557f, 0.559f, -0.784f, 0.0f, 0.353f, 0.557f, 0.559f, + -0.776f, 0.0f, 0.35f, 0.556f, 0.559f, -0.768f, 0.0f, 0.348f, 0.556f, 0.559f, -0.76f, 0.0f, 0.346f, 0.555f, 0.559f, -0.752f, 0.0f, 0.346f, 0.554f, 0.559f, + -0.744f, 0.0f, 0.347f, 0.553f, 0.554f, -0.737f, 0.0f, 0.348f, 0.552f, 0.548f, -0.729f, 0.0f, 0.351f, 0.551f, 0.544f, -0.723f, 0.0f, 0.355f, 0.551f, 0.546f, + -0.716f, 0.0f, 0.36f, 0.55f, 0.546f, -0.709f, 0.0f, 0.366f, 0.55f, 0.547f, -0.702f, 0.0f, 0.372f, 0.549f, 0.547f, -0.696f, 0.0f, 0.379f, 0.549f, 0.547f, + -0.689f, 0.0f, 0.386f, 0.549f, 0.548f, -0.683f, 0.0f, 0.394f, 0.549f, 0.548f, -0.676f, 0.0f, 0.403f, 0.549f, 0.549f, -0.67f, 0.0f, 0.413f, 0.549f, 0.548f, + -0.664f, 0.0f, 0.422f, 0.549f, 0.549f, -0.658f, 0.0f, 0.432f, 0.55f, 0.549f, -0.652f, 0.0f, 0.441f, 0.551f, 0.548f, -0.646f, 0.0f, 0.451f, 0.552f, 0.548f, + -0.639f, 0.0f, 0.46f, 0.554f, 0.548f, -0.632f, 0.0f, 0.469f, 0.556f, 0.549f, -0.624f, 0.0f, 0.478f, 0.559f, 0.549f, -0.616f, 0.0f, 0.487f, 0.563f, 0.549f, + -0.609f, 0.0f, 0.497f, 0.567f, 0.549f, -0.6f, 0.0f, 0.507f, 0.572f, 0.558f, -0.592f, 0.0f, 0.518f, 0.577f, 0.574f, -0.584f, 0.0f, 0.528f, 0.582f, 0.587f, + -0.575f, 0.0f, 0.538f, 0.586f, 0.592f, -0.566f, 0.0f, 0.548f, 0.591f, 0.595f, -0.556f, 0.0f, 0.557f, 0.594f, 0.597f, -0.546f, 0.0f, 0.567f, 0.597f, 0.598f, + -0.536f, 0.0f, 0.577f, 0.6f, 0.6f, -0.525f, 0.0f, 0.586f, 0.602f, 0.603f, -0.514f, 0.0f, 0.596f, 0.604f, 0.605f, -0.503f, 0.0f, 0.606f, 0.605f, 0.606f, + -0.492f, 0.0f, 0.615f, 0.606f, 0.607f, -0.482f, 0.0f, 0.624f, 0.607f, 0.607f, -0.471f, 0.0f, 0.632f, 0.608f, 0.607f, -0.462f, 0.0f, 0.64f, 0.609f, 0.607f, + -0.453f, 0.0f, 0.647f, 0.61f, 0.61f, -0.444f, 0.0f, 0.654f, 0.612f, 0.611f, -0.435f, 0.0f, 0.66f, 0.614f, 0.613f, -0.427f, 0.0f, 0.666f, 0.616f, 0.615f, + -0.418f, 0.0f, 0.672f, 0.617f, 0.618f, -0.409f, 0.0f, 0.677f, 0.619f, 0.621f, -0.399f, 0.0f, 0.683f, 0.621f, 0.622f, -0.389f, 0.0f, 0.69f, 0.623f, 0.623f, + -0.379f, 0.0f, 0.696f, 0.624f, 0.624f, -0.368f, 0.0f, 0.702f, 0.626f, 0.626f, -0.356f, 0.0f, 0.708f, 0.628f, 0.628f, -0.345f, 0.0f, 0.713f, 0.63f, 0.63f, + -0.333f, 0.0f, 0.719f, 0.633f, 0.631f, -0.32f, 0.0f, 0.724f, 0.637f, 0.632f, -0.307f, 0.0f, 0.729f, 0.641f, 0.64f, -0.294f, 0.0f, 0.732f, 0.646f, 0.644f, + -0.281f, 0.0f, 0.736f, 0.65f, 0.655f, -0.268f, 0.0f, 0.739f, 0.654f, 0.657f, -0.255f, 0.0f, 0.742f, 0.657f, 0.658f, -0.243f, 0.0f, 0.745f, 0.659f, 0.661f, + -0.23f, 0.0f, 0.747f, 0.662f, 0.663f, -0.217f, 0.0f, 0.75f, 0.664f, 0.664f, -0.203f, 0.0f, 0.753f, 0.666f, 0.666f, -0.19f, 0.0f, 0.755f, 0.667f, 0.668f, + -0.177f, 0.0f, 0.757f, 0.669f, 0.67f, -0.163f, 0.0f, 0.76f, 0.671f, 0.671f, -0.15f, 0.0f, 0.762f, 0.673f, 0.672f, -0.136f, 0.0f, 0.764f, 0.674f, 0.674f, + -0.122f, 0.0f, 0.767f, 0.676f, 0.676f, -0.108f, 0.0f, 0.769f, 0.677f, 0.678f, -0.093f, 0.0f, 0.771f, 0.678f, 0.68f, -0.079f, 0.0f, 0.773f, 0.678f, 0.68f, + -0.064f, 0.0f, 0.774f, 0.679f, 0.679f, -0.049f, 0.0f, 0.775f, 0.68f, 0.68f, -0.033f, 0.0f, 0.775f, 0.68f, 0.68f, -0.018f, 0.0f, 0.776f, 0.68f, 0.68f, + -0.002f, 0.0f, 0.776f, 0.681f, 0.68f, 0.013f, 0.0f, 0.777f, 0.681f, 0.681f, 0.029f, 0.0f, 0.777f, 0.682f, 0.681f, 0.045f, 0.0f, 0.777f, 0.682f, 0.681f, + 0.061f, 0.0f, 0.777f, 0.683f, 0.683f, 0.077f, 0.0f, 0.776f, 0.683f, 0.683f, 0.094f, 0.0f, 0.775f, 0.684f, 0.684f, 0.11f, 0.0f, 0.774f, 0.685f, 0.683f, + 0.126f, 0.0f, 0.773f, 0.685f, 0.685f, 0.142f, 0.0f, 0.771f, 0.687f, 0.685f, 0.158f, 0.0f, 0.769f, 0.688f, 0.685f, 0.174f, 0.0f, 0.767f, 0.69f, 0.686f, + 0.19f, 0.0f, 0.765f, 0.691f, 0.692f, 0.206f, 0.0f, 0.762f, 0.693f, 0.694f, 0.222f, 0.0f, 0.757f, 0.695f, 0.696f, 0.238f, 0.0f, 0.752f, 0.697f, 0.697f, + 0.254f, 0.0f, 0.747f, 0.699f, 0.698f, 0.27f, 0.0f, 0.742f, 0.7f, 0.7f, 0.286f, 0.0f, 0.736f, 0.702f, 0.702f, 0.302f, 0.0f, 0.73f, 0.704f, 0.704f, + 0.318f, 0.0f, 0.724f, 0.705f, 0.71f, 0.335f, 0.0f, 0.717f, 0.707f, 0.71f, 0.351f, 0.0f, 0.709f, 0.708f, 0.71f, 0.367f, 0.0f, 0.701f, 0.709f, 0.711f, + 0.382f, 0.0f, 0.692f, 0.71f, 0.713f, 0.397f, 0.0f, 0.683f, 0.711f, 0.713f, 0.41f, 0.0f, 0.675f, 0.712f, 0.713f, 0.422f, 0.0f, 0.666f, 0.712f, 0.714f, + 0.434f, 0.0f, 0.658f, 0.713f, 0.714f, 0.446f, 0.0f, 0.649f, 0.714f, 0.714f, 0.458f, 0.0f, 0.641f, 0.714f, 0.714f, 0.47f, 0.0f, 0.632f, 0.715f, 0.715f, + 0.483f, 0.0f, 0.622f, 0.715f, 0.716f, 0.496f, 0.0f, 0.611f, 0.715f, 0.716f, 0.51f, 0.0f, 0.6f, 0.716f, 0.717f, 0.523f, 0.0f, 0.588f, 0.716f, 0.716f, + 0.536f, 0.0f, 0.576f, 0.717f, 0.717f, 0.55f, 0.0f, 0.563f, 0.717f, 0.717f, 0.564f, 0.0f, 0.549f, 0.717f, 0.717f, 0.577f, 0.0f, 0.536f, 0.718f, 0.717f, + 0.59f, 0.0f, 0.522f, 0.718f, 0.717f, 0.603f, 0.0f, 0.508f, 0.718f, 0.718f, 0.615f, 0.0f, 0.496f, 0.718f, 0.718f, 0.625f, 0.0f, 0.484f, 0.718f, 0.718f, + 0.635f, 0.0f, 0.473f, 0.719f, 0.718f, 0.645f, 0.0f, 0.461f, 0.719f, 0.718f, 0.654f, 0.0f, 0.45f, 0.719f, 0.718f, 0.662f, 0.0f, 0.44f, 0.719f, 0.719f, + 0.67f, 0.0f, 0.431f, 0.719f, 0.719f, 0.676f, 0.0f, 0.422f, 0.719f, 0.719f, 0.682f, 0.0f, 0.414f, 0.719f, 0.719f, 0.687f, 0.0f, 0.407f, 0.719f, 0.719f, + 0.692f, 0.0f, 0.4f, 0.719f, 0.719f, 0.697f, 0.0f, 0.394f, 0.719f, 0.719f, 0.701f, 0.0f, 0.388f, 0.718f, 0.718f, 0.705f, 0.0f, 0.383f, 0.718f, 0.717f, + 0.708f, 0.0f, 0.378f, 0.718f, 0.717f, 0.711f, 0.0f, 0.374f, 0.717f, 0.717f, 0.714f, 0.0f, 0.37f, 0.717f, 0.717f, 0.717f, 0.0f, 0.366f, 0.717f, 0.717f, + 0.719f, 0.0f, 0.362f, 0.718f, 0.717f, 0.722f, 0.0f, 0.359f, 0.718f, 0.718f, 0.724f, 0.0f, 0.356f, 0.718f, 0.717f, 0.727f, 0.0f, 0.352f, 0.717f, 0.719f, + 0.73f, 0.0f, 0.349f, 0.717f, 0.719f, 0.734f, 0.0f, 0.347f, 0.715f, 0.719f, 0.737f, 0.0f, 0.344f, 0.714f, 0.714f, 0.742f, 0.0f, 0.341f, 0.713f, 0.709f, + 0.746f, 0.0f, 0.339f, 0.714f, 0.707f, 0.751f, 0.0f, 0.336f, 0.718f, 0.704f, 0.757f, 0.0f, 0.334f, 0.724f, 0.705f, 0.763f, 0.0f, 0.332f, 0.732f, 0.705f, + 0.769f, -0.0f, 0.329f, 0.742f, 0.704f, 0.775f, -0.0f, 0.328f, 0.753f, 0.713f, 0.782f, -0.0f, 0.327f, 0.764f, 0.804f, 0.789f, -0.0f, 0.327f, 0.774f, 0.813f, + 0.797f, -0.0f, 0.327f, 0.783f, 0.815f, 0.805f, -0.0f, 0.328f, 0.791f, 0.815f, 0.814f, -0.0f, 0.329f, 0.797f, 0.816f, 0.823f, -0.0f, 0.331f, 0.802f, 0.815f, + 0.832f, 0.0f, 0.335f, 0.806f, 0.816f, 0.841f, 0.0f, 0.341f, 0.809f, 0.816f, 0.851f, 0.0f, 0.346f, 0.811f, 0.816f, 0.861f, 0.0f, 0.351f, 0.812f, 0.816f, + 0.871f, 0.0f, 0.356f, 0.813f, 0.815f, 0.881f, 0.0f, 0.361f, 0.814f, 0.816f, 0.893f, 0.0f, 0.365f, 0.814f, 0.816f, 0.906f, 0.0f, 0.368f, 0.814f, 0.817f, + 0.922f, 0.0f, 0.372f, 0.813f, 0.816f, 0.939f, 0.0f, 0.375f, 0.812f, 0.817f, 0.957f, 0.0f, 0.377f, 0.811f, 0.817f, 0.977f, 0.0f, 0.379f, 0.81f, 0.815f, + 0.995f, 0.0f, 0.38f, 0.808f, 0.813f, 1.012f, 0.0f, 0.379f, 0.806f, 0.807f, 1.028f, 0.0f, 0.377f, 0.803f, 0.803f, 1.042f, 0.0f, 0.374f, 0.8f, 0.801f, + 1.054f, 0.0f, 0.371f, 0.797f, 0.8f, 1.065f, 0.0f, 0.366f, 0.794f, 0.8f, 1.076f, 0.0f, 0.361f, 0.791f, 0.792f, 1.085f, 0.0f, 0.355f, 0.788f, 0.781f, + 1.093f, 0.0f, 0.348f, 0.785f, 0.781f, 1.1f, 0.0f, 0.34f, 0.783f, 0.78f, 1.106f, 0.0f, 0.33f, 0.782f, 0.78f, 1.113f, 0.0f, 0.321f, 0.781f, 0.778f, + 1.117f, 0.0f, 0.31f, 0.78f, 0.777f, 1.122f, -0.0f, 0.299f, 0.779f, 0.777f, 1.125f, -0.0f, 0.286f, 0.778f, 0.776f, 1.129f, -0.0f, 0.274f, 0.778f, 0.777f, + 1.131f, -0.0f, 0.262f, 0.778f, 0.777f, 1.132f, -0.0f, 0.249f, 0.777f, 0.777f, 1.134f, -0.0f, 0.237f, 0.777f, 0.778f, 1.134f, -0.0f, 0.225f, 0.777f, 0.778f, + 1.135f, -0.0f, 0.213f, 0.776f, 0.777f, 1.134f, -0.0f, 0.201f, 0.776f, 0.776f, 1.134f, -0.0f, 0.189f, 0.776f, 0.775f, 1.132f, -0.0f, 0.177f, 0.775f, 0.776f, + 1.13f, -0.0f, 0.164f, 0.775f, 0.775f, 1.129f, -0.0f, 0.152f, 0.774f, 0.774f, 1.126f, -0.0f, 0.141f, 0.774f, 0.773f, 1.122f, -0.0f, 0.13f, 0.774f, 0.772f, + 1.118f, -0.0f, 0.118f, 0.773f, 0.772f, 1.113f, -0.0f, 0.108f, 0.773f, 0.773f, 1.107f, -0.0f, 0.097f, 0.773f, 0.774f, 1.102f, -0.0f, 0.087f, 0.772f, 0.773f, + 1.095f, -0.0f, 0.077f, 0.772f, 0.773f, 1.088f, -0.0f, 0.067f, 0.771f, 0.772f, 1.081f, -0.0f, 0.057f, 0.771f, 0.773f, 1.073f, -0.0f, 0.048f, 0.77f, 0.772f, + 1.066f, -0.0f, 0.038f, 0.769f, 0.767f, 1.058f, -0.0f, 0.029f, 0.768f, 0.766f, 1.05f, -0.0f, 0.019f, 0.768f, 0.765f, 1.041f, -0.0f, 0.011f, 0.767f, 0.765f, + 1.032f, -0.0f, 0.003f, 0.767f, 0.766f, 1.023f, -0.0f, -0.004f, 0.766f, 0.765f, 1.013f, -0.0f, -0.011f, 0.766f, 0.765f, 1.003f, -0.0f, -0.019f, 0.765f, 0.766f, + 0.993f, -0.0f, -0.026f, 0.765f, 0.765f, 0.983f, -0.0f, -0.034f, 0.764f, 0.765f, 0.972f, -0.0f, -0.041f, 0.762f, 0.765f, 0.962f, -0.0f, -0.048f, 0.761f, 0.765f, + 0.951f, -0.0f, -0.055f, 0.759f, 0.762f, 0.94f, -0.0f, -0.063f, 0.756f, 0.761f, 0.929f, -0.0f, -0.07f, 0.754f, 0.755f, 0.918f, -0.0f, -0.078f, 0.751f, 0.751f, + 0.907f, -0.0f, -0.085f, 0.748f, 0.747f, 0.896f, -0.0f, -0.092f, 0.745f, 0.744f, 0.884f, -0.0f, -0.099f, 0.742f, 0.742f, 0.873f, -0.0f, -0.105f, 0.739f, 0.738f, + 0.861f, -0.0f, -0.11f, 0.736f, 0.737f, 0.849f, 0.0f, -0.115f, 0.733f, 0.731f, 0.836f, 0.0f, -0.119f, 0.73f, 0.73f, 0.823f, 0.0f, -0.124f, 0.728f, 0.727f, + 0.81f, 0.0f, -0.128f, 0.725f, 0.725f, 0.796f, 0.0f, -0.132f, 0.723f, 0.723f, 0.783f, 0.0f, -0.136f, 0.72f, 0.719f, 0.77f, 0.0f, -0.141f, 0.718f, 0.717f, + 0.756f, 0.0f, -0.145f, 0.715f, 0.712f, 0.742f, 0.0f, -0.15f, 0.713f, 0.708f, 0.728f, 0.0f, -0.152f, 0.711f, 0.707f, 0.713f, 0.0f, -0.155f, 0.709f, 0.706f, + 0.699f, 0.0f, -0.156f, 0.706f, 0.706f, 0.684f, 0.0f, -0.158f, 0.704f, 0.705f, 0.67f, 0.0f, -0.159f, 0.702f, 0.705f, 0.656f, 0.0f, -0.16f, 0.7f, 0.704f, + 0.642f, 0.0f, -0.161f, 0.698f, 0.702f, 0.628f, 0.0f, -0.161f, 0.695f, 0.698f, 0.614f, 0.0f, -0.162f, 0.693f, 0.695f, 0.6f, 0.0f, -0.162f, 0.691f, 0.691f, + 0.587f, 0.0f, -0.162f, 0.688f, 0.686f, 0.574f, 0.0f, -0.162f, 0.686f, 0.685f, 0.561f, 0.0f, -0.161f, 0.683f, 0.683f, 0.548f, 0.0f, -0.161f, 0.681f, 0.683f, + 0.535f, 0.0f, -0.161f, 0.678f, 0.678f, 0.523f, 0.0f, -0.16f, 0.676f, 0.676f, 0.512f, 0.0f, -0.16f, 0.673f, 0.674f, 0.501f, 0.0f, -0.16f, 0.671f, 0.67f, + 0.49f, 0.0f, -0.16f, 0.668f, 0.668f, 0.48f, 0.0f, -0.161f, 0.666f, 0.663f, 0.469f, 0.0f, -0.162f, 0.665f, 0.66f, 0.458f, 0.0f, -0.165f, 0.663f, 0.66f, + 0.447f, 0.0f, -0.167f, 0.662f, 0.659f, 0.437f, 0.0f, -0.171f, 0.661f, 0.659f, 0.426f, 0.0f, -0.175f, 0.66f, 0.659f, 0.415f, 0.0f, -0.18f, 0.66f, 0.659f, + 0.404f, 0.0f, -0.185f, 0.659f, 0.659f, 0.393f, 0.0f, -0.191f, 0.659f, 0.657f, 0.383f, 0.0f, -0.196f, 0.659f, 0.657f, 0.373f, 0.0f, -0.202f, 0.658f, 0.659f, + 0.363f, -0.0f, -0.208f, 0.658f, 0.658f, 0.353f, -0.0f, -0.215f, 0.658f, 0.659f, 0.344f, -0.0f, -0.223f, 0.658f, 0.659f, 0.336f, -0.0f, -0.23f, 0.658f, 0.659f, + 0.327f, -0.0f, -0.238f, 0.658f, 0.658f, 0.319f, -0.0f, -0.245f, 0.657f, 0.657f, 0.312f, -0.0f, -0.253f, 0.657f, 0.656f, 0.305f, -0.0f, -0.261f, 0.656f, 0.658f, + 0.299f, -0.0f, -0.269f, 0.655f, 0.658f, 0.293f, 0.0f, -0.278f, 0.653f, 0.657f, 0.288f, 0.0f, -0.287f, 0.65f, 0.657f, 0.283f, 0.0f, -0.295f, 0.646f, 0.656f, + 0.279f, 0.0f, -0.304f, 0.642f, 0.655f, 0.275f, 0.0f, -0.313f, 0.637f, 0.642f, 0.271f, 0.0f, -0.322f, 0.633f, 0.637f, 0.268f, 0.0f, -0.331f, 0.628f, 0.609f, + 0.265f, 0.0f, -0.341f, 0.624f, 0.607f, 0.263f, 0.0f, -0.35f, 0.62f, 0.608f, 0.261f, 0.0f, -0.359f, 0.617f, 0.608f, 0.259f, 0.0f, -0.369f, 0.614f, 0.607f, + 0.258f, 0.0f, -0.379f, 0.612f, 0.606f, 0.257f, 0.0f, -0.389f, 0.61f, 0.606f, 0.258f, 0.0f, -0.399f, 0.609f, 0.605f, 0.258f, 0.0f, -0.41f, 0.608f, 0.604f, + 0.26f, 0.0f, -0.421f, 0.608f, 0.606f, 0.263f, 0.0f, -0.431f, 0.607f, 0.606f, 0.266f, 0.0f, -0.441f, 0.607f, 0.606f, 0.27f, 0.0f, -0.452f, 0.606f, 0.607f, + 0.274f, 0.0f, -0.463f, 0.606f, 0.607f, 0.279f, 0.0f, -0.475f, 0.605f, 0.607f, 0.283f, 0.0f, -0.487f, 0.604f, 0.607f, 0.288f, 0.0f, -0.498f, 0.603f, 0.607f, + 0.293f, 0.0f, -0.511f, 0.601f, 0.607f, 0.297f, 0.0f, -0.523f, 0.598f, 0.606f, 0.301f, 0.0f, -0.536f, 0.595f, 0.605f, 0.305f, 0.0f, -0.549f, 0.591f, 0.602f, + 0.309f, 0.0f, -0.562f, 0.588f, 0.597f, 0.312f, 0.0f, -0.576f, 0.583f, 0.585f, 0.315f, 0.0f, -0.59f, 0.579f, 0.577f, 0.318f, 0.0f, -0.604f, 0.574f, 0.576f, + 0.321f, 0.0f, -0.618f, 0.569f, 0.57f, 0.323f, 0.0f, -0.633f, 0.564f, 0.564f, 0.326f, 0.0f, -0.647f, 0.559f, 0.554f, 0.328f, 0.0f, -0.663f, 0.555f, 0.549f, + 0.33f, 0.0f, -0.678f, 0.551f, 0.546f, 0.332f, 0.0f, -0.693f, 0.547f, 0.543f, 0.334f, 0.0f, -0.709f, 0.544f, 0.543f, 0.336f, 0.0f, -0.726f, 0.541f, 0.541f, + 0.338f, 0.0f, -0.742f, 0.538f, 0.54f, 0.338f, 0.0f, -0.758f, 0.536f, 0.538f, 0.338f, 0.0f, -0.773f, 0.534f, 0.53f, 0.337f, 0.0f, -0.787f, 0.532f, 0.528f, + 0.337f, 0.0f, -0.801f, 0.53f, 0.528f, 0.336f, 0.0f, -0.814f, 0.529f, 0.528f, 0.334f, 0.0f, -0.827f, 0.527f, 0.528f, 0.333f, 0.0f, -0.84f, 0.525f, 0.529f, + 0.331f, 0.0f, -0.853f, 0.523f, 0.529f, 0.328f, 0.0f, -0.866f, 0.521f, 0.528f, 0.324f, 0.0f, -0.877f, 0.519f, 0.516f, 0.32f, 0.0f, -0.889f, 0.516f, 0.515f, + 0.315f, 0.0f, -0.9f, 0.513f, 0.515f, 0.31f, 0.0f, -0.91f, 0.51f, 0.514f, 0.304f, 0.0f, -0.921f, 0.507f, 0.513f, 0.297f, 0.0f, -0.931f, 0.505f, 0.507f, + 0.289f, 0.0f, -0.94f, 0.502f, 0.498f, 0.281f, 0.0f, -0.948f, 0.499f, 0.494f, 0.272f, 0.0f, -0.956f, 0.497f, 0.491f, 0.262f, 0.0f, -0.963f, 0.495f, 0.49f, + 0.253f, 0.0f, -0.969f, 0.494f, 0.491f, 0.242f, 0.0f, -0.975f, 0.493f, 0.491f, 0.231f, 0.0f, -0.98f, 0.492f, 0.49f, 0.22f, 0.0f, -0.986f, 0.491f, 0.489f, + 0.208f, 0.0f, -0.99f, 0.491f, 0.49f, 0.195f, 0.0f, -0.994f, 0.491f, 0.491f, 0.181f, 0.0f, -0.998f, 0.491f, 0.491f, 0.168f, 0.0f, -1.001f, 0.491f, 0.492f, + 0.154f, 0.0f, -1.005f, 0.491f, 0.492f, 0.141f, 0.0f, -1.008f, 0.492f, 0.492f, 0.126f, 0.0f, -1.01f, 0.492f, 0.492f, 0.112f, 0.0f, -1.011f, 0.492f, 0.492f, + 0.097f, 0.0f, -1.013f, 0.492f, 0.492f, 0.081f, 0.0f, -1.013f, 0.492f, 0.492f, 0.066f, 0.0f, -1.014f, 0.493f, 0.493f, 0.05f, 0.0f, -1.014f, 0.493f, 0.494f, + 0.035f, 0.0f, -1.014f, 0.493f, 0.494f, 0.019f, 0.0f, -1.013f, 0.493f, 0.494f, 0.004f, 0.0f, -1.012f, 0.493f, 0.494f, -0.011f, 0.0f, -1.011f, 0.493f, 0.493f, + -0.026f, 0.0f, -1.01f, 0.492f, 0.493f, -0.041f, 0.0f, -1.008f, 0.492f, 0.492f, -0.056f, 0.0f, -1.006f, 0.492f, 0.492f, -0.07f, 0.0f, -1.004f, 0.491f, 0.492f, + -0.084f, 0.0f, -1.001f, 0.491f, 0.492f, -0.098f, 0.0f, -0.999f, 0.491f, 0.491f, -0.112f, 0.0f, -0.995f, 0.491f, 0.49f, -0.125f, 0.0f, -0.992f, 0.49f, 0.49f, + -0.138f, 0.0f, -0.987f, 0.49f, 0.491f, -0.15f, 0.0f, -0.983f, 0.49f, 0.49f, -0.162f, 0.0f, -0.978f, 0.49f, 0.49f, -0.174f, 0.0f, -0.973f, 0.489f, 0.489f, + -0.185f, 0.0f, -0.967f, 0.489f, 0.488f, -0.196f, 0.0f, -0.961f, 0.489f, 0.489f, -0.207f, 0.0f, -0.955f, 0.489f, 0.489f, -0.218f, 0.0f, -0.949f, 0.489f, 0.49f, + -0.229f, 0.0f, -0.943f, 0.489f, 0.489f, -0.24f, 0.0f, -0.936f, 0.489f, 0.489f, -0.25f, 0.0f, -0.929f, 0.489f, 0.489f, -0.261f, 0.0f, -0.922f, 0.489f, 0.489f, + -0.271f, 0.0f, -0.914f, 0.489f, 0.49f, -0.28f, 0.0f, -0.907f, 0.49f, 0.49f, -0.289f, 0.0f, -0.898f, 0.49f, 0.489f, -0.298f, 0.0f, -0.89f, 0.49f, 0.489f, + -0.306f, 0.0f, -0.882f, 0.49f, 0.49f, -0.314f, 0.0f, -0.875f, 0.491f, 0.489f, -0.322f, 0.0f, -0.866f, 0.492f, 0.489f, -0.328f, 0.0f, -0.857f, 0.492f, 0.489f, + -0.333f, 0.0f, -0.847f, 0.493f, 0.49f, -0.336f, 0.0f, -0.836f, 0.494f, 0.488f, -0.338f, 0.0f, -0.824f, 0.496f, 0.49f, -0.338f, 0.0f, -0.811f, 0.497f, 0.49f, + -0.338f, 0.0f, -0.798f, 0.499f, 0.491f, -0.337f, 0.0f, -0.785f, 0.501f, 0.497f, -0.337f, 0.0f, -0.772f, 0.503f, 0.5f, -0.337f, 0.0f, -0.759f, 0.505f, 0.504f, + -0.336f, -0.0f, -0.746f, 0.507f, 0.505f, -0.336f, -0.0f, -0.733f, 0.51f, 0.51f, -0.335f, -0.0f, -0.719f, 0.512f, 0.513f, -0.334f, -0.0f, -0.706f, 0.515f, 0.515f, + -0.333f, -0.0f, -0.692f, 0.518f, 0.516f, -0.332f, -0.0f, -0.678f, 0.52f, 0.522f, -0.331f, -0.0f, -0.665f, 0.523f, 0.523f, -0.329f, -0.0f, -0.651f, 0.525f, 0.528f, + -0.327f, -0.0f, -0.637f, 0.528f, 0.53f, -0.325f, -0.0f, -0.624f, 0.53f, 0.532f, -0.322f, -0.0f, -0.61f, 0.532f, 0.534f, -0.319f, -0.0f, -0.597f, 0.535f, 0.535f, + -0.316f, -0.0f, -0.584f, 0.537f, 0.538f, -0.313f, -0.0f, -0.57f, 0.539f, 0.54f, -0.31f, -0.0f, -0.557f, 0.541f, 0.542f, -0.307f, -0.0f, -0.544f, 0.542f, 0.545f, + -0.303f, -0.0f, -0.531f, 0.544f, 0.546f, -0.3f, -0.0f, -0.519f, 0.546f, 0.549f, -0.298f, -0.0f, -0.506f, 0.547f, 0.549f, -0.295f, -0.0f, -0.494f, 0.548f, 0.549f, + -0.292f, -0.0f, -0.482f, 0.549f, 0.55f, -0.29f, -0.0f, -0.47f, 0.55f, 0.552f, -0.287f, -0.0f, -0.459f, 0.551f, 0.552f, -0.285f, -0.0f, -0.447f, 0.551f, 0.552f, + -0.284f, -0.0f, -0.436f, 0.552f, 0.552f, -0.282f, -0.0f, -0.425f, 0.552f, 0.553f, -0.281f, -0.0f, -0.413f, 0.553f, 0.553f, -0.28f, -0.0f, -0.402f, 0.553f, 0.553f, + -0.28f, -0.0f, -0.392f, 0.553f, 0.553f, -0.281f, -0.0f, -0.381f, 0.554f, 0.553f, -0.283f, -0.0f, -0.369f, 0.554f, 0.554f, -0.286f, -0.0f, -0.359f, 0.554f, 0.554f, + -0.289f, -0.0f, -0.348f, 0.555f, 0.554f, -0.294f, -0.0f, -0.337f, 0.555f, 0.555f, -0.299f, -0.0f, -0.327f, 0.555f, 0.554f, -0.305f, -0.0f, -0.317f, 0.556f, 0.555f, + -0.312f, -0.0f, -0.307f, 0.556f, 0.555f, -0.319f, -0.0f, -0.297f, 0.556f, 0.557f, -0.326f, 0.0f, -0.287f, 0.557f, 0.558f, -0.334f, 0.0f, -0.278f, 0.557f, 0.557f, + -0.341f, 0.0f, -0.268f, 0.557f, 0.558f, -0.349f, 0.0f, -0.259f, 0.558f, 0.558f, -0.359f, 0.0f, -0.251f, 0.558f, 0.558f, -0.368f, 0.0f, -0.243f, 0.558f, 0.558f, + -0.378f, 0.0f, -0.235f, 0.558f, 0.559f, -0.388f, 0.0f, -0.228f, 0.558f, 0.558f, -0.398f, 0.0f, -0.221f, 0.559f, 0.559f, -0.408f, 0.0f, -0.214f, 0.559f, 0.559f, + -0.418f, 0.0f, -0.208f, 0.559f, 0.559f, -0.427f, 0.0f, -0.202f, 0.559f, 0.558f, -0.436f, 0.0f, -0.196f, 0.559f, 0.559f, -0.445f, 0.0f, -0.191f, 0.559f, 0.559f, + -0.453f, 0.0f, -0.187f, 0.558f, 0.559f, -0.462f, 0.0f, -0.183f, 0.558f, 0.558f, -0.469f, 0.0f, -0.18f, 0.558f, 0.558f, -0.477f, 0.0f, -0.176f, 0.558f, 0.558f, + -0.484f, 0.0f, -0.174f, 0.557f, 0.558f, -0.493f, 0.0f, -0.17f, 0.555f, 0.559f, +}; + + +static const float data1[136 * GP_PRIM_DATABUF_SIZE] = { + -0.369f, 0.0f, -0.048f, 0.065f, 0.065f, -0.378f, 0.0f, -0.046f, 0.239f, 0.293f, -0.383f, 0.0f, -0.044f, 0.316f, 0.339f, -0.39f, 0.0f, -0.041f, 0.348f, 0.355f, + -0.398f, 0.0f, -0.038f, 0.364f, 0.368f, -0.405f, 0.0f, -0.035f, 0.373f, 0.374f, -0.413f, 0.0f, -0.031f, 0.381f, 0.381f, -0.421f, 0.0f, -0.026f, 0.388f, 0.391f, + -0.429f, 0.0f, -0.02f, 0.392f, 0.394f, -0.437f, 0.0f, -0.014f, 0.395f, 0.396f, -0.445f, 0.0f, -0.008f, 0.397f, 0.397f, -0.453f, 0.0f, -0.001f, 0.399f, 0.4f, + -0.461f, 0.0f, 0.007f, 0.401f, 0.401f, -0.468f, -0.0f, 0.016f, 0.404f, 0.404f, -0.474f, 0.0f, 0.023f, 0.406f, 0.407f, -0.479f, 0.0f, 0.03f, 0.409f, 0.409f, + -0.485f, 0.0f, 0.039f, 0.412f, 0.412f, -0.49f, 0.0f, 0.048f, 0.415f, 0.415f, -0.495f, 0.0f, 0.057f, 0.417f, 0.417f, -0.499f, 0.0f, 0.068f, 0.42f, 0.421f, + -0.503f, 0.0f, 0.079f, 0.421f, 0.421f, -0.507f, -0.0f, 0.091f, 0.423f, 0.423f, -0.51f, -0.0f, 0.102f, 0.424f, 0.424f, -0.513f, -0.0f, 0.112f, 0.424f, 0.425f, + -0.515f, -0.0f, 0.123f, 0.425f, 0.425f, -0.517f, -0.0f, 0.135f, 0.425f, 0.425f, -0.518f, -0.0f, 0.146f, 0.426f, 0.425f, -0.519f, -0.0f, 0.158f, 0.426f, 0.425f, + -0.52f, -0.0f, 0.169f, 0.426f, 0.426f, -0.52f, -0.0f, 0.181f, 0.427f, 0.427f, -0.519f, -0.0f, 0.192f, 0.427f, 0.427f, -0.518f, -0.0f, 0.203f, 0.427f, 0.427f, + -0.517f, -0.0f, 0.213f, 0.427f, 0.428f, -0.515f, -0.0f, 0.222f, 0.428f, 0.427f, -0.513f, -0.0f, 0.232f, 0.428f, 0.427f, -0.51f, -0.0f, 0.241f, 0.429f, 0.427f, + -0.508f, -0.0f, 0.25f, 0.43f, 0.428f, -0.505f, -0.0f, 0.259f, 0.431f, 0.431f, -0.501f, -0.0f, 0.267f, 0.431f, 0.432f, -0.497f, -0.0f, 0.276f, 0.432f, 0.433f, + -0.493f, -0.0f, 0.284f, 0.433f, 0.433f, -0.488f, -0.0f, 0.293f, 0.434f, 0.434f, -0.484f, -0.0f, 0.301f, 0.434f, 0.435f, -0.479f, -0.0f, 0.308f, 0.435f, 0.436f, + -0.474f, -0.0f, 0.316f, 0.435f, 0.435f, -0.468f, -0.0f, 0.322f, 0.436f, 0.436f, -0.463f, -0.0f, 0.329f, 0.436f, 0.436f, -0.457f, -0.0f, 0.335f, 0.436f, 0.436f, + -0.451f, -0.0f, 0.341f, 0.437f, 0.436f, -0.445f, -0.0f, 0.347f, 0.438f, 0.437f, -0.438f, -0.0f, 0.352f, 0.44f, 0.437f, -0.432f, -0.0f, 0.357f, 0.442f, 0.441f, + -0.426f, 0.0f, 0.362f, 0.444f, 0.446f, -0.419f, 0.0f, 0.366f, 0.445f, 0.447f, -0.413f, 0.0f, 0.369f, 0.446f, 0.447f, -0.407f, 0.0f, 0.373f, 0.446f, 0.447f, + -0.401f, 0.0f, 0.376f, 0.447f, 0.447f, -0.395f, 0.0f, 0.378f, 0.447f, 0.448f, -0.388f, 0.0f, 0.381f, 0.447f, 0.448f, -0.382f, 0.0f, 0.383f, 0.448f, 0.448f, + -0.375f, 0.0f, 0.384f, 0.448f, 0.448f, -0.369f, 0.0f, 0.386f, 0.448f, 0.448f, -0.362f, 0.0f, 0.387f, 0.448f, 0.448f, -0.355f, 0.0f, 0.388f, 0.448f, 0.448f, + -0.348f, 0.0f, 0.388f, 0.448f, 0.448f, -0.341f, 0.0f, 0.387f, 0.448f, 0.449f, -0.334f, 0.0f, 0.387f, 0.448f, 0.448f, -0.327f, 0.0f, 0.386f, 0.448f, 0.449f, + -0.32f, 0.0f, 0.384f, 0.449f, 0.449f, -0.313f, 0.0f, 0.382f, 0.449f, 0.449f, -0.307f, 0.0f, 0.38f, 0.449f, 0.449f, -0.3f, 0.0f, 0.377f, 0.449f, 0.45f, + -0.294f, 0.0f, 0.375f, 0.45f, 0.45f, -0.288f, -0.0f, 0.372f, 0.45f, 0.45f, -0.282f, -0.0f, 0.368f, 0.45f, 0.451f, -0.276f, -0.0f, 0.365f, 0.45f, 0.451f, + -0.27f, -0.0f, 0.361f, 0.45f, 0.451f, -0.264f, -0.0f, 0.357f, 0.45f, 0.451f, -0.258f, -0.0f, 0.352f, 0.45f, 0.45f, -0.251f, -0.0f, 0.347f, 0.45f, 0.451f, + -0.245f, -0.0f, 0.341f, 0.451f, 0.451f, -0.24f, -0.0f, 0.335f, 0.451f, 0.451f, -0.234f, -0.0f, 0.329f, 0.451f, 0.451f, -0.228f, -0.0f, 0.323f, 0.452f, 0.452f, + -0.223f, -0.0f, 0.316f, 0.452f, 0.453f, -0.218f, -0.0f, 0.309f, 0.452f, 0.453f, -0.213f, -0.0f, 0.301f, 0.453f, 0.453f, -0.208f, -0.0f, 0.294f, 0.453f, 0.453f, + -0.204f, -0.0f, 0.286f, 0.453f, 0.453f, -0.2f, -0.0f, 0.277f, 0.453f, 0.454f, -0.196f, -0.0f, 0.269f, 0.453f, 0.454f, -0.192f, -0.0f, 0.26f, 0.454f, 0.454f, + -0.189f, -0.0f, 0.25f, 0.454f, 0.454f, -0.186f, -0.0f, 0.241f, 0.454f, 0.455f, -0.183f, -0.0f, 0.231f, 0.454f, 0.455f, -0.181f, -0.0f, 0.221f, 0.454f, 0.455f, + -0.179f, -0.0f, 0.209f, 0.455f, 0.455f, -0.177f, -0.0f, 0.197f, 0.455f, 0.455f, -0.176f, -0.0f, 0.184f, 0.455f, 0.455f, -0.176f, -0.0f, 0.171f, 0.455f, 0.456f, + -0.176f, -0.0f, 0.158f, 0.455f, 0.456f, -0.177f, -0.0f, 0.145f, 0.455f, 0.456f, -0.178f, -0.0f, 0.132f, 0.455f, 0.456f, -0.18f, -0.0f, 0.12f, 0.456f, 0.456f, + -0.182f, -0.0f, 0.108f, 0.456f, 0.456f, -0.185f, -0.0f, 0.097f, 0.456f, 0.456f, -0.188f, -0.0f, 0.086f, 0.456f, 0.457f, -0.191f, -0.0f, 0.076f, 0.456f, 0.457f, + -0.194f, -0.0f, 0.067f, 0.457f, 0.457f, -0.198f, -0.0f, 0.058f, 0.457f, 0.457f, -0.202f, -0.0f, 0.05f, 0.457f, 0.457f, -0.206f, -0.0f, 0.042f, 0.457f, 0.457f, + -0.21f, -0.0f, 0.034f, 0.458f, 0.457f, -0.215f, -0.0f, 0.027f, 0.458f, 0.457f, -0.22f, -0.0f, 0.02f, 0.458f, 0.458f, -0.225f, -0.0f, 0.014f, 0.458f, 0.458f, + -0.23f, -0.0f, 0.007f, 0.458f, 0.458f, -0.235f, -0.0f, 0.002f, 0.459f, 0.458f, -0.24f, -0.0f, -0.004f, 0.459f, 0.458f, -0.246f, -0.0f, -0.009f, 0.46f, 0.459f, + -0.251f, 0.0f, -0.013f, 0.464f, 0.463f, -0.257f, 0.0f, -0.018f, 0.467f, 0.468f, -0.262f, 0.0f, -0.022f, 0.469f, 0.469f, -0.268f, 0.0f, -0.026f, 0.471f, 0.47f, + -0.274f, 0.0f, -0.029f, 0.477f, 0.478f, -0.28f, 0.0f, -0.033f, 0.478f, 0.478f, -0.286f, 0.0f, -0.036f, 0.478f, 0.478f, -0.292f, 0.0f, -0.038f, 0.479f, 0.479f, + -0.298f, 0.0f, -0.041f, 0.48f, 0.48f, -0.305f, 0.0f, -0.043f, 0.48f, 0.48f, -0.311f, 0.0f, -0.045f, 0.482f, 0.482f, -0.318f, 0.0f, -0.047f, 0.482f, 0.482f, + -0.324f, 0.0f, -0.048f, 0.482f, 0.482f, -0.331f, 0.0f, -0.049f, 0.48f, 0.482f, -0.336f, 0.0f, -0.05f, 0.457f, 0.485f, -0.344f, 0.0f, -0.05f, 0.32f, 0.32f, +}; + +static const float data2[2 * GP_PRIM_DATABUF_SIZE] = { + -0.512f, 0.0f, -0.168f, 0.545f, 0.557f, -0.521f, 0.0f, -0.167f, 0.535f, 0.558f, +}; + +static const float data3[1 * GP_PRIM_DATABUF_SIZE] = { + -1.014f, 0.0f, 0.186f, 0.0f, 0.003f, +}; + +static const float data4[1 * GP_PRIM_DATABUF_SIZE] = { + -1.014f, 0.0f, 0.186f, 0.02f, 0.02f, +}; + +static const float data5[48 * GP_PRIM_DATABUF_SIZE] = { + -1.014f, 0.0f, 0.187f, 0.066f, 0.066f, -1.013f, 0.0f, 0.2f, 0.222f, 0.356f, -1.01f, 0.0f, 0.208f, 0.295f, 0.404f, -1.006f, 0.0f, 0.218f, 0.354f, 0.431f, + -1.001f, 0.0f, 0.226f, 0.392f, 0.445f, -0.994f, 0.0f, 0.233f, 0.418f, 0.453f, -0.987f, 0.0f, 0.238f, 0.437f, 0.457f, -0.979f, 0.0f, 0.242f, 0.45f, 0.47f, + -0.97f, 0.0f, 0.245f, 0.459f, 0.473f, -0.96f, -0.0f, 0.246f, 0.465f, 0.474f, -0.951f, -0.0f, 0.245f, 0.469f, 0.475f, -0.942f, 0.0f, 0.242f, 0.471f, 0.473f, + -0.932f, 0.0f, 0.239f, 0.472f, 0.474f, -0.924f, 0.0f, 0.234f, 0.471f, 0.474f, -0.915f, 0.0f, 0.228f, 0.469f, 0.474f, -0.906f, 0.0f, 0.22f, 0.464f, 0.47f, + -0.898f, 0.0f, 0.212f, 0.458f, 0.46f, -0.89f, 0.0f, 0.203f, 0.451f, 0.453f, -0.882f, 0.0f, 0.193f, 0.443f, 0.443f, -0.875f, 0.0f, 0.182f, 0.435f, 0.437f, + -0.869f, 0.0f, 0.172f, 0.426f, 0.428f, -0.863f, 0.0f, 0.161f, 0.417f, 0.415f, -0.858f, 0.0f, 0.148f, 0.409f, 0.41f, -0.854f, 0.0f, 0.137f, 0.399f, 0.399f, + -0.85f, 0.0f, 0.126f, 0.39f, 0.392f, -0.847f, 0.0f, 0.116f, 0.379f, 0.386f, -0.846f, 0.0f, 0.109f, 0.369f, 0.371f, -0.846f, 0.0f, 0.104f, 0.361f, 0.357f, + -0.847f, 0.0f, 0.101f, 0.355f, 0.339f, -0.849f, 0.0f, 0.101f, 0.353f, 0.334f, -0.853f, 0.0f, 0.103f, 0.354f, 0.345f, -0.859f, 0.0f, 0.108f, 0.357f, 0.35f, + -0.865f, 0.0f, 0.116f, 0.363f, 0.365f, -0.873f, 0.0f, 0.126f, 0.369f, 0.375f, -0.881f, 0.0f, 0.137f, 0.375f, 0.379f, -0.89f, 0.0f, 0.149f, 0.381f, 0.38f, + -0.899f, 0.0f, 0.159f, 0.387f, 0.385f, -0.908f, 0.0f, 0.168f, 0.394f, 0.394f, -0.919f, 0.0f, 0.177f, 0.401f, 0.398f, -0.932f, 0.0f, 0.184f, 0.409f, 0.404f, + -0.945f, 0.0f, 0.191f, 0.418f, 0.415f, -0.958f, 0.0f, 0.195f, 0.427f, 0.431f, -0.969f, 0.0f, 0.197f, 0.434f, 0.443f, -0.979f, 0.0f, 0.197f, 0.436f, 0.445f, + -0.987f, 0.0f, 0.195f, 0.428f, 0.463f, -0.995f, 0.0f, 0.192f, 0.398f, 0.46f, -1.001f, 0.0f, 0.189f, 0.345f, 0.465f, -1.01f, 0.0f, 0.183f, 0.236f, 0.236f, +}; + +static const float data6[47 * GP_PRIM_DATABUF_SIZE] = { + 0.022f, 0.0f, -0.353f, 0.125f, 0.125f, 0.012f, 0.0f, -0.352f, 0.175f, 0.288f, 0.004f, 0.0f, -0.352f, 0.206f, 0.313f, -0.006f, 0.0f, -0.352f, 0.241f, 0.323f, + -0.017f, 0.0f, -0.352f, 0.27f, 0.33f, -0.029f, 0.0f, -0.351f, 0.295f, 0.334f, -0.041f, 0.0f, -0.349f, 0.314f, 0.337f, -0.052f, 0.0f, -0.344f, 0.327f, 0.341f, + -0.063f, 0.0f, -0.337f, 0.336f, 0.344f, -0.072f, 0.0f, -0.329f, 0.341f, 0.345f, -0.081f, 0.0f, -0.32f, 0.345f, 0.345f, -0.088f, 0.0f, -0.311f, 0.348f, 0.345f, + -0.093f, 0.0f, -0.303f, 0.352f, 0.347f, -0.098f, 0.0f, -0.295f, 0.356f, 0.352f, -0.101f, 0.0f, -0.287f, 0.361f, 0.357f, -0.102f, 0.0f, -0.279f, 0.367f, 0.364f, + -0.103f, 0.0f, -0.271f, 0.373f, 0.378f, -0.102f, 0.0f, -0.263f, 0.379f, 0.382f, -0.1f, 0.0f, -0.255f, 0.383f, 0.389f, -0.098f, 0.0f, -0.247f, 0.387f, 0.391f, + -0.094f, 0.0f, -0.24f, 0.389f, 0.393f, -0.09f, 0.0f, -0.233f, 0.391f, 0.393f, -0.086f, 0.0f, -0.227f, 0.392f, 0.393f, -0.082f, 0.0f, -0.222f, 0.393f, 0.393f, + -0.078f, 0.0f, -0.219f, 0.394f, 0.393f, -0.075f, 0.0f, -0.217f, 0.397f, 0.393f, -0.072f, 0.0f, -0.217f, 0.4f, 0.393f, -0.07f, 0.0f, -0.219f, 0.402f, 0.408f, + -0.069f, 0.0f, -0.222f, 0.404f, 0.408f, -0.069f, 0.0f, -0.228f, 0.406f, 0.409f, -0.069f, 0.0f, -0.234f, 0.407f, 0.409f, -0.07f, 0.0f, -0.241f, 0.408f, 0.409f, + -0.07f, 0.0f, -0.248f, 0.408f, 0.409f, -0.07f, 0.0f, -0.256f, 0.409f, 0.409f, -0.07f, 0.0f, -0.263f, 0.409f, 0.41f, -0.069f, 0.0f, -0.271f, 0.41f, 0.411f, + -0.068f, 0.0f, -0.279f, 0.41f, 0.411f, -0.065f, 0.0f, -0.287f, 0.41f, 0.411f, -0.062f, 0.0f, -0.295f, 0.409f, 0.411f, -0.057f, 0.0f, -0.303f, 0.409f, 0.409f, + -0.052f, 0.0f, -0.31f, 0.408f, 0.409f, -0.047f, 0.0f, -0.318f, 0.407f, 0.408f, -0.041f, 0.0f, -0.324f, 0.406f, 0.407f, -0.035f, 0.0f, -0.329f, 0.403f, 0.407f, + -0.027f, 0.0f, -0.333f, 0.4f, 0.408f, -0.021f, 0.0f, -0.336f, 0.398f, 0.403f, -0.012f, 0.0f, -0.339f, 0.393f, 0.393f, +}; + +static const float data7[162 * GP_PRIM_DATABUF_SIZE] = { + -0.291f, 0.0f, -0.34f, 0.093f, 0.093f, -0.289f, -0.0f, -0.35f, 0.149f, 0.176f, -0.287f, -0.0f, -0.357f, 0.182f, 0.242f, -0.284f, -0.0f, -0.365f, 0.215f, 0.257f, + -0.281f, -0.0f, -0.374f, 0.242f, 0.266f, -0.278f, -0.0f, -0.384f, 0.266f, 0.287f, -0.275f, -0.0f, -0.394f, 0.285f, 0.304f, -0.271f, 0.0f, -0.405f, 0.302f, 0.316f, + -0.267f, 0.0f, -0.417f, 0.317f, 0.326f, -0.263f, 0.0f, -0.429f, 0.33f, 0.337f, -0.259f, 0.0f, -0.442f, 0.342f, 0.346f, -0.256f, 0.0f, -0.454f, 0.354f, 0.351f, + -0.253f, 0.0f, -0.467f, 0.365f, 0.362f, -0.251f, 0.0f, -0.48f, 0.376f, 0.38f, -0.249f, -0.0f, -0.493f, 0.386f, 0.391f, -0.247f, -0.0f, -0.505f, 0.394f, 0.396f, + -0.246f, -0.0f, -0.518f, 0.401f, 0.405f, -0.245f, 0.0f, -0.53f, 0.408f, 0.409f, -0.245f, 0.0f, -0.542f, 0.415f, 0.413f, -0.245f, 0.0f, -0.554f, 0.421f, 0.42f, + -0.245f, 0.0f, -0.565f, 0.426f, 0.43f, -0.246f, 0.0f, -0.575f, 0.43f, 0.433f, -0.246f, -0.0f, -0.585f, 0.432f, 0.435f, -0.247f, -0.0f, -0.594f, 0.434f, 0.436f, + -0.247f, -0.0f, -0.603f, 0.435f, 0.436f, -0.248f, -0.0f, -0.612f, 0.436f, 0.436f, -0.25f, -0.0f, -0.621f, 0.437f, 0.438f, -0.252f, -0.0f, -0.631f, 0.437f, 0.438f, + -0.254f, -0.0f, -0.642f, 0.438f, 0.438f, -0.255f, 0.0f, -0.653f, 0.438f, 0.438f, -0.258f, 0.0f, -0.664f, 0.438f, 0.439f, -0.26f, 0.0f, -0.674f, 0.439f, 0.439f, + -0.261f, 0.0f, -0.685f, 0.439f, 0.439f, -0.262f, 0.0f, -0.696f, 0.439f, 0.439f, -0.264f, 0.0f, -0.706f, 0.439f, 0.439f, -0.265f, 0.0f, -0.717f, 0.439f, 0.439f, + -0.265f, 0.0f, -0.727f, 0.438f, 0.439f, -0.266f, 0.0f, -0.738f, 0.437f, 0.439f, -0.266f, 0.0f, -0.749f, 0.435f, 0.438f, -0.266f, 0.0f, -0.76f, 0.433f, 0.433f, + -0.265f, 0.0f, -0.771f, 0.431f, 0.428f, -0.265f, 0.0f, -0.781f, 0.43f, 0.428f, -0.263f, 0.0f, -0.792f, 0.429f, 0.428f, -0.26f, 0.0f, -0.802f, 0.428f, 0.429f, + -0.257f, 0.0f, -0.812f, 0.426f, 0.427f, -0.254f, 0.0f, -0.821f, 0.423f, 0.426f, -0.25f, 0.0f, -0.829f, 0.421f, 0.42f, -0.247f, 0.0f, -0.837f, 0.418f, 0.416f, + -0.242f, 0.0f, -0.844f, 0.417f, 0.415f, -0.238f, 0.0f, -0.85f, 0.415f, 0.413f, -0.234f, 0.0f, -0.857f, 0.415f, 0.413f, -0.229f, 0.0f, -0.864f, 0.414f, 0.413f, + -0.224f, 0.0f, -0.87f, 0.414f, 0.413f, -0.219f, 0.0f, -0.877f, 0.414f, 0.414f, -0.214f, 0.0f, -0.883f, 0.414f, 0.413f, -0.208f, 0.0f, -0.89f, 0.413f, 0.413f, + -0.203f, 0.0f, -0.897f, 0.413f, 0.413f, -0.197f, 0.0f, -0.903f, 0.413f, 0.413f, -0.191f, 0.0f, -0.909f, 0.413f, 0.413f, -0.186f, 0.0f, -0.914f, 0.413f, 0.413f, + -0.181f, 0.0f, -0.92f, 0.413f, 0.413f, -0.175f, -0.0f, -0.925f, 0.413f, 0.413f, -0.17f, -0.0f, -0.931f, 0.413f, 0.413f, -0.164f, -0.0f, -0.936f, 0.413f, 0.413f, + -0.159f, -0.0f, -0.942f, 0.413f, 0.413f, -0.152f, -0.0f, -0.948f, 0.413f, 0.413f, -0.145f, -0.0f, -0.955f, 0.413f, 0.413f, -0.137f, -0.0f, -0.961f, 0.414f, 0.413f, + -0.13f, -0.0f, -0.967f, 0.414f, 0.413f, -0.122f, -0.0f, -0.974f, 0.414f, 0.414f, -0.114f, -0.0f, -0.979f, 0.414f, 0.413f, -0.106f, -0.0f, -0.985f, 0.414f, 0.413f, + -0.098f, -0.0f, -0.989f, 0.414f, 0.414f, -0.091f, -0.0f, -0.993f, 0.414f, 0.413f, -0.083f, -0.0f, -0.997f, 0.414f, 0.414f, -0.075f, -0.0f, -0.999f, 0.414f, 0.414f, + -0.066f, -0.0f, -1.001f, 0.414f, 0.414f, -0.057f, -0.0f, -1.003f, 0.414f, 0.413f, -0.046f, -0.0f, -1.006f, 0.414f, 0.413f, -0.038f, -0.0f, -1.008f, 0.414f, 0.413f, + -0.031f, -0.0f, -1.009f, 0.421f, 0.413f, -0.036f, -0.0f, -1.008f, 0.423f, 0.424f, -0.045f, -0.0f, -1.006f, 0.425f, 0.425f, -0.054f, -0.0f, -1.005f, 0.425f, 0.425f, + -0.064f, -0.0f, -1.005f, 0.425f, 0.425f, -0.073f, -0.0f, -1.004f, 0.425f, 0.425f, -0.084f, -0.0f, -1.003f, 0.425f, 0.425f, -0.095f, -0.0f, -1.001f, 0.424f, 0.424f, + -0.105f, -0.0f, -0.997f, 0.423f, 0.424f, -0.116f, -0.0f, -0.994f, 0.422f, 0.422f, -0.127f, -0.0f, -0.991f, 0.421f, 0.419f, -0.137f, -0.0f, -0.987f, 0.42f, 0.419f, + -0.148f, -0.0f, -0.983f, 0.42f, 0.419f, -0.158f, -0.0f, -0.98f, 0.42f, 0.419f, -0.167f, -0.0f, -0.976f, 0.419f, 0.419f, -0.176f, -0.0f, -0.973f, 0.419f, 0.419f, + -0.184f, -0.0f, -0.969f, 0.419f, 0.419f, -0.192f, -0.0f, -0.966f, 0.419f, 0.418f, -0.2f, 0.0f, -0.962f, 0.419f, 0.418f, -0.207f, 0.0f, -0.957f, 0.419f, 0.419f, + -0.215f, 0.0f, -0.953f, 0.419f, 0.418f, -0.223f, 0.0f, -0.948f, 0.419f, 0.419f, -0.231f, 0.0f, -0.944f, 0.419f, 0.419f, -0.239f, 0.0f, -0.939f, 0.419f, 0.419f, + -0.247f, 0.0f, -0.934f, 0.419f, 0.419f, -0.255f, 0.0f, -0.929f, 0.419f, 0.419f, -0.262f, 0.0f, -0.924f, 0.419f, 0.419f, -0.269f, 0.0f, -0.919f, 0.419f, 0.418f, + -0.275f, 0.0f, -0.914f, 0.419f, 0.419f, -0.281f, 0.0f, -0.909f, 0.419f, 0.418f, -0.287f, 0.0f, -0.904f, 0.419f, 0.418f, -0.293f, 0.0f, -0.899f, 0.419f, 0.418f, + -0.299f, 0.0f, -0.894f, 0.42f, 0.419f, -0.304f, 0.0f, -0.888f, 0.421f, 0.42f, -0.311f, 0.0f, -0.882f, 0.423f, 0.422f, -0.317f, 0.0f, -0.876f, 0.424f, 0.424f, + -0.322f, 0.0f, -0.869f, 0.426f, 0.426f, -0.328f, 0.0f, -0.861f, 0.427f, 0.427f, -0.332f, 0.0f, -0.853f, 0.429f, 0.429f, -0.336f, 0.0f, -0.843f, 0.43f, 0.429f, + -0.339f, 0.0f, -0.834f, 0.432f, 0.431f, -0.341f, 0.0f, -0.821f, 0.435f, 0.434f, -0.342f, 0.0f, -0.809f, 0.438f, 0.439f, -0.343f, 0.0f, -0.796f, 0.44f, 0.44f, + -0.343f, 0.0f, -0.783f, 0.442f, 0.442f, -0.343f, 0.0f, -0.772f, 0.446f, 0.445f, -0.342f, 0.0f, -0.76f, 0.45f, 0.45f, -0.342f, 0.0f, -0.748f, 0.454f, 0.455f, + -0.34f, 0.0f, -0.735f, 0.457f, 0.457f, -0.339f, 0.0f, -0.723f, 0.46f, 0.46f, -0.338f, 0.0f, -0.711f, 0.463f, 0.464f, -0.336f, 0.0f, -0.7f, 0.465f, 0.465f, + -0.335f, 0.0f, -0.688f, 0.466f, 0.466f, -0.332f, 0.0f, -0.676f, 0.467f, 0.467f, -0.331f, 0.0f, -0.664f, 0.467f, 0.467f, -0.33f, 0.0f, -0.651f, 0.467f, 0.467f, + -0.328f, 0.0f, -0.638f, 0.467f, 0.467f, -0.325f, 0.0f, -0.625f, 0.467f, 0.467f, -0.323f, 0.0f, -0.614f, 0.467f, 0.467f, -0.321f, 0.0f, -0.603f, 0.467f, 0.466f, + -0.318f, 0.0f, -0.592f, 0.467f, 0.466f, -0.315f, 0.0f, -0.581f, 0.467f, 0.466f, -0.313f, 0.0f, -0.569f, 0.467f, 0.467f, -0.311f, -0.0f, -0.557f, 0.467f, 0.467f, + -0.309f, -0.0f, -0.543f, 0.467f, 0.467f, -0.306f, -0.0f, -0.531f, 0.467f, 0.467f, -0.303f, -0.0f, -0.519f, 0.467f, 0.467f, -0.301f, -0.0f, -0.507f, 0.467f, 0.468f, + -0.299f, -0.0f, -0.497f, 0.467f, 0.467f, -0.297f, -0.0f, -0.487f, 0.467f, 0.467f, -0.295f, 0.0f, -0.476f, 0.465f, 0.467f, -0.293f, 0.0f, -0.466f, 0.463f, 0.467f, + -0.292f, 0.0f, -0.456f, 0.46f, 0.466f, -0.291f, 0.0f, -0.445f, 0.455f, 0.459f, -0.29f, 0.0f, -0.435f, 0.449f, 0.457f, -0.29f, 0.0f, -0.424f, 0.44f, 0.448f, + -0.29f, 0.0f, -0.413f, 0.43f, 0.44f, -0.29f, 0.0f, -0.403f, 0.418f, 0.437f, -0.29f, -0.0f, -0.393f, 0.404f, 0.415f, -0.291f, -0.0f, -0.384f, 0.388f, 0.393f, + -0.29f, -0.0f, -0.376f, 0.374f, 0.379f, -0.29f, -0.0f, -0.365f, 0.352f, 0.352f, +}; + +static const float data8[55 * GP_PRIM_DATABUF_SIZE] = { + 0.781f, 0.0f, 0.098f, 0.109f, 0.109f, 0.784f, 0.0f, 0.105f, 0.202f, 0.338f, 0.785f, 0.0f, 0.108f, 0.254f, 0.369f, 0.787f, 0.0f, 0.113f, 0.306f, 0.382f, + 0.787f, 0.0f, 0.118f, 0.344f, 0.392f, 0.789f, 0.0f, 0.123f, 0.372f, 0.401f, 0.79f, 0.0f, 0.128f, 0.392f, 0.41f, 0.792f, 0.0f, 0.135f, 0.406f, 0.42f, + 0.794f, 0.0f, 0.142f, 0.416f, 0.424f, 0.797f, 0.0f, 0.152f, 0.424f, 0.428f, 0.801f, 0.0f, 0.161f, 0.429f, 0.431f, 0.807f, 0.0f, 0.172f, 0.432f, 0.435f, + 0.814f, 0.0f, 0.182f, 0.435f, 0.438f, 0.821f, 0.0f, 0.19f, 0.437f, 0.439f, 0.828f, 0.0f, 0.197f, 0.439f, 0.44f, 0.836f, 0.0f, 0.204f, 0.44f, 0.441f, + 0.845f, -0.0f, 0.211f, 0.44f, 0.441f, 0.853f, -0.0f, 0.215f, 0.441f, 0.441f, 0.861f, -0.0f, 0.219f, 0.441f, 0.441f, 0.87f, -0.0f, 0.222f, 0.441f, 0.442f, + 0.878f, -0.0f, 0.224f, 0.441f, 0.442f, 0.886f, -0.0f, 0.226f, 0.441f, 0.442f, 0.895f, -0.0f, 0.227f, 0.44f, 0.442f, 0.903f, 0.0f, 0.226f, 0.439f, 0.441f, + 0.911f, 0.0f, 0.225f, 0.436f, 0.441f, 0.919f, 0.0f, 0.224f, 0.432f, 0.441f, 0.927f, 0.0f, 0.221f, 0.425f, 0.436f, 0.934f, 0.0f, 0.218f, 0.415f, 0.429f, + 0.94f, 0.0f, 0.215f, 0.404f, 0.406f, 0.944f, 0.0f, 0.211f, 0.393f, 0.389f, 0.947f, 0.0f, 0.208f, 0.384f, 0.378f, 0.948f, 0.0f, 0.204f, 0.376f, 0.371f, + 0.946f, 0.0f, 0.2f, 0.369f, 0.364f, 0.943f, 0.0f, 0.196f, 0.365f, 0.358f, 0.937f, 0.0f, 0.193f, 0.364f, 0.354f, 0.931f, 0.0f, 0.189f, 0.366f, 0.359f, + 0.925f, 0.0f, 0.186f, 0.37f, 0.367f, 0.917f, 0.0f, 0.182f, 0.374f, 0.375f, 0.908f, 0.0f, 0.177f, 0.378f, 0.382f, 0.899f, 0.0f, 0.172f, 0.381f, 0.384f, + 0.889f, 0.0f, 0.167f, 0.384f, 0.385f, 0.876f, 0.0f, 0.163f, 0.387f, 0.387f, 0.864f, 0.0f, 0.156f, 0.39f, 0.388f, 0.852f, 0.0f, 0.15f, 0.393f, 0.39f, + 0.841f, 0.0f, 0.144f, 0.396f, 0.396f, 0.832f, 0.0f, 0.138f, 0.399f, 0.401f, 0.826f, 0.0f, 0.133f, 0.401f, 0.404f, 0.82f, 0.0f, 0.127f, 0.403f, 0.405f, + 0.816f, 0.0f, 0.122f, 0.403f, 0.407f, 0.812f, 0.0f, 0.119f, 0.399f, 0.406f, 0.808f, 0.0f, 0.115f, 0.39f, 0.405f, 0.805f, 0.0f, 0.113f, 0.371f, 0.407f, + 0.801f, 0.0f, 0.111f, 0.341f, 0.407f, 0.799f, 0.0f, 0.109f, 0.309f, 0.405f, 0.795f, 0.0f, 0.106f, 0.255f, 0.255f, +}; + +static const float data9[70 * GP_PRIM_DATABUF_SIZE] = { + 0.819f, -0.0f, 0.325f, 0.109f, 0.109f, 0.829f, -0.0f, 0.328f, 0.258f, 0.403f, 0.835f, -0.0f, 0.329f, 0.327f, 0.428f, 0.843f, -0.0f, 0.331f, 0.383f, 0.452f, + 0.851f, -0.0f, 0.332f, 0.419f, 0.465f, 0.861f, -0.0f, 0.334f, 0.444f, 0.473f, 0.87f, -0.0f, 0.336f, 0.461f, 0.48f, 0.881f, -0.0f, 0.337f, 0.473f, 0.486f, + 0.892f, -0.0f, 0.339f, 0.482f, 0.496f, 0.904f, -0.0f, 0.341f, 0.489f, 0.501f, 0.917f, -0.0f, 0.342f, 0.494f, 0.503f, 0.931f, -0.0f, 0.342f, 0.498f, 0.505f, + 0.945f, -0.0f, 0.342f, 0.501f, 0.505f, 0.958f, -0.0f, 0.342f, 0.503f, 0.506f, 0.971f, -0.0f, 0.341f, 0.505f, 0.506f, 0.984f, -0.0f, 0.341f, 0.506f, 0.506f, + 0.997f, -0.0f, 0.339f, 0.507f, 0.508f, 1.009f, -0.0f, 0.337f, 0.507f, 0.507f, 1.021f, -0.0f, 0.333f, 0.508f, 0.508f, 1.033f, -0.0f, 0.33f, 0.508f, 0.508f, + 1.044f, -0.0f, 0.326f, 0.508f, 0.508f, 1.056f, -0.0f, 0.322f, 0.508f, 0.508f, 1.068f, -0.0f, 0.317f, 0.508f, 0.508f, 1.078f, -0.0f, 0.311f, 0.507f, 0.508f, + 1.089f, -0.0f, 0.304f, 0.506f, 0.508f, 1.099f, 0.0f, 0.294f, 0.503f, 0.506f, 1.107f, 0.0f, 0.287f, 0.498f, 0.506f, 1.113f, 0.0f, 0.28f, 0.49f, 0.505f, + 1.117f, 0.0f, 0.276f, 0.48f, 0.501f, 1.121f, 0.0f, 0.272f, 0.468f, 0.492f, 1.124f, 0.0f, 0.27f, 0.455f, 0.467f, 1.127f, 0.0f, 0.27f, 0.443f, 0.431f, + 1.129f, 0.0f, 0.271f, 0.431f, 0.4f, 1.13f, 0.0f, 0.274f, 0.422f, 0.399f, 1.13f, 0.0f, 0.278f, 0.414f, 0.399f, 1.13f, 0.0f, 0.286f, 0.408f, 0.399f, + 1.128f, 0.0f, 0.295f, 0.404f, 0.399f, 1.124f, 0.0f, 0.305f, 0.402f, 0.399f, 1.119f, 0.0f, 0.316f, 0.403f, 0.4f, 1.113f, -0.0f, 0.327f, 0.405f, 0.401f, + 1.107f, -0.0f, 0.337f, 0.408f, 0.411f, 1.1f, -0.0f, 0.345f, 0.412f, 0.412f, 1.094f, -0.0f, 0.352f, 0.416f, 0.413f, 1.087f, -0.0f, 0.357f, 0.421f, 0.422f, + 1.08f, -0.0f, 0.363f, 0.426f, 0.428f, 1.071f, -0.0f, 0.368f, 0.429f, 0.43f, 1.062f, -0.0f, 0.373f, 0.431f, 0.431f, 1.051f, -0.0f, 0.377f, 0.433f, 0.431f, + 1.039f, -0.0f, 0.381f, 0.436f, 0.437f, 1.026f, -0.0f, 0.383f, 0.438f, 0.44f, 1.013f, -0.0f, 0.384f, 0.44f, 0.44f, 1.0f, -0.0f, 0.385f, 0.441f, 0.443f, + 0.987f, -0.0f, 0.385f, 0.442f, 0.443f, 0.975f, -0.0f, 0.384f, 0.443f, 0.443f, 0.962f, -0.0f, 0.383f, 0.443f, 0.444f, 0.949f, -0.0f, 0.381f, 0.443f, 0.443f, + 0.936f, -0.0f, 0.38f, 0.443f, 0.444f, 0.923f, -0.0f, 0.378f, 0.443f, 0.444f, 0.909f, -0.0f, 0.375f, 0.443f, 0.444f, 0.897f, -0.0f, 0.371f, 0.443f, 0.444f, + 0.886f, -0.0f, 0.367f, 0.443f, 0.443f, 0.876f, -0.0f, 0.363f, 0.443f, 0.444f, 0.868f, -0.0f, 0.359f, 0.443f, 0.442f, 0.86f, -0.0f, 0.355f, 0.442f, 0.443f, + 0.852f, -0.0f, 0.35f, 0.441f, 0.443f, 0.844f, -0.0f, 0.347f, 0.433f, 0.443f, 0.837f, -0.0f, 0.343f, 0.409f, 0.443f, 0.83f, -0.0f, 0.338f, 0.344f, 0.443f, + 0.824f, -0.0f, 0.335f, 0.239f, 0.437f, 0.815f, -0.0f, 0.326f, 0.0f, 0.003f, +}; + +static const float data10[227 * GP_PRIM_DATABUF_SIZE] = { + -0.675f, 0.0f, 0.411f, 0.099f, 0.099f, -0.669f, 0.0f, 0.418f, 0.358f, 0.358f, -0.666f, 0.0f, 0.424f, 0.381f, 0.381f, -0.662f, 0.0f, 0.431f, 0.389f, 0.389f, + -0.658f, 0.0f, 0.438f, 0.393f, 0.393f, -0.649f, 0.0f, 0.448f, 0.404f, 0.404f, -0.641f, 0.0f, 0.458f, 0.419f, 0.419f, -0.632f, 0.0f, 0.468f, 0.431f, 0.434f, + -0.626f, 0.0f, 0.476f, 0.435f, 0.436f, -0.62f, 0.0f, 0.484f, 0.437f, 0.438f, -0.615f, 0.0f, 0.492f, 0.439f, 0.439f, -0.61f, 0.0f, 0.499f, 0.439f, 0.44f, + -0.605f, 0.0f, 0.506f, 0.44f, 0.44f, -0.6f, 0.0f, 0.512f, 0.44f, 0.44f, -0.595f, 0.0f, 0.519f, 0.44f, 0.44f, -0.59f, 0.0f, 0.526f, 0.441f, 0.441f, + -0.584f, 0.0f, 0.532f, 0.441f, 0.441f, -0.579f, 0.0f, 0.539f, 0.441f, 0.441f, -0.573f, 0.0f, 0.545f, 0.442f, 0.442f, -0.566f, 0.0f, 0.551f, 0.443f, 0.443f, + -0.559f, 0.0f, 0.557f, 0.443f, 0.443f, -0.552f, 0.0f, 0.563f, 0.444f, 0.444f, -0.545f, 0.0f, 0.569f, 0.445f, 0.445f, -0.538f, 0.0f, 0.576f, 0.447f, 0.447f, + -0.532f, 0.0f, 0.582f, 0.448f, 0.448f, -0.525f, 0.0f, 0.589f, 0.45f, 0.45f, -0.519f, 0.0f, 0.595f, 0.451f, 0.452f, -0.513f, 0.0f, 0.602f, 0.452f, 0.453f, + -0.506f, 0.0f, 0.608f, 0.453f, 0.453f, -0.5f, 0.0f, 0.613f, 0.453f, 0.454f, -0.493f, 0.0f, 0.619f, 0.453f, 0.454f, -0.486f, 0.0f, 0.625f, 0.453f, 0.454f, + -0.479f, 0.0f, 0.631f, 0.453f, 0.454f, -0.472f, 0.0f, 0.637f, 0.453f, 0.454f, -0.464f, 0.0f, 0.642f, 0.453f, 0.454f, -0.457f, 0.0f, 0.649f, 0.453f, 0.454f, + -0.45f, 0.0f, 0.655f, 0.453f, 0.453f, -0.443f, 0.0f, 0.661f, 0.453f, 0.453f, -0.435f, 0.0f, 0.667f, 0.453f, 0.454f, -0.427f, 0.0f, 0.672f, 0.453f, 0.454f, + -0.419f, 0.0f, 0.677f, 0.453f, 0.454f, -0.411f, 0.0f, 0.682f, 0.453f, 0.453f, -0.403f, 0.0f, 0.688f, 0.453f, 0.453f, -0.395f, 0.0f, 0.692f, 0.453f, 0.454f, + -0.387f, 0.0f, 0.697f, 0.453f, 0.454f, -0.379f, 0.0f, 0.702f, 0.453f, 0.454f, -0.372f, 0.0f, 0.707f, 0.454f, 0.454f, -0.364f, 0.0f, 0.712f, 0.454f, 0.454f, + -0.356f, 0.0f, 0.716f, 0.454f, 0.454f, -0.349f, 0.0f, 0.721f, 0.454f, 0.454f, -0.342f, 0.0f, 0.725f, 0.454f, 0.454f, -0.334f, 0.0f, 0.73f, 0.454f, 0.454f, + -0.326f, 0.0f, 0.733f, 0.454f, 0.454f, -0.318f, 0.0f, 0.737f, 0.454f, 0.454f, -0.31f, 0.0f, 0.74f, 0.454f, 0.454f, -0.301f, 0.0f, 0.743f, 0.454f, 0.454f, + -0.293f, 0.0f, 0.746f, 0.454f, 0.455f, -0.284f, 0.0f, 0.749f, 0.454f, 0.455f, -0.274f, 0.0f, 0.752f, 0.455f, 0.455f, -0.265f, 0.0f, 0.755f, 0.455f, 0.455f, + -0.255f, 0.0f, 0.757f, 0.455f, 0.455f, -0.245f, 0.0f, 0.76f, 0.456f, 0.455f, -0.234f, 0.0f, 0.762f, 0.457f, 0.456f, -0.223f, 0.0f, 0.764f, 0.458f, 0.458f, + -0.212f, 0.0f, 0.766f, 0.459f, 0.46f, -0.201f, 0.0f, 0.769f, 0.461f, 0.46f, -0.189f, 0.0f, 0.771f, 0.462f, 0.461f, -0.177f, 0.0f, 0.773f, 0.464f, 0.463f, + -0.166f, 0.0f, 0.775f, 0.465f, 0.465f, -0.153f, 0.0f, 0.777f, 0.467f, 0.467f, -0.141f, 0.0f, 0.779f, 0.469f, 0.469f, -0.128f, 0.0f, 0.781f, 0.472f, 0.472f, + -0.116f, 0.0f, 0.782f, 0.474f, 0.473f, -0.101f, 0.0f, 0.782f, 0.477f, 0.477f, -0.087f, 0.0f, 0.783f, 0.482f, 0.477f, -0.073f, 0.0f, 0.783f, 0.489f, 0.483f, + -0.059f, 0.0f, 0.783f, 0.497f, 0.5f, -0.046f, 0.0f, 0.784f, 0.503f, 0.509f, -0.033f, 0.0f, 0.784f, 0.508f, 0.51f, -0.022f, 0.0f, 0.784f, 0.51f, 0.512f, + -0.011f, 0.0f, 0.785f, 0.512f, 0.512f, -0.0f, 0.0f, 0.786f, 0.513f, 0.512f, 0.011f, 0.0f, 0.786f, 0.515f, 0.513f, 0.022f, 0.0f, 0.786f, 0.517f, 0.517f, + 0.032f, 0.0f, 0.786f, 0.52f, 0.519f, 0.044f, 0.0f, 0.786f, 0.522f, 0.524f, 0.055f, 0.0f, 0.785f, 0.525f, 0.525f, 0.066f, 0.0f, 0.785f, 0.527f, 0.525f, + 0.076f, 0.0f, 0.784f, 0.53f, 0.53f, 0.086f, 0.0f, 0.783f, 0.532f, 0.533f, 0.097f, 0.0f, 0.782f, 0.535f, 0.534f, 0.108f, 0.0f, 0.782f, 0.538f, 0.541f, + 0.119f, 0.0f, 0.781f, 0.54f, 0.542f, 0.13f, 0.0f, 0.781f, 0.543f, 0.543f, 0.141f, 0.0f, 0.78f, 0.545f, 0.545f, 0.154f, 0.0f, 0.779f, 0.547f, 0.547f, + 0.165f, 0.0f, 0.777f, 0.549f, 0.548f, 0.177f, 0.0f, 0.775f, 0.55f, 0.552f, 0.188f, 0.0f, 0.772f, 0.552f, 0.552f, 0.199f, 0.0f, 0.77f, 0.553f, 0.553f, + 0.209f, 0.0f, 0.767f, 0.554f, 0.554f, 0.218f, 0.0f, 0.765f, 0.555f, 0.556f, 0.226f, 0.0f, 0.763f, 0.556f, 0.557f, 0.235f, 0.0f, 0.761f, 0.557f, 0.557f, + 0.244f, 0.0f, 0.758f, 0.558f, 0.558f, 0.253f, 0.0f, 0.755f, 0.559f, 0.559f, 0.263f, 0.0f, 0.752f, 0.56f, 0.559f, 0.272f, 0.0f, 0.749f, 0.561f, 0.56f, + 0.285f, 0.0f, 0.745f, 0.562f, 0.56f, 0.299f, 0.0f, 0.741f, 0.563f, 0.563f, 0.316f, 0.0f, 0.736f, 0.564f, 0.564f, 0.331f, 0.0f, 0.728f, 0.565f, 0.567f, + 0.349f, 0.0f, 0.718f, 0.565f, 0.568f, 0.365f, 0.0f, 0.708f, 0.566f, 0.568f, 0.38f, 0.0f, 0.699f, 0.566f, 0.568f, 0.39f, 0.0f, 0.693f, 0.566f, 0.568f, + 0.397f, 0.0f, 0.687f, 0.566f, 0.569f, 0.4f, 0.0f, 0.683f, 0.566f, 0.569f, 0.401f, 0.0f, 0.681f, 0.565f, 0.57f, 0.4f, 0.0f, 0.679f, 0.565f, 0.57f, + 0.397f, 0.0f, 0.678f, 0.564f, 0.57f, 0.393f, 0.0f, 0.678f, 0.564f, 0.565f, 0.387f, 0.0f, 0.678f, 0.563f, 0.559f, 0.379f, 0.0f, 0.679f, 0.562f, 0.558f, + 0.37f, 0.0f, 0.681f, 0.561f, 0.557f, 0.357f, 0.0f, 0.684f, 0.561f, 0.557f, 0.342f, 0.0f, 0.689f, 0.56f, 0.557f, 0.324f, 0.0f, 0.694f, 0.56f, 0.557f, + 0.307f, 0.0f, 0.697f, 0.559f, 0.558f, 0.291f, 0.0f, 0.699f, 0.559f, 0.558f, 0.274f, 0.0f, 0.701f, 0.559f, 0.557f, 0.26f, 0.0f, 0.703f, 0.558f, 0.558f, + 0.246f, 0.0f, 0.705f, 0.558f, 0.558f, 0.235f, 0.0f, 0.707f, 0.558f, 0.558f, 0.224f, 0.0f, 0.709f, 0.558f, 0.558f, 0.214f, 0.0f, 0.711f, 0.558f, 0.558f, + 0.203f, 0.0f, 0.713f, 0.558f, 0.559f, 0.192f, 0.0f, 0.714f, 0.558f, 0.558f, 0.181f, 0.0f, 0.714f, 0.557f, 0.557f, 0.17f, 0.0f, 0.714f, 0.557f, 0.557f, + 0.16f, 0.0f, 0.715f, 0.557f, 0.556f, 0.149f, 0.0f, 0.715f, 0.557f, 0.556f, 0.139f, 0.0f, 0.716f, 0.557f, 0.556f, 0.129f, 0.0f, 0.716f, 0.558f, 0.556f, + 0.119f, 0.0f, 0.717f, 0.558f, 0.556f, 0.109f, 0.0f, 0.717f, 0.558f, 0.557f, 0.099f, 0.0f, 0.718f, 0.558f, 0.557f, 0.089f, 0.0f, 0.718f, 0.559f, 0.557f, + 0.079f, 0.0f, 0.718f, 0.559f, 0.558f, 0.068f, 0.0f, 0.719f, 0.559f, 0.559f, 0.057f, 0.0f, 0.719f, 0.56f, 0.56f, 0.046f, 0.0f, 0.718f, 0.56f, 0.561f, + 0.035f, 0.0f, 0.718f, 0.561f, 0.561f, 0.024f, 0.0f, 0.718f, 0.561f, 0.562f, 0.013f, 0.0f, 0.717f, 0.562f, 0.562f, 0.002f, 0.0f, 0.717f, 0.562f, 0.563f, + -0.01f, 0.0f, 0.717f, 0.563f, 0.564f, -0.021f, 0.0f, 0.717f, 0.563f, 0.564f, -0.032f, 0.0f, 0.716f, 0.563f, 0.564f, -0.044f, 0.0f, 0.715f, 0.564f, 0.564f, + -0.055f, 0.0f, 0.714f, 0.564f, 0.565f, -0.066f, 0.0f, 0.713f, 0.564f, 0.565f, -0.078f, 0.0f, 0.712f, 0.564f, 0.564f, -0.089f, 0.0f, 0.711f, 0.564f, 0.564f, + -0.101f, 0.0f, 0.709f, 0.565f, 0.564f, -0.112f, 0.0f, 0.708f, 0.565f, 0.564f, -0.124f, 0.0f, 0.707f, 0.565f, 0.564f, -0.135f, 0.0f, 0.705f, 0.565f, 0.564f, + -0.146f, 0.0f, 0.704f, 0.566f, 0.564f, -0.158f, 0.0f, 0.702f, 0.566f, 0.564f, -0.169f, 0.0f, 0.7f, 0.566f, 0.566f, -0.18f, 0.0f, 0.698f, 0.567f, 0.568f, + -0.191f, 0.0f, 0.696f, 0.567f, 0.568f, -0.203f, 0.0f, 0.693f, 0.567f, 0.568f, -0.215f, 0.0f, 0.69f, 0.567f, 0.568f, -0.227f, 0.0f, 0.687f, 0.567f, 0.568f, + -0.238f, 0.0f, 0.684f, 0.567f, 0.568f, -0.25f, 0.0f, 0.681f, 0.567f, 0.569f, -0.262f, 0.0f, 0.678f, 0.567f, 0.569f, -0.273f, 0.0f, 0.675f, 0.567f, 0.567f, + -0.284f, 0.0f, 0.673f, 0.567f, 0.566f, -0.295f, 0.0f, 0.671f, 0.567f, 0.567f, -0.305f, 0.0f, 0.669f, 0.566f, 0.567f, -0.316f, 0.0f, 0.666f, 0.566f, 0.567f, + -0.326f, 0.0f, 0.663f, 0.565f, 0.566f, -0.337f, 0.0f, 0.66f, 0.565f, 0.566f, -0.348f, 0.0f, 0.655f, 0.564f, 0.564f, -0.359f, 0.0f, 0.652f, 0.563f, 0.564f, + -0.369f, 0.0f, 0.648f, 0.562f, 0.563f, -0.379f, 0.0f, 0.644f, 0.561f, 0.56f, -0.389f, 0.0f, 0.64f, 0.561f, 0.559f, -0.399f, 0.0f, 0.636f, 0.56f, 0.559f, + -0.409f, 0.0f, 0.633f, 0.559f, 0.559f, -0.419f, 0.0f, 0.629f, 0.559f, 0.559f, -0.428f, 0.0f, 0.625f, 0.559f, 0.558f, -0.438f, 0.0f, 0.62f, 0.559f, 0.559f, + -0.447f, 0.0f, 0.615f, 0.559f, 0.559f, -0.457f, 0.0f, 0.61f, 0.559f, 0.559f, -0.466f, 0.0f, 0.605f, 0.559f, 0.559f, -0.474f, 0.0f, 0.6f, 0.559f, 0.559f, + -0.483f, 0.0f, 0.595f, 0.559f, 0.559f, -0.492f, 0.0f, 0.591f, 0.559f, 0.559f, -0.5f, 0.0f, 0.586f, 0.559f, 0.559f, -0.508f, 0.0f, 0.58f, 0.559f, 0.559f, + -0.515f, 0.0f, 0.574f, 0.559f, 0.559f, -0.523f, 0.0f, 0.568f, 0.559f, 0.559f, -0.531f, 0.0f, 0.562f, 0.559f, 0.558f, -0.54f, 0.0f, 0.556f, 0.559f, 0.558f, + -0.548f, 0.0f, 0.549f, 0.559f, 0.559f, -0.556f, 0.0f, 0.543f, 0.559f, 0.559f, -0.562f, 0.0f, 0.537f, 0.559f, 0.559f, -0.568f, 0.0f, 0.531f, 0.559f, 0.559f, + -0.574f, 0.0f, 0.524f, 0.559f, 0.559f, -0.58f, 0.0f, 0.518f, 0.558f, 0.559f, -0.586f, 0.0f, 0.512f, 0.557f, 0.558f, -0.591f, 0.0f, 0.506f, 0.555f, 0.557f, + -0.597f, 0.0f, 0.5f, 0.551f, 0.556f, -0.603f, 0.0f, 0.493f, 0.546f, 0.547f, -0.609f, 0.0f, 0.487f, 0.541f, 0.538f, -0.614f, 0.0f, 0.48f, 0.536f, 0.535f, + -0.621f, 0.0f, 0.473f, 0.534f, 0.534f, -0.628f, 0.0f, 0.467f, 0.534f, 0.534f, -0.637f, 0.0f, 0.459f, 0.534f, 0.534f, -0.642f, 0.0f, 0.452f, 0.532f, 0.532f, + -0.65f, 0.0f, 0.445f, 0.528f, 0.528f, -0.654f, 0.0f, 0.438f, 0.525f, 0.525f, -0.659f, 0.0f, 0.431f, 0.522f, 0.522f, +}; + +static const float data11[1 * GP_PRIM_DATABUF_SIZE] = { + -0.525f, 0.0f, 0.174f, 0.124f, 0.124f, +}; + +static const float data12[123 * GP_PRIM_DATABUF_SIZE] = { + -0.53f, 0.0f, 0.193f, 0.147f, 0.147f, -0.532f, 0.0f, 0.186f, 0.316f, 0.316f, -0.534f, 0.0f, 0.18f, 0.353f, 0.353f, -0.535f, 0.0f, 0.173f, 0.382f, 0.382f, + -0.537f, 0.0f, 0.165f, 0.384f, 0.384f, -0.538f, 0.0f, 0.155f, 0.387f, 0.387f, -0.539f, 0.0f, 0.145f, 0.393f, 0.393f, -0.54f, -0.0f, 0.134f, 0.399f, 0.399f, + -0.541f, -0.0f, 0.123f, 0.4f, 0.4f, -0.542f, -0.0f, 0.11f, 0.401f, 0.401f, -0.542f, 0.0f, 0.094f, 0.402f, 0.402f, -0.54f, 0.0f, 0.078f, 0.403f, 0.403f, + -0.538f, 0.0f, 0.061f, 0.404f, 0.404f, -0.535f, 0.0f, 0.045f, 0.404f, 0.404f, -0.531f, 0.0f, 0.031f, 0.404f, 0.404f, -0.526f, 0.0f, 0.018f, 0.404f, 0.404f, + -0.52f, -0.0f, 0.005f, 0.405f, 0.405f, -0.513f, -0.0f, -0.01f, 0.405f, 0.405f, -0.505f, -0.0f, -0.024f, 0.405f, 0.405f, -0.495f, -0.0f, -0.037f, 0.405f, 0.405f, + -0.485f, 0.0f, -0.051f, 0.405f, 0.405f, -0.474f, 0.0f, -0.064f, 0.406f, 0.406f, -0.462f, 0.0f, -0.076f, 0.405f, 0.405f, -0.451f, 0.0f, -0.086f, 0.406f, 0.406f, + -0.442f, 0.0f, -0.094f, 0.406f, 0.406f, -0.432f, 0.0f, -0.102f, 0.406f, 0.406f, -0.422f, 0.0f, -0.108f, 0.405f, 0.405f, -0.411f, 0.0f, -0.114f, 0.406f, 0.406f, + -0.4f, 0.0f, -0.119f, 0.405f, 0.405f, -0.389f, 0.0f, -0.122f, 0.406f, 0.406f, -0.378f, 0.0f, -0.125f, 0.407f, 0.407f, -0.365f, 0.0f, -0.127f, 0.412f, 0.412f, + -0.354f, 0.0f, -0.129f, 0.418f, 0.418f, -0.342f, 0.0f, -0.131f, 0.44f, 0.44f, -0.33f, 0.0f, -0.131f, 0.448f, 0.448f, -0.317f, 0.0f, -0.131f, 0.469f, 0.469f, + -0.305f, 0.0f, -0.13f, 0.477f, 0.477f, -0.293f, 0.0f, -0.128f, 0.482f, 0.482f, -0.278f, 0.0f, -0.125f, 0.494f, 0.494f, -0.266f, 0.0f, -0.121f, 0.5f, 0.5f, + -0.253f, 0.0f, -0.116f, 0.507f, 0.507f, -0.242f, 0.0f, -0.111f, 0.509f, 0.509f, -0.231f, 0.0f, -0.105f, 0.511f, 0.511f, -0.222f, 0.0f, -0.099f, 0.511f, 0.511f, + -0.213f, 0.0f, -0.092f, 0.512f, 0.512f, -0.206f, 0.0f, -0.084f, 0.513f, 0.513f, -0.199f, 0.0f, -0.076f, 0.514f, 0.514f, -0.192f, 0.0f, -0.067f, 0.515f, 0.515f, + -0.186f, -0.0f, -0.058f, 0.516f, 0.516f, -0.18f, -0.0f, -0.049f, 0.516f, 0.516f, -0.175f, -0.0f, -0.04f, 0.515f, 0.515f, -0.17f, -0.0f, -0.03f, 0.515f, 0.515f, + -0.166f, -0.0f, -0.02f, 0.516f, 0.516f, -0.163f, -0.0f, -0.01f, 0.504f, 0.504f, -0.159f, -0.0f, 0.002f, 0.502f, 0.502f, -0.155f, -0.0f, 0.014f, 0.501f, 0.501f, + -0.152f, -0.0f, 0.027f, 0.502f, 0.502f, -0.149f, -0.0f, 0.043f, 0.5f, 0.5f, -0.148f, -0.0f, 0.058f, 0.49f, 0.49f, -0.147f, -0.0f, 0.075f, 0.47f, 0.47f, + -0.146f, -0.0f, 0.09f, 0.463f, 0.463f, -0.146f, -0.0f, 0.105f, 0.454f, 0.454f, -0.146f, -0.0f, 0.12f, 0.427f, 0.427f, -0.148f, 0.0f, 0.133f, 0.413f, 0.413f, + -0.15f, 0.0f, 0.144f, 0.4f, 0.4f, -0.153f, 0.0f, 0.152f, 0.383f, 0.383f, -0.156f, 0.0f, 0.157f, 0.369f, 0.369f, -0.158f, 0.0f, 0.16f, 0.36f, 0.36f, + -0.16f, 0.0f, 0.158f, 0.349f, 0.349f, -0.162f, 0.0f, 0.154f, 0.364f, 0.364f, -0.164f, 0.0f, 0.147f, 0.37f, 0.37f, -0.166f, 0.0f, 0.139f, 0.378f, 0.378f, + -0.168f, 0.0f, 0.13f, 0.386f, 0.386f, -0.172f, 0.0f, 0.119f, 0.394f, 0.394f, -0.176f, -0.0f, 0.108f, 0.405f, 0.405f, -0.18f, -0.0f, 0.096f, 0.412f, 0.412f, + -0.185f, -0.0f, 0.084f, 0.417f, 0.417f, -0.191f, -0.0f, 0.073f, 0.425f, 0.425f, -0.196f, -0.0f, 0.063f, 0.431f, 0.431f, -0.202f, -0.0f, 0.053f, 0.441f, 0.441f, + -0.208f, -0.0f, 0.043f, 0.444f, 0.444f, -0.214f, -0.0f, 0.034f, 0.451f, 0.451f, -0.22f, 0.0f, 0.026f, 0.46f, 0.46f, -0.226f, 0.0f, 0.018f, 0.463f, 0.463f, + -0.232f, 0.0f, 0.01f, 0.474f, 0.474f, -0.239f, 0.0f, 0.004f, 0.477f, 0.477f, -0.247f, 0.0f, -0.003f, 0.48f, 0.48f, -0.255f, 0.0f, -0.008f, 0.483f, 0.483f, + -0.264f, 0.0f, -0.013f, 0.497f, 0.497f, -0.274f, 0.0f, -0.018f, 0.501f, 0.501f, -0.285f, 0.0f, -0.022f, 0.505f, 0.505f, -0.297f, 0.0f, -0.024f, 0.509f, 0.509f, + -0.311f, 0.0f, -0.025f, 0.51f, 0.51f, -0.325f, 0.0f, -0.024f, 0.512f, 0.512f, -0.339f, 0.0f, -0.023f, 0.512f, 0.512f, -0.354f, 0.0f, -0.022f, 0.513f, 0.513f, + -0.368f, 0.0f, -0.02f, 0.513f, 0.513f, -0.382f, 0.0f, -0.017f, 0.514f, 0.514f, -0.397f, 0.0f, -0.013f, 0.514f, 0.514f, -0.41f, 0.0f, -0.007f, 0.514f, 0.514f, + -0.422f, 0.0f, 0.001f, 0.513f, 0.513f, -0.434f, 0.0f, 0.009f, 0.514f, 0.514f, -0.446f, 0.0f, 0.018f, 0.514f, 0.514f, -0.458f, 0.0f, 0.028f, 0.514f, 0.514f, + -0.47f, -0.0f, 0.039f, 0.514f, 0.514f, -0.48f, 0.0f, 0.048f, 0.514f, 0.514f, -0.487f, 0.0f, 0.057f, 0.514f, 0.514f, -0.493f, 0.0f, 0.068f, 0.514f, 0.514f, + -0.498f, 0.0f, 0.08f, 0.514f, 0.514f, -0.502f, 0.0f, 0.092f, 0.514f, 0.514f, -0.506f, 0.0f, 0.104f, 0.514f, 0.514f, -0.509f, -0.0f, 0.116f, 0.515f, 0.515f, + -0.511f, -0.0f, 0.125f, 0.515f, 0.515f, -0.513f, -0.0f, 0.133f, 0.515f, 0.515f, -0.515f, -0.0f, 0.141f, 0.515f, 0.515f, -0.517f, 0.0f, 0.148f, 0.515f, 0.515f, + -0.519f, 0.0f, 0.155f, 0.514f, 0.514f, -0.52f, 0.0f, 0.161f, 0.514f, 0.514f, -0.522f, 0.0f, 0.168f, 0.514f, 0.514f, -0.523f, 0.0f, 0.174f, 0.514f, 0.514f, + -0.525f, 0.0f, 0.18f, 0.514f, 0.514f, -0.526f, 0.0f, 0.185f, 0.514f, 0.514f, -0.527f, 0.0f, 0.191f, 0.513f, 0.513f, +}; + +static const float data13[125 * GP_PRIM_DATABUF_SIZE] = { + 0.184f, 0.0f, 0.22f, 0.026f, 0.026f, 0.182f, 0.0f, 0.21f, 0.275f, 0.275f, 0.18f, 0.0f, 0.203f, 0.301f, 0.301f, 0.178f, 0.0f, 0.195f, 0.322f, 0.322f, + 0.176f, 0.0f, 0.186f, 0.343f, 0.343f, 0.173f, 0.0f, 0.176f, 0.36f, 0.36f, 0.17f, -0.0f, 0.166f, 0.367f, 0.367f, 0.168f, -0.0f, 0.156f, 0.38f, 0.38f, + 0.165f, -0.0f, 0.145f, 0.385f, 0.385f, 0.163f, -0.0f, 0.132f, 0.391f, 0.391f, 0.161f, -0.0f, 0.119f, 0.401f, 0.401f, 0.16f, -0.0f, 0.103f, 0.405f, 0.405f, + 0.161f, -0.0f, 0.086f, 0.405f, 0.405f, 0.163f, -0.0f, 0.068f, 0.407f, 0.407f, 0.165f, 0.0f, 0.051f, 0.409f, 0.409f, 0.168f, 0.0f, 0.034f, 0.409f, 0.409f, + 0.172f, 0.0f, 0.018f, 0.409f, 0.409f, 0.177f, 0.0f, 0.004f, 0.409f, 0.409f, 0.183f, 0.0f, -0.008f, 0.411f, 0.411f, 0.19f, 0.0f, -0.022f, 0.411f, 0.411f, + 0.196f, 0.0f, -0.034f, 0.411f, 0.411f, 0.203f, 0.0f, -0.045f, 0.411f, 0.411f, 0.211f, 0.0f, -0.055f, 0.411f, 0.411f, 0.219f, 0.0f, -0.064f, 0.411f, 0.411f, + 0.227f, 0.0f, -0.072f, 0.411f, 0.411f, 0.235f, 0.0f, -0.08f, 0.412f, 0.412f, 0.244f, 0.0f, -0.087f, 0.412f, 0.412f, 0.253f, 0.0f, -0.094f, 0.413f, 0.413f, + 0.262f, 0.0f, -0.1f, 0.413f, 0.413f, 0.273f, 0.0f, -0.105f, 0.413f, 0.413f, 0.284f, 0.0f, -0.11f, 0.413f, 0.413f, 0.295f, 0.0f, -0.114f, 0.419f, 0.419f, + 0.307f, 0.0f, -0.117f, 0.425f, 0.425f, 0.321f, -0.0f, -0.118f, 0.433f, 0.433f, 0.334f, -0.0f, -0.12f, 0.446f, 0.446f, 0.347f, -0.0f, -0.12f, 0.474f, 0.474f, + 0.36f, -0.0f, -0.12f, 0.481f, 0.481f, 0.374f, -0.0f, -0.119f, 0.491f, 0.491f, 0.387f, -0.0f, -0.118f, 0.494f, 0.494f, 0.401f, 0.0f, -0.116f, 0.5f, 0.5f, + 0.414f, 0.0f, -0.112f, 0.505f, 0.505f, 0.426f, -0.0f, -0.107f, 0.51f, 0.51f, 0.438f, -0.0f, -0.101f, 0.513f, 0.513f, 0.449f, -0.0f, -0.094f, 0.515f, 0.515f, + 0.46f, -0.0f, -0.086f, 0.517f, 0.517f, 0.47f, -0.0f, -0.078f, 0.519f, 0.519f, 0.478f, -0.0f, -0.07f, 0.52f, 0.52f, 0.486f, -0.0f, -0.061f, 0.522f, 0.522f, + 0.493f, -0.0f, -0.052f, 0.523f, 0.523f, 0.499f, -0.0f, -0.044f, 0.522f, 0.522f, 0.505f, -0.0f, -0.035f, 0.522f, 0.522f, 0.51f, -0.0f, -0.027f, 0.523f, 0.523f, + 0.514f, -0.0f, -0.018f, 0.523f, 0.523f, 0.517f, -0.0f, -0.009f, 0.523f, 0.523f, 0.52f, -0.0f, -0.001f, 0.524f, 0.524f, 0.522f, -0.0f, 0.008f, 0.523f, 0.523f, + 0.525f, -0.0f, 0.018f, 0.521f, 0.522f, 0.527f, -0.0f, 0.027f, 0.515f, 0.514f, 0.529f, -0.0f, 0.036f, 0.512f, 0.512f, 0.531f, -0.0f, 0.045f, 0.509f, 0.51f, + 0.533f, -0.0f, 0.053f, 0.506f, 0.505f, 0.535f, -0.0f, 0.062f, 0.503f, 0.503f, 0.536f, -0.0f, 0.071f, 0.5f, 0.5f, 0.538f, -0.0f, 0.08f, 0.496f, 0.497f, + 0.538f, -0.0f, 0.09f, 0.491f, 0.492f, 0.539f, -0.0f, 0.1f, 0.485f, 0.486f, 0.539f, 0.0f, 0.11f, 0.475f, 0.476f, 0.539f, 0.0f, 0.12f, 0.46f, 0.459f, + 0.539f, 0.0f, 0.13f, 0.444f, 0.448f, 0.538f, 0.0f, 0.139f, 0.406f, 0.405f, 0.537f, 0.0f, 0.144f, 0.399f, 0.399f, 0.536f, 0.0f, 0.146f, 0.395f, 0.395f, + 0.535f, 0.0f, 0.144f, 0.412f, 0.412f, 0.533f, 0.0f, 0.139f, 0.413f, 0.413f, 0.53f, 0.0f, 0.131f, 0.414f, 0.413f, 0.528f, 0.0f, 0.122f, 0.419f, 0.418f, + 0.525f, 0.0f, 0.112f, 0.425f, 0.424f, 0.521f, 0.0f, 0.102f, 0.444f, 0.444f, 0.518f, 0.0f, 0.094f, 0.451f, 0.452f, 0.514f, 0.0f, 0.085f, 0.457f, 0.457f, + 0.509f, 0.0f, 0.078f, 0.461f, 0.46f, 0.504f, 0.0f, 0.069f, 0.469f, 0.468f, 0.499f, 0.0f, 0.06f, 0.481f, 0.481f, 0.493f, 0.0f, 0.052f, 0.489f, 0.489f, + 0.487f, 0.0f, 0.044f, 0.492f, 0.492f, 0.481f, 0.0f, 0.037f, 0.501f, 0.5f, 0.474f, 0.0f, 0.029f, 0.513f, 0.513f, 0.467f, 0.0f, 0.022f, 0.521f, 0.521f, + 0.458f, 0.0f, 0.015f, 0.524f, 0.524f, 0.449f, 0.0f, 0.008f, 0.525f, 0.525f, 0.439f, 0.0f, 0.001f, 0.528f, 0.528f, 0.427f, 0.0f, -0.005f, 0.532f, 0.532f, + 0.416f, 0.0f, -0.011f, 0.533f, 0.533f, 0.401f, 0.0f, -0.015f, 0.537f, 0.537f, 0.386f, 0.0f, -0.018f, 0.539f, 0.539f, 0.371f, 0.0f, -0.02f, 0.538f, 0.538f, + 0.356f, 0.0f, -0.021f, 0.543f, 0.543f, 0.341f, 0.0f, -0.023f, 0.543f, 0.543f, 0.326f, 0.0f, -0.023f, 0.543f, 0.543f, 0.312f, 0.0f, -0.022f, 0.543f, 0.543f, + 0.298f, 0.0f, -0.018f, 0.543f, 0.543f, 0.286f, 0.0f, -0.014f, 0.543f, 0.543f, 0.273f, 0.0f, -0.006f, 0.543f, 0.543f, 0.26f, 0.0f, 0.004f, 0.543f, 0.543f, + 0.247f, 0.0f, 0.013f, 0.543f, 0.543f, 0.235f, 0.0f, 0.022f, 0.543f, 0.543f, 0.225f, 0.0f, 0.033f, 0.543f, 0.543f, 0.215f, 0.0f, 0.045f, 0.542f, 0.542f, + 0.206f, 0.0f, 0.061f, 0.54f, 0.54f, 0.199f, 0.0f, 0.078f, 0.542f, 0.542f, 0.193f, 0.0f, 0.094f, 0.542f, 0.542f, 0.189f, -0.0f, 0.109f, 0.541f, 0.541f, + 0.186f, -0.0f, 0.119f, 0.542f, 0.542f, 0.185f, -0.0f, 0.127f, 0.542f, 0.542f, 0.184f, -0.0f, 0.135f, 0.542f, 0.542f, 0.184f, -0.0f, 0.142f, 0.542f, 0.542f, + 0.183f, -0.0f, 0.149f, 0.541f, 0.541f, 0.183f, -0.0f, 0.156f, 0.538f, 0.538f, 0.183f, -0.0f, 0.163f, 0.539f, 0.539f, 0.183f, -0.0f, 0.17f, 0.54f, 0.54f, + 0.183f, 0.0f, 0.177f, 0.54f, 0.54f, 0.183f, 0.0f, 0.184f, 0.54f, 0.54f, 0.183f, 0.0f, 0.191f, 0.54f, 0.54f, 0.184f, 0.0f, 0.196f, 0.539f, 0.539f, + 0.184f, 0.0f, 0.204f, 0.518f, 0.518f, +}; + +static const float data14[45 * GP_PRIM_DATABUF_SIZE] = { + -0.096f, -0.0f, -0.305f, 0.01f, 0.01f, -0.09f, -0.0f, -0.313f, 0.121f, 0.362f, -0.086f, -0.0f, -0.318f, 0.179f, 0.368f, -0.081f, -0.0f, -0.325f, 0.234f, 0.37f, + -0.075f, -0.0f, -0.331f, 0.272f, 0.37f, -0.068f, -0.0f, -0.338f, 0.302f, 0.371f, -0.061f, -0.0f, -0.345f, 0.324f, 0.374f, -0.053f, -0.0f, -0.352f, 0.34f, 0.377f, + -0.044f, -0.0f, -0.358f, 0.352f, 0.378f, -0.035f, -0.0f, -0.362f, 0.362f, 0.377f, -0.026f, -0.0f, -0.366f, 0.37f, 0.378f, -0.018f, -0.0f, -0.368f, 0.377f, 0.378f, + -0.009f, -0.0f, -0.369f, 0.383f, 0.376f, -0.001f, -0.0f, -0.369f, 0.389f, 0.369f, 0.007f, -0.0f, -0.368f, 0.395f, 0.364f, 0.015f, -0.0f, -0.367f, 0.4f, 0.388f, + 0.023f, -0.0f, -0.365f, 0.405f, 0.41f, 0.03f, -0.0f, -0.363f, 0.41f, 0.429f, 0.038f, -0.0f, -0.36f, 0.414f, 0.438f, 0.044f, -0.0f, -0.357f, 0.417f, 0.441f, + 0.05f, -0.0f, -0.355f, 0.419f, 0.444f, 0.055f, -0.0f, -0.352f, 0.42f, 0.441f, 0.06f, -0.0f, -0.349f, 0.421f, 0.445f, 0.063f, -0.0f, -0.347f, 0.421f, 0.446f, + 0.065f, -0.0f, -0.344f, 0.42f, 0.443f, 0.065f, -0.0f, -0.342f, 0.42f, 0.437f, 0.065f, -0.0f, -0.341f, 0.419f, 0.413f, 0.063f, -0.0f, -0.339f, 0.418f, 0.404f, + 0.061f, -0.0f, -0.338f, 0.418f, 0.403f, 0.057f, -0.0f, -0.337f, 0.418f, 0.402f, 0.052f, -0.0f, -0.337f, 0.418f, 0.407f, 0.046f, -0.0f, -0.337f, 0.419f, 0.411f, + 0.04f, 0.0f, -0.336f, 0.42f, 0.416f, 0.032f, 0.0f, -0.337f, 0.422f, 0.421f, 0.023f, 0.0f, -0.339f, 0.424f, 0.425f, 0.014f, 0.0f, -0.34f, 0.426f, 0.427f, + 0.003f, 0.0f, -0.341f, 0.428f, 0.427f, -0.007f, 0.0f, -0.341f, 0.43f, 0.433f, -0.018f, 0.0f, -0.339f, 0.432f, 0.437f, -0.027f, 0.0f, -0.335f, 0.434f, 0.438f, + -0.037f, 0.0f, -0.33f, 0.435f, 0.437f, -0.046f, -0.0f, -0.326f, 0.436f, 0.438f, -0.055f, -0.0f, -0.321f, 0.436f, 0.44f, -0.062f, -0.0f, -0.316f, 0.437f, 0.439f, + -0.073f, -0.0f, -0.31f, 0.437f, 0.437f, +}; + +static const float data16[84 * GP_PRIM_DATABUF_SIZE] = { + 0.737f, 0.0f, 0.177f, 0.148f, 0.148f, 0.735f, 0.0f, 0.164f, 0.214f, 0.39f, 0.734f, 0.0f, 0.155f, 0.254f, 0.402f, 0.732f, 0.0f, 0.143f, 0.295f, 0.413f, + 0.73f, 0.0f, 0.132f, 0.328f, 0.415f, 0.728f, 0.0f, 0.121f, 0.355f, 0.415f, 0.726f, 0.0f, 0.109f, 0.375f, 0.416f, 0.724f, 0.0f, 0.097f, 0.39f, 0.417f, + 0.721f, 0.0f, 0.086f, 0.401f, 0.418f, 0.719f, 0.0f, 0.074f, 0.408f, 0.419f, 0.716f, 0.0f, 0.062f, 0.413f, 0.42f, 0.713f, 0.0f, 0.05f, 0.416f, 0.42f, + 0.71f, 0.0f, 0.039f, 0.418f, 0.421f, 0.707f, 0.0f, 0.028f, 0.42f, 0.421f, 0.703f, 0.0f, 0.017f, 0.421f, 0.422f, 0.7f, 0.0f, 0.006f, 0.421f, 0.422f, + 0.696f, 0.0f, -0.005f, 0.422f, 0.422f, 0.693f, 0.0f, -0.015f, 0.422f, 0.422f, 0.689f, 0.0f, -0.025f, 0.423f, 0.423f, 0.685f, 0.0f, -0.034f, 0.423f, 0.423f, + 0.681f, 0.0f, -0.044f, 0.423f, 0.423f, 0.677f, 0.0f, -0.053f, 0.423f, 0.423f, 0.672f, 0.0f, -0.062f, 0.423f, 0.423f, 0.668f, 0.0f, -0.071f, 0.422f, 0.424f, + 0.662f, 0.0f, -0.08f, 0.422f, 0.424f, 0.657f, 0.0f, -0.088f, 0.422f, 0.422f, 0.651f, 0.0f, -0.095f, 0.421f, 0.419f, 0.645f, 0.0f, -0.103f, 0.42f, 0.419f, + 0.638f, 0.0f, -0.109f, 0.42f, 0.419f, 0.631f, 0.0f, -0.115f, 0.419f, 0.419f, 0.624f, 0.0f, -0.12f, 0.419f, 0.419f, 0.617f, 0.0f, -0.125f, 0.419f, 0.419f, + 0.61f, 0.0f, -0.129f, 0.418f, 0.418f, 0.602f, 0.0f, -0.133f, 0.418f, 0.416f, 0.594f, 0.0f, -0.137f, 0.417f, 0.416f, 0.587f, 0.0f, -0.14f, 0.417f, 0.415f, + 0.579f, 0.0f, -0.142f, 0.417f, 0.416f, 0.571f, 0.0f, -0.144f, 0.417f, 0.415f, 0.564f, 0.0f, -0.145f, 0.417f, 0.416f, 0.556f, 0.0f, -0.146f, 0.417f, 0.415f, + 0.549f, 0.0f, -0.146f, 0.417f, 0.415f, 0.541f, 0.0f, -0.146f, 0.417f, 0.415f, 0.535f, 0.0f, -0.145f, 0.417f, 0.416f, 0.53f, 0.0f, -0.143f, 0.418f, 0.418f, + 0.526f, 0.0f, -0.14f, 0.418f, 0.418f, 0.524f, 0.0f, -0.136f, 0.42f, 0.418f, 0.524f, 0.0f, -0.132f, 0.422f, 0.416f, 0.527f, 0.0f, -0.126f, 0.424f, 0.424f, + 0.531f, 0.0f, -0.121f, 0.427f, 0.428f, 0.536f, 0.0f, -0.115f, 0.43f, 0.433f, 0.542f, 0.0f, -0.109f, 0.433f, 0.436f, 0.548f, 0.0f, -0.102f, 0.435f, 0.436f, + 0.555f, 0.0f, -0.095f, 0.436f, 0.437f, 0.562f, 0.0f, -0.088f, 0.437f, 0.438f, 0.568f, 0.0f, -0.081f, 0.437f, 0.438f, 0.575f, 0.0f, -0.073f, 0.438f, 0.438f, + 0.581f, 0.0f, -0.065f, 0.438f, 0.438f, 0.587f, 0.0f, -0.058f, 0.438f, 0.438f, 0.593f, 0.0f, -0.05f, 0.438f, 0.438f, 0.599f, 0.0f, -0.041f, 0.438f, 0.438f, + 0.605f, 0.0f, -0.033f, 0.438f, 0.438f, 0.61f, 0.0f, -0.024f, 0.438f, 0.438f, 0.615f, 0.0f, -0.015f, 0.438f, 0.438f, 0.621f, 0.0f, -0.006f, 0.438f, 0.438f, + 0.626f, 0.0f, 0.004f, 0.438f, 0.438f, 0.631f, 0.0f, 0.013f, 0.437f, 0.438f, 0.636f, 0.0f, 0.023f, 0.436f, 0.438f, 0.641f, 0.0f, 0.032f, 0.434f, 0.438f, + 0.647f, 0.0f, 0.042f, 0.432f, 0.437f, 0.652f, 0.0f, 0.051f, 0.431f, 0.429f, 0.657f, 0.0f, 0.06f, 0.429f, 0.426f, 0.662f, 0.0f, 0.069f, 0.427f, 0.425f, + 0.668f, 0.0f, 0.078f, 0.425f, 0.425f, 0.673f, 0.0f, 0.087f, 0.423f, 0.424f, 0.678f, 0.0f, 0.095f, 0.42f, 0.422f, 0.683f, 0.0f, 0.104f, 0.416f, 0.42f, + 0.688f, 0.0f, 0.112f, 0.411f, 0.421f, 0.693f, 0.0f, 0.12f, 0.403f, 0.417f, 0.698f, 0.0f, 0.128f, 0.394f, 0.411f, 0.702f, 0.0f, 0.135f, 0.382f, 0.404f, + 0.707f, 0.0f, 0.143f, 0.369f, 0.388f, 0.711f, 0.0f, 0.15f, 0.352f, 0.371f, 0.714f, 0.0f, 0.155f, 0.338f, 0.352f, 0.719f, 0.0f, 0.164f, 0.315f, 0.315f, +}; + +static const float data15[44 * GP_PRIM_DATABUF_SIZE] = { + -0.085f, 0.0f, -0.816f, 0.138f, 0.138f, -0.079f, 0.0f, -0.825f, 0.246f, 0.309f, -0.074f, 0.0f, -0.832f, 0.302f, 0.34f, -0.067f, 0.0f, -0.84f, 0.335f, 0.352f, + -0.059f, 0.0f, -0.848f, 0.357f, 0.374f, -0.05f, 0.0f, -0.855f, 0.371f, 0.378f, -0.041f, 0.0f, -0.861f, 0.382f, 0.383f, -0.031f, 0.0f, -0.866f, 0.391f, 0.396f, + -0.021f, 0.0f, -0.871f, 0.398f, 0.401f, -0.011f, 0.0f, -0.874f, 0.404f, 0.407f, -0.001f, 0.0f, -0.877f, 0.409f, 0.411f, 0.01f, 0.0f, -0.878f, 0.415f, 0.412f, + 0.02f, 0.0f, -0.878f, 0.422f, 0.417f, 0.031f, 0.0f, -0.878f, 0.43f, 0.421f, 0.042f, 0.0f, -0.876f, 0.438f, 0.437f, 0.052f, 0.0f, -0.873f, 0.445f, 0.451f, + 0.062f, 0.0f, -0.868f, 0.451f, 0.459f, 0.071f, 0.0f, -0.863f, 0.456f, 0.463f, 0.08f, 0.0f, -0.857f, 0.46f, 0.465f, 0.087f, 0.0f, -0.85f, 0.462f, 0.465f, + 0.094f, 0.0f, -0.842f, 0.461f, 0.465f, 0.098f, 0.0f, -0.835f, 0.458f, 0.467f, 0.101f, 0.0f, -0.827f, 0.451f, 0.457f, 0.103f, 0.0f, -0.82f, 0.436f, 0.451f, + 0.102f, 0.0f, -0.815f, 0.422f, 0.418f, 0.1f, 0.0f, -0.811f, 0.419f, 0.378f, 0.096f, 0.0f, -0.814f, 0.436f, 0.447f, 0.089f, 0.0f, -0.817f, 0.454f, 0.465f, + 0.082f, 0.0f, -0.821f, 0.465f, 0.47f, 0.072f, 0.0f, -0.825f, 0.473f, 0.477f, 0.061f, 0.0f, -0.828f, 0.477f, 0.479f, 0.049f, 0.0f, -0.832f, 0.48f, 0.485f, + 0.036f, 0.0f, -0.834f, 0.483f, 0.48f, 0.023f, 0.0f, -0.836f, 0.484f, 0.485f, 0.01f, 0.0f, -0.838f, 0.486f, 0.487f, -0.003f, 0.0f, -0.84f, 0.486f, 0.488f, + -0.016f, 0.0f, -0.84f, 0.486f, 0.489f, -0.027f, 0.0f, -0.84f, 0.485f, 0.485f, -0.039f, 0.0f, -0.839f, 0.484f, 0.484f, -0.049f, 0.0f, -0.837f, 0.483f, 0.485f, + -0.058f, 0.0f, -0.834f, 0.48f, 0.481f, -0.066f, 0.0f, -0.83f, 0.473f, 0.479f, -0.072f, 0.0f, -0.827f, 0.462f, 0.472f, -0.081f, 0.0f, -0.823f, 0.442f, 0.442f, +}; + +static const float data17[56 * GP_PRIM_DATABUF_SIZE] = { + -1.007f, -0.0f, 0.183f, 0.022f, 0.022f, -1.003f, -0.0f, 0.181f, 0.192f, 0.436f, -0.998f, -0.0f, 0.18f, 0.28f, 0.451f, -0.99f, -0.0f, 0.178f, 0.355f, 0.459f, + -0.98f, -0.0f, 0.175f, 0.402f, 0.464f, -0.967f, -0.0f, 0.169f, 0.432f, 0.467f, -0.952f, -0.0f, 0.152f, 0.449f, 0.468f, -0.943f, 0.0f, 0.138f, 0.459f, 0.469f, + -0.939f, 0.0f, 0.128f, 0.464f, 0.469f, -0.934f, 0.0f, 0.119f, 0.467f, 0.47f, -0.929f, 0.0f, 0.11f, 0.469f, 0.47f, -0.924f, 0.0f, 0.101f, 0.47f, 0.47f, + -0.919f, 0.0f, 0.092f, 0.47f, 0.471f, -0.913f, 0.0f, 0.082f, 0.471f, 0.471f, -0.908f, 0.0f, 0.072f, 0.471f, 0.471f, -0.903f, 0.0f, 0.063f, 0.472f, 0.472f, + -0.897f, 0.0f, 0.053f, 0.472f, 0.472f, -0.892f, 0.0f, 0.044f, 0.473f, 0.473f, -0.886f, 0.0f, 0.035f, 0.473f, 0.473f, -0.881f, 0.0f, 0.026f, 0.473f, 0.473f, + -0.876f, 0.0f, 0.018f, 0.473f, 0.473f, -0.87f, 0.0f, 0.012f, 0.472f, 0.473f, -0.865f, 0.0f, 0.006f, 0.47f, 0.473f, -0.86f, 0.0f, 0.003f, 0.468f, 0.473f, + -0.855f, 0.0f, 0.001f, 0.466f, 0.469f, -0.85f, 0.0f, 0.001f, 0.463f, 0.469f, -0.846f, 0.0f, 0.003f, 0.46f, 0.45f, -0.843f, 0.0f, 0.008f, 0.458f, 0.454f, + -0.84f, 0.0f, 0.014f, 0.456f, 0.454f, -0.838f, 0.0f, 0.021f, 0.455f, 0.454f, -0.836f, 0.0f, 0.03f, 0.453f, 0.455f, -0.835f, 0.0f, 0.039f, 0.451f, 0.455f, + -0.835f, 0.0f, 0.049f, 0.449f, 0.453f, -0.836f, 0.0f, 0.059f, 0.447f, 0.445f, -0.837f, 0.0f, 0.068f, 0.445f, 0.441f, -0.84f, 0.0f, 0.078f, 0.443f, 0.44f, + -0.843f, 0.0f, 0.087f, 0.442f, 0.44f, -0.846f, 0.0f, 0.095f, 0.442f, 0.44f, -0.851f, -0.0f, 0.103f, 0.441f, 0.441f, -0.855f, -0.0f, 0.111f, 0.441f, 0.44f, + -0.86f, -0.0f, 0.119f, 0.441f, 0.441f, -0.865f, -0.0f, 0.127f, 0.441f, 0.441f, -0.871f, -0.0f, 0.134f, 0.441f, 0.441f, -0.877f, -0.0f, 0.141f, 0.441f, 0.441f, + -0.883f, -0.0f, 0.149f, 0.441f, 0.442f, -0.889f, -0.0f, 0.156f, 0.441f, 0.441f, -0.896f, -0.0f, 0.163f, 0.441f, 0.442f, -0.904f, -0.0f, 0.169f, 0.442f, 0.441f, + -0.913f, -0.0f, 0.176f, 0.442f, 0.441f, -0.925f, -0.0f, 0.183f, 0.443f, 0.441f, -0.941f, -0.0f, 0.19f, 0.444f, 0.442f, -0.956f, -0.0f, 0.195f, 0.446f, 0.443f, + -0.971f, -0.0f, 0.198f, 0.448f, 0.443f, -0.983f, -0.0f, 0.198f, 0.451f, 0.452f, -0.992f, -0.0f, 0.198f, 0.454f, 0.456f, -1.001f, 0.0f, 0.196f, 0.457f, 0.457f, +}; + +static const float data18[59 * GP_PRIM_DATABUF_SIZE] = { + 0.782f, 0.0f, 0.099f, 0.04f, 0.04f, 0.779f, 0.0f, 0.088f, 0.108f, 0.34f, 0.777f, 0.0f, 0.08f, 0.149f, 0.35f, 0.774f, 0.0f, 0.071f, 0.194f, 0.352f, + 0.772f, 0.0f, 0.062f, 0.231f, 0.352f, 0.771f, 0.0f, 0.053f, 0.263f, 0.353f, 0.769f, 0.0f, 0.044f, 0.289f, 0.353f, 0.768f, 0.0f, 0.036f, 0.31f, 0.353f, + 0.767f, 0.0f, 0.029f, 0.327f, 0.353f, 0.767f, 0.0f, 0.023f, 0.341f, 0.353f, 0.767f, 0.0f, 0.017f, 0.353f, 0.353f, 0.768f, 0.0f, 0.013f, 0.363f, 0.353f, + 0.769f, 0.0f, 0.01f, 0.373f, 0.353f, 0.771f, 0.0f, 0.009f, 0.382f, 0.351f, 0.773f, 0.0f, 0.008f, 0.39f, 0.393f, 0.776f, 0.0f, 0.009f, 0.399f, 0.41f, + 0.779f, 0.0f, 0.011f, 0.407f, 0.425f, 0.783f, 0.0f, 0.015f, 0.415f, 0.434f, 0.787f, 0.0f, 0.019f, 0.423f, 0.44f, 0.792f, 0.0f, 0.024f, 0.429f, 0.441f, + 0.797f, 0.0f, 0.03f, 0.435f, 0.444f, 0.802f, 0.0f, 0.037f, 0.441f, 0.447f, 0.807f, 0.0f, 0.044f, 0.445f, 0.453f, 0.813f, 0.0f, 0.051f, 0.449f, 0.457f, + 0.819f, 0.0f, 0.058f, 0.452f, 0.458f, 0.825f, 0.0f, 0.066f, 0.455f, 0.46f, 0.831f, 0.0f, 0.074f, 0.457f, 0.462f, 0.838f, 0.0f, 0.082f, 0.459f, 0.462f, + 0.845f, 0.0f, 0.09f, 0.461f, 0.462f, 0.852f, 0.0f, 0.098f, 0.462f, 0.463f, 0.859f, 0.0f, 0.106f, 0.463f, 0.464f, 0.867f, 0.0f, 0.113f, 0.464f, 0.464f, + 0.874f, 0.0f, 0.121f, 0.465f, 0.465f, 0.882f, 0.0f, 0.129f, 0.465f, 0.465f, 0.889f, 0.0f, 0.136f, 0.466f, 0.466f, 0.897f, 0.0f, 0.143f, 0.466f, 0.467f, + 0.904f, 0.0f, 0.15f, 0.467f, 0.466f, 0.911f, 0.0f, 0.157f, 0.467f, 0.467f, 0.916f, 0.0f, 0.163f, 0.468f, 0.468f, 0.921f, 0.0f, 0.169f, 0.468f, 0.469f, + 0.924f, 0.0f, 0.173f, 0.468f, 0.469f, 0.926f, 0.0f, 0.177f, 0.469f, 0.468f, 0.925f, 0.0f, 0.18f, 0.469f, 0.468f, 0.922f, 0.0f, 0.181f, 0.469f, 0.469f, + 0.918f, 0.0f, 0.181f, 0.469f, 0.469f, 0.912f, 0.0f, 0.18f, 0.469f, 0.469f, 0.905f, 0.0f, 0.178f, 0.468f, 0.47f, 0.898f, 0.0f, 0.175f, 0.466f, 0.471f, + 0.89f, 0.0f, 0.172f, 0.462f, 0.469f, 0.882f, 0.0f, 0.168f, 0.454f, 0.468f, 0.874f, 0.0f, 0.164f, 0.442f, 0.467f, 0.866f, 0.0f, 0.159f, 0.423f, 0.467f, + 0.858f, 0.0f, 0.154f, 0.398f, 0.468f, 0.851f, 0.0f, 0.149f, 0.366f, 0.468f, 0.844f, 0.0f, 0.144f, 0.326f, 0.469f, 0.837f, 0.0f, 0.139f, 0.282f, 0.469f, + 0.83f, 0.0f, 0.134f, 0.231f, 0.467f, 0.824f, 0.0f, 0.13f, 0.184f, 0.415f, 0.816f, 0.0f, 0.124f, 0.111f, 0.111f, +}; + +static const float data19[100 * GP_PRIM_DATABUF_SIZE] = { + -0.279f, 0.0f, 0.568f, 0.154f, 0.154f, -0.266f, 0.0f, 0.569f, 0.249f, 0.318f, -0.258f, 0.0f, 0.57f, 0.296f, 0.357f, -0.248f, 0.0f, 0.571f, 0.337f, 0.383f, + -0.238f, 0.0f, 0.571f, 0.363f, 0.396f, -0.229f, 0.0f, 0.571f, 0.381f, 0.403f, -0.219f, 0.0f, 0.57f, 0.392f, 0.407f, -0.209f, 0.0f, 0.568f, 0.399f, 0.407f, + -0.2f, 0.0f, 0.566f, 0.403f, 0.408f, -0.19f, 0.0f, 0.563f, 0.406f, 0.41f, -0.181f, 0.0f, 0.559f, 0.407f, 0.41f, -0.171f, 0.0f, 0.555f, 0.409f, 0.41f, + -0.161f, 0.0f, 0.551f, 0.409f, 0.411f, -0.152f, 0.0f, 0.546f, 0.41f, 0.411f, -0.142f, 0.0f, 0.542f, 0.41f, 0.412f, -0.132f, 0.0f, 0.537f, 0.411f, 0.411f, + -0.122f, 0.0f, 0.533f, 0.411f, 0.411f, -0.112f, 0.0f, 0.528f, 0.411f, 0.412f, -0.102f, 0.0f, 0.524f, 0.411f, 0.412f, -0.092f, 0.0f, 0.519f, 0.41f, 0.412f, + -0.081f, 0.0f, 0.515f, 0.407f, 0.411f, -0.071f, 0.0f, 0.511f, 0.403f, 0.408f, -0.061f, 0.0f, 0.507f, 0.399f, 0.401f, -0.051f, 0.0f, 0.503f, 0.394f, 0.395f, + -0.041f, 0.0f, 0.499f, 0.39f, 0.388f, -0.031f, 0.0f, 0.495f, 0.386f, 0.383f, -0.021f, 0.0f, 0.491f, 0.383f, 0.38f, -0.011f, 0.0f, 0.488f, 0.381f, 0.378f, + -0.001f, 0.0f, 0.486f, 0.379f, 0.377f, 0.009f, 0.0f, 0.484f, 0.378f, 0.377f, 0.019f, 0.0f, 0.483f, 0.377f, 0.375f, 0.03f, 0.0f, 0.482f, 0.377f, 0.375f, + 0.041f, 0.0f, 0.482f, 0.378f, 0.376f, 0.051f, 0.0f, 0.483f, 0.379f, 0.376f, 0.062f, 0.0f, 0.484f, 0.381f, 0.376f, 0.073f, 0.0f, 0.486f, 0.385f, 0.379f, + 0.085f, 0.0f, 0.488f, 0.389f, 0.382f, 0.096f, 0.0f, 0.491f, 0.395f, 0.392f, 0.108f, 0.0f, 0.494f, 0.402f, 0.4f, 0.12f, 0.0f, 0.497f, 0.409f, 0.409f, + 0.132f, 0.0f, 0.501f, 0.415f, 0.416f, 0.144f, 0.0f, 0.505f, 0.421f, 0.427f, 0.157f, 0.0f, 0.509f, 0.425f, 0.43f, 0.17f, 0.0f, 0.513f, 0.429f, 0.433f, + 0.181f, 0.0f, 0.517f, 0.431f, 0.433f, 0.192f, 0.0f, 0.52f, 0.433f, 0.434f, 0.201f, 0.0f, 0.522f, 0.433f, 0.435f, 0.208f, 0.0f, 0.524f, 0.433f, 0.435f, + 0.213f, 0.0f, 0.524f, 0.432f, 0.436f, 0.216f, 0.0f, 0.523f, 0.431f, 0.435f, 0.217f, 0.0f, 0.521f, 0.43f, 0.426f, 0.215f, 0.0f, 0.518f, 0.429f, 0.427f, + 0.213f, 0.0f, 0.515f, 0.428f, 0.427f, 0.208f, 0.0f, 0.511f, 0.428f, 0.427f, 0.203f, 0.0f, 0.506f, 0.428f, 0.427f, 0.196f, 0.0f, 0.502f, 0.428f, 0.427f, + 0.189f, 0.0f, 0.497f, 0.428f, 0.427f, 0.181f, 0.0f, 0.492f, 0.428f, 0.427f, 0.173f, 0.0f, 0.487f, 0.428f, 0.428f, 0.163f, 0.0f, 0.482f, 0.429f, 0.428f, + 0.154f, 0.0f, 0.477f, 0.429f, 0.429f, 0.145f, 0.0f, 0.472f, 0.43f, 0.43f, 0.135f, 0.0f, 0.467f, 0.431f, 0.431f, 0.125f, 0.0f, 0.462f, 0.432f, 0.43f, + 0.116f, 0.0f, 0.457f, 0.433f, 0.431f, 0.106f, 0.0f, 0.453f, 0.435f, 0.434f, 0.096f, 0.0f, 0.448f, 0.436f, 0.436f, 0.086f, 0.0f, 0.444f, 0.437f, 0.438f, + 0.076f, 0.0f, 0.44f, 0.438f, 0.44f, 0.065f, 0.0f, 0.436f, 0.439f, 0.441f, 0.055f, 0.0f, 0.433f, 0.44f, 0.441f, 0.044f, 0.0f, 0.431f, 0.441f, 0.442f, + 0.033f, 0.0f, 0.429f, 0.441f, 0.442f, 0.022f, 0.0f, 0.427f, 0.441f, 0.442f, 0.011f, 0.0f, 0.426f, 0.442f, 0.443f, -0.0f, 0.0f, 0.426f, 0.442f, 0.442f, + -0.011f, 0.0f, 0.426f, 0.442f, 0.442f, -0.022f, 0.0f, 0.427f, 0.442f, 0.442f, -0.033f, 0.0f, 0.429f, 0.442f, 0.442f, -0.042f, 0.0f, 0.432f, 0.441f, 0.442f, + -0.052f, 0.0f, 0.435f, 0.441f, 0.441f, -0.061f, 0.0f, 0.439f, 0.441f, 0.441f, -0.07f, 0.0f, 0.443f, 0.441f, 0.441f, -0.078f, 0.0f, 0.448f, 0.441f, 0.441f, + -0.087f, 0.0f, 0.453f, 0.441f, 0.442f, -0.095f, 0.0f, 0.458f, 0.441f, 0.441f, -0.104f, 0.0f, 0.463f, 0.44f, 0.44f, -0.113f, 0.0f, 0.468f, 0.44f, 0.44f, + -0.122f, 0.0f, 0.473f, 0.44f, 0.44f, -0.132f, 0.0f, 0.479f, 0.44f, 0.44f, -0.143f, 0.0f, 0.485f, 0.44f, 0.44f, -0.154f, 0.0f, 0.491f, 0.44f, 0.44f, + -0.165f, 0.0f, 0.498f, 0.44f, 0.44f, -0.176f, 0.0f, 0.504f, 0.439f, 0.439f, -0.187f, 0.0f, 0.51f, 0.435f, 0.44f, -0.198f, 0.0f, 0.516f, 0.424f, 0.44f, + -0.209f, 0.0f, 0.522f, 0.393f, 0.44f, -0.219f, 0.0f, 0.527f, 0.324f, 0.44f, -0.228f, 0.0f, 0.532f, 0.222f, 0.404f, -0.241f, 0.0f, 0.538f, 0.037f, 0.037f, +}; + +static const float data20[136 * GP_PRIM_DATABUF_SIZE] = { + 0.331f, 0.0f, -0.036f, 0.065f, 0.065f, 0.322f, 0.0f, -0.034f, 0.239f, 0.293f, 0.317f, 0.0f, -0.032f, 0.316f, 0.339f, 0.31f, 0.0f, -0.029f, 0.348f, 0.355f, + 0.302f, 0.0f, -0.027f, 0.364f, 0.368f, 0.295f, 0.0f, -0.023f, 0.373f, 0.374f, 0.287f, 0.0f, -0.02f, 0.381f, 0.381f, 0.279f, 0.0f, -0.015f, 0.388f, 0.391f, + 0.271f, 0.0f, -0.01f, 0.392f, 0.394f, 0.263f, 0.0f, -0.004f, 0.395f, 0.396f, 0.255f, 0.0f, 0.002f, 0.397f, 0.397f, 0.247f, 0.0f, 0.008f, 0.399f, 0.4f, + 0.239f, 0.0f, 0.016f, 0.401f, 0.401f, 0.232f, -0.0f, 0.024f, 0.404f, 0.404f, 0.226f, 0.0f, 0.031f, 0.406f, 0.407f, 0.221f, 0.0f, 0.038f, 0.409f, 0.409f, + 0.215f, 0.0f, 0.045f, 0.412f, 0.412f, 0.21f, 0.0f, 0.054f, 0.415f, 0.415f, 0.205f, 0.0f, 0.063f, 0.417f, 0.417f, 0.201f, 0.0f, 0.073f, 0.42f, 0.421f, + 0.197f, 0.0f, 0.083f, 0.421f, 0.421f, 0.193f, -0.0f, 0.094f, 0.423f, 0.423f, 0.19f, -0.0f, 0.104f, 0.424f, 0.424f, 0.187f, -0.0f, 0.114f, 0.424f, 0.425f, + 0.185f, -0.0f, 0.125f, 0.425f, 0.425f, 0.183f, -0.0f, 0.135f, 0.425f, 0.425f, 0.182f, -0.0f, 0.146f, 0.426f, 0.425f, 0.181f, -0.0f, 0.157f, 0.426f, 0.425f, + 0.18f, -0.0f, 0.168f, 0.426f, 0.426f, 0.18f, -0.0f, 0.179f, 0.427f, 0.427f, 0.181f, -0.0f, 0.189f, 0.427f, 0.427f, 0.182f, -0.0f, 0.199f, 0.427f, 0.427f, + 0.183f, -0.0f, 0.208f, 0.427f, 0.428f, 0.185f, -0.0f, 0.218f, 0.428f, 0.427f, 0.187f, -0.0f, 0.226f, 0.428f, 0.427f, 0.19f, -0.0f, 0.235f, 0.429f, 0.427f, + 0.192f, -0.0f, 0.243f, 0.43f, 0.428f, 0.196f, -0.0f, 0.252f, 0.431f, 0.431f, 0.199f, -0.0f, 0.26f, 0.431f, 0.432f, 0.203f, -0.0f, 0.268f, 0.432f, 0.433f, + 0.207f, -0.0f, 0.276f, 0.433f, 0.433f, 0.212f, -0.0f, 0.283f, 0.434f, 0.434f, 0.216f, -0.0f, 0.291f, 0.434f, 0.435f, 0.221f, -0.0f, 0.298f, 0.435f, 0.436f, + 0.227f, -0.0f, 0.305f, 0.435f, 0.435f, 0.232f, -0.0f, 0.311f, 0.436f, 0.436f, 0.238f, -0.0f, 0.317f, 0.436f, 0.436f, 0.243f, -0.0f, 0.323f, 0.436f, 0.436f, + 0.249f, -0.0f, 0.329f, 0.437f, 0.436f, 0.255f, -0.0f, 0.334f, 0.438f, 0.437f, 0.262f, -0.0f, 0.339f, 0.44f, 0.437f, 0.268f, -0.0f, 0.344f, 0.442f, 0.441f, + 0.274f, 0.0f, 0.348f, 0.444f, 0.446f, 0.281f, 0.0f, 0.352f, 0.445f, 0.447f, 0.287f, 0.0f, 0.355f, 0.446f, 0.447f, 0.293f, 0.0f, 0.358f, 0.446f, 0.447f, + 0.299f, 0.0f, 0.361f, 0.447f, 0.447f, 0.306f, 0.0f, 0.363f, 0.447f, 0.448f, 0.312f, 0.0f, 0.366f, 0.447f, 0.448f, 0.318f, 0.0f, 0.368f, 0.448f, 0.448f, + 0.325f, 0.0f, 0.369f, 0.448f, 0.448f, 0.331f, 0.0f, 0.371f, 0.448f, 0.448f, 0.338f, 0.0f, 0.372f, 0.448f, 0.448f, 0.345f, 0.0f, 0.372f, 0.448f, 0.448f, + 0.352f, 0.0f, 0.372f, 0.448f, 0.448f, 0.359f, 0.0f, 0.372f, 0.448f, 0.449f, 0.366f, 0.0f, 0.371f, 0.448f, 0.448f, 0.373f, 0.0f, 0.37f, 0.448f, 0.449f, + 0.38f, 0.0f, 0.369f, 0.449f, 0.449f, 0.387f, 0.0f, 0.367f, 0.449f, 0.449f, 0.393f, 0.0f, 0.365f, 0.449f, 0.449f, 0.4f, 0.0f, 0.363f, 0.449f, 0.45f, + 0.406f, 0.0f, 0.36f, 0.45f, 0.45f, 0.412f, -0.0f, 0.357f, 0.45f, 0.45f, 0.418f, -0.0f, 0.354f, 0.45f, 0.451f, 0.424f, -0.0f, 0.351f, 0.45f, 0.451f, + 0.43f, -0.0f, 0.347f, 0.45f, 0.451f, 0.436f, -0.0f, 0.343f, 0.45f, 0.451f, 0.443f, -0.0f, 0.339f, 0.45f, 0.45f, 0.449f, -0.0f, 0.334f, 0.45f, 0.451f, + 0.455f, -0.0f, 0.329f, 0.451f, 0.451f, 0.46f, -0.0f, 0.323f, 0.451f, 0.451f, 0.466f, -0.0f, 0.318f, 0.451f, 0.451f, 0.472f, -0.0f, 0.311f, 0.452f, 0.452f, + 0.477f, -0.0f, 0.305f, 0.452f, 0.453f, 0.482f, -0.0f, 0.298f, 0.452f, 0.453f, 0.487f, -0.0f, 0.291f, 0.453f, 0.453f, 0.492f, -0.0f, 0.284f, 0.453f, 0.453f, + 0.496f, -0.0f, 0.277f, 0.453f, 0.453f, 0.5f, -0.0f, 0.269f, 0.453f, 0.454f, 0.504f, -0.0f, 0.261f, 0.453f, 0.454f, 0.508f, -0.0f, 0.252f, 0.454f, 0.454f, + 0.511f, -0.0f, 0.244f, 0.454f, 0.454f, 0.514f, -0.0f, 0.235f, 0.454f, 0.455f, 0.517f, -0.0f, 0.225f, 0.454f, 0.455f, 0.519f, -0.0f, 0.216f, 0.454f, 0.455f, + 0.521f, -0.0f, 0.205f, 0.455f, 0.455f, 0.523f, -0.0f, 0.194f, 0.455f, 0.455f, 0.524f, -0.0f, 0.182f, 0.455f, 0.455f, 0.524f, -0.0f, 0.169f, 0.455f, 0.456f, + 0.524f, -0.0f, 0.157f, 0.455f, 0.456f, 0.523f, -0.0f, 0.145f, 0.455f, 0.456f, 0.522f, -0.0f, 0.133f, 0.455f, 0.456f, 0.52f, -0.0f, 0.122f, 0.456f, 0.456f, + 0.518f, -0.0f, 0.11f, 0.456f, 0.456f, 0.515f, -0.0f, 0.1f, 0.456f, 0.456f, 0.513f, -0.0f, 0.09f, 0.456f, 0.457f, 0.509f, -0.0f, 0.081f, 0.456f, 0.457f, + 0.506f, -0.0f, 0.072f, 0.457f, 0.457f, 0.502f, -0.0f, 0.064f, 0.457f, 0.457f, 0.498f, -0.0f, 0.056f, 0.457f, 0.457f, 0.494f, -0.0f, 0.049f, 0.457f, 0.457f, + 0.49f, -0.0f, 0.041f, 0.458f, 0.457f, 0.485f, -0.0f, 0.034f, 0.458f, 0.457f, 0.48f, -0.0f, 0.028f, 0.458f, 0.458f, 0.475f, -0.0f, 0.022f, 0.458f, 0.458f, + 0.47f, -0.0f, 0.016f, 0.458f, 0.458f, 0.465f, -0.0f, 0.011f, 0.459f, 0.458f, 0.46f, -0.0f, 0.006f, 0.459f, 0.458f, 0.454f, -0.0f, 0.001f, 0.46f, 0.459f, + 0.449f, 0.0f, -0.003f, 0.464f, 0.463f, 0.443f, 0.0f, -0.007f, 0.467f, 0.468f, 0.438f, 0.0f, -0.011f, 0.469f, 0.469f, 0.432f, 0.0f, -0.015f, 0.471f, 0.47f, + 0.426f, 0.0f, -0.018f, 0.477f, 0.478f, 0.42f, 0.0f, -0.021f, 0.478f, 0.478f, 0.414f, 0.0f, -0.024f, 0.478f, 0.478f, 0.408f, 0.0f, -0.027f, 0.479f, 0.479f, + 0.402f, 0.0f, -0.029f, 0.48f, 0.48f, 0.395f, 0.0f, -0.031f, 0.48f, 0.48f, 0.389f, 0.0f, -0.033f, 0.482f, 0.482f, 0.382f, 0.0f, -0.035f, 0.482f, 0.482f, + 0.376f, 0.0f, -0.036f, 0.482f, 0.482f, 0.369f, 0.0f, -0.037f, 0.48f, 0.482f, 0.364f, 0.0f, -0.037f, 0.457f, 0.485f, 0.356f, 0.0f, -0.038f, 0.32f, 0.32f, +}; + +static const float data21[353 * GP_PRIM_DATABUF_SIZE] = { + -0.382f, 0.0f, 0.397f, 0.0f, 1.0f, -0.386f, 0.0f, 0.394f, 0.0f, 1.0f, -0.389f, 0.0f, 0.392f, 0.0f, 1.0f, -0.392f, 0.0f, 0.39f, 0.0f, 1.0f, + -0.395f, 0.0f, 0.388f, 0.0f, 1.0f, -0.399f, 0.0f, 0.385f, 0.0f, 1.0f, -0.402f, 0.0f, 0.383f, 0.0f, 1.0f, -0.405f, 0.0f, 0.381f, 0.0f, 1.0f, + -0.408f, 0.0f, 0.379f, 0.0f, 1.0f, -0.411f, 0.0f, 0.377f, 0.0f, 1.0f, -0.414f, 0.0f, 0.375f, 0.0f, 1.0f, -0.417f, 0.0f, 0.372f, 0.0f, 1.0f, + -0.42f, 0.0f, 0.37f, 0.0f, 1.0f, -0.423f, 0.0f, 0.368f, 0.0f, 1.0f, -0.425f, 0.0f, 0.366f, 0.0f, 1.0f, -0.428f, 0.0f, 0.364f, 0.0f, 1.0f, + -0.431f, 0.0f, 0.362f, 0.0f, 1.0f, -0.433f, 0.0f, 0.359f, 0.0f, 1.0f, -0.436f, 0.0f, 0.357f, 0.0f, 1.0f, -0.438f, 0.0f, 0.355f, 0.0f, 1.0f, + -0.441f, 0.0f, 0.353f, 0.0f, 1.0f, -0.443f, 0.0f, 0.351f, 0.0f, 1.0f, -0.445f, 0.0f, 0.349f, 0.0f, 1.0f, -0.447f, 0.0f, 0.346f, 0.0f, 1.0f, + -0.45f, 0.0f, 0.344f, 0.0f, 1.0f, -0.452f, 0.0f, 0.342f, 0.0f, 1.0f, -0.454f, 0.0f, 0.34f, 0.0f, 1.0f, -0.456f, 0.0f, 0.337f, 0.0f, 1.0f, + -0.458f, 0.0f, 0.335f, 0.0f, 1.0f, -0.46f, 0.0f, 0.333f, 0.0f, 1.0f, -0.462f, 0.0f, 0.33f, 0.0f, 1.0f, -0.464f, 0.0f, 0.328f, 0.0f, 1.0f, + -0.466f, 0.0f, 0.326f, 0.0f, 1.0f, -0.468f, 0.0f, 0.323f, 0.0f, 1.0f, -0.47f, 0.0f, 0.321f, 0.0f, 1.0f, -0.472f, 0.0f, 0.319f, 0.0f, 1.0f, + -0.474f, 0.0f, 0.316f, 0.0f, 1.0f, -0.475f, 0.0f, 0.314f, 0.0f, 1.0f, -0.477f, 0.0f, 0.311f, 0.0f, 1.0f, -0.479f, 0.0f, 0.309f, 0.0f, 1.0f, + -0.481f, 0.0f, 0.307f, 0.0f, 1.0f, -0.482f, 0.0f, 0.304f, 0.0f, 1.0f, -0.484f, 0.0f, 0.302f, 0.0f, 1.0f, -0.486f, 0.0f, 0.299f, 0.0f, 1.0f, + -0.487f, 0.0f, 0.297f, 0.0f, 1.0f, -0.489f, 0.0f, 0.294f, 0.0f, 1.0f, -0.49f, 0.0f, 0.292f, 0.0f, 1.0f, -0.492f, 0.0f, 0.289f, 0.0f, 1.0f, + -0.494f, 0.0f, 0.286f, 0.0f, 1.0f, -0.495f, 0.0f, 0.284f, 0.0f, 1.0f, -0.497f, 0.0f, 0.281f, 0.0f, 1.0f, -0.498f, 0.0f, 0.279f, 0.001f, 1.0f, + -0.499f, 0.0f, 0.276f, 0.001f, 1.0f, -0.501f, 0.0f, 0.273f, 0.002f, 1.0f, -0.502f, 0.0f, 0.271f, 0.003f, 1.0f, -0.504f, 0.0f, 0.268f, 0.005f, 1.0f, + -0.505f, 0.0f, 0.265f, 0.008f, 1.0f, -0.506f, 0.0f, 0.262f, 0.011f, 1.0f, -0.508f, 0.0f, 0.259f, 0.016f, 1.0f, -0.509f, 0.0f, 0.256f, 0.021f, 1.0f, + -0.51f, 0.0f, 0.254f, 0.027f, 1.0f, -0.512f, 0.0f, 0.251f, 0.035f, 1.0f, -0.513f, 0.0f, 0.248f, 0.043f, 1.0f, -0.514f, 0.0f, 0.245f, 0.053f, 1.0f, + -0.515f, 0.0f, 0.242f, 0.064f, 1.0f, -0.516f, 0.0f, 0.239f, 0.076f, 1.0f, -0.517f, 0.0f, 0.235f, 0.09f, 1.0f, -0.519f, 0.0f, 0.232f, 0.105f, 1.0f, + -0.52f, 0.0f, 0.229f, 0.122f, 1.0f, -0.521f, 0.0f, 0.226f, 0.14f, 1.0f, -0.521f, 0.0f, 0.222f, 0.159f, 1.0f, -0.522f, 0.0f, 0.219f, 0.179f, 1.0f, + -0.523f, 0.0f, 0.216f, 0.2f, 1.0f, -0.524f, 0.0f, 0.212f, 0.221f, 1.0f, -0.525f, 0.0f, 0.209f, 0.243f, 1.0f, -0.526f, 0.0f, 0.205f, 0.265f, 1.0f, + -0.526f, 0.0f, 0.202f, 0.286f, 1.0f, -0.527f, 0.0f, 0.198f, 0.306f, 1.0f, -0.527f, 0.0f, 0.195f, 0.326f, 1.0f, -0.528f, 0.0f, 0.191f, 0.345f, 1.0f, + -0.528f, 0.0f, 0.187f, 0.363f, 1.0f, -0.529f, 0.0f, 0.184f, 0.38f, 1.0f, -0.529f, 0.0f, 0.18f, 0.395f, 1.0f, -0.529f, 0.0f, 0.176f, 0.41f, 1.0f, + -0.53f, 0.0f, 0.173f, 0.424f, 1.0f, -0.53f, 0.0f, 0.169f, 0.438f, 1.0f, -0.53f, 0.0f, 0.165f, 0.452f, 1.0f, -0.53f, 0.0f, 0.161f, 0.465f, 1.0f, + -0.53f, 0.0f, 0.157f, 0.478f, 1.0f, -0.53f, 0.0f, 0.154f, 0.492f, 1.0f, -0.53f, 0.0f, 0.15f, 0.505f, 1.0f, -0.53f, 0.0f, 0.146f, 0.517f, 1.0f, + -0.53f, 0.0f, 0.142f, 0.53f, 1.0f, -0.529f, 0.0f, 0.138f, 0.542f, 1.0f, -0.529f, 0.0f, 0.134f, 0.553f, 1.0f, -0.528f, 0.0f, 0.13f, 0.564f, 1.0f, + -0.528f, 0.0f, 0.127f, 0.574f, 1.0f, -0.527f, 0.0f, 0.123f, 0.583f, 1.0f, -0.527f, 0.0f, 0.119f, 0.592f, 1.0f, -0.526f, 0.0f, 0.115f, 0.6f, 1.0f, + -0.526f, 0.0f, 0.111f, 0.608f, 1.0f, -0.525f, 0.0f, 0.108f, 0.615f, 1.0f, -0.524f, 0.0f, 0.104f, 0.622f, 1.0f, -0.523f, 0.0f, 0.1f, 0.628f, 1.0f, + -0.522f, 0.0f, 0.097f, 0.635f, 1.0f, -0.521f, 0.0f, 0.093f, 0.641f, 1.0f, -0.52f, 0.0f, 0.089f, 0.647f, 1.0f, -0.519f, 0.0f, 0.086f, 0.653f, 1.0f, + -0.518f, 0.0f, 0.082f, 0.659f, 1.0f, -0.517f, 0.0f, 0.079f, 0.664f, 1.0f, -0.515f, 0.0f, 0.075f, 0.67f, 1.0f, -0.514f, 0.0f, 0.072f, 0.675f, 1.0f, + -0.513f, 0.0f, 0.069f, 0.68f, 1.0f, -0.511f, 0.0f, 0.065f, 0.685f, 1.0f, -0.51f, 0.0f, 0.062f, 0.69f, 1.0f, -0.509f, 0.0f, 0.059f, 0.695f, 1.0f, + -0.507f, 0.0f, 0.056f, 0.7f, 1.0f, -0.505f, 0.0f, 0.053f, 0.704f, 1.0f, -0.504f, 0.0f, 0.049f, 0.709f, 1.0f, -0.502f, 0.0f, 0.046f, 0.714f, 1.0f, + -0.5f, 0.0f, 0.043f, 0.719f, 1.0f, -0.499f, 0.0f, 0.04f, 0.724f, 1.0f, -0.497f, 0.0f, 0.038f, 0.73f, 1.0f, -0.495f, 0.0f, 0.035f, 0.735f, 1.0f, + -0.493f, 0.0f, 0.032f, 0.741f, 1.0f, -0.491f, 0.0f, 0.029f, 0.748f, 1.0f, -0.489f, 0.0f, 0.026f, 0.754f, 1.0f, -0.488f, -0.0f, 0.024f, 0.76f, 1.0f, + -0.486f, -0.0f, 0.022f, 0.767f, 1.0f, -0.485f, -0.0f, 0.019f, 0.773f, 1.0f, -0.483f, -0.0f, 0.017f, 0.779f, 1.0f, -0.482f, -0.0f, 0.015f, 0.785f, 1.0f, + -0.48f, -0.0f, 0.013f, 0.79f, 1.0f, -0.478f, -0.0f, 0.01f, 0.795f, 1.0f, -0.476f, -0.0f, 0.008f, 0.8f, 1.0f, -0.474f, -0.0f, 0.006f, 0.804f, 1.0f, + -0.472f, -0.0f, 0.004f, 0.808f, 1.0f, -0.47f, -0.0f, 0.002f, 0.811f, 1.0f, -0.468f, -0.0f, -0.0f, 0.814f, 1.0f, -0.466f, -0.0f, -0.002f, 0.816f, 1.0f, + -0.464f, -0.0f, -0.004f, 0.818f, 1.0f, -0.461f, -0.0f, -0.006f, 0.82f, 1.0f, -0.459f, -0.0f, -0.008f, 0.822f, 1.0f, -0.456f, -0.0f, -0.01f, 0.823f, 1.0f, + -0.454f, -0.0f, -0.012f, 0.825f, 1.0f, -0.451f, -0.0f, -0.014f, 0.826f, 1.0f, -0.448f, -0.0f, -0.016f, 0.827f, 1.0f, -0.445f, -0.0f, -0.018f, 0.828f, 1.0f, + -0.442f, -0.0f, -0.02f, 0.829f, 1.0f, -0.439f, -0.0f, -0.022f, 0.829f, 1.0f, -0.436f, -0.0f, -0.024f, 0.83f, 1.0f, -0.433f, -0.0f, -0.026f, 0.83f, 1.0f, + -0.43f, -0.0f, -0.027f, 0.83f, 1.0f, -0.426f, -0.0f, -0.029f, 0.83f, 1.0f, -0.423f, 0.0f, -0.031f, 0.83f, 1.0f, -0.42f, 0.0f, -0.032f, 0.83f, 1.0f, + -0.417f, 0.0f, -0.033f, 0.831f, 1.0f, -0.414f, 0.0f, -0.034f, 0.831f, 1.0f, -0.411f, 0.0f, -0.035f, 0.831f, 1.0f, -0.408f, 0.0f, -0.037f, 0.831f, 1.0f, + -0.405f, 0.0f, -0.038f, 0.831f, 1.0f, -0.402f, 0.0f, -0.039f, 0.831f, 1.0f, -0.399f, 0.0f, -0.039f, 0.831f, 1.0f, -0.396f, 0.0f, -0.04f, 0.832f, 1.0f, + -0.393f, 0.0f, -0.041f, 0.832f, 1.0f, -0.389f, 0.0f, -0.042f, 0.832f, 1.0f, -0.386f, 0.0f, -0.043f, 0.832f, 1.0f, -0.383f, 0.0f, -0.044f, 0.832f, 1.0f, + -0.379f, 0.0f, -0.044f, 0.832f, 1.0f, -0.376f, 0.0f, -0.045f, 0.832f, 1.0f, -0.372f, 0.0f, -0.045f, 0.832f, 1.0f, -0.369f, 0.0f, -0.046f, 0.832f, 1.0f, + -0.366f, 0.0f, -0.047f, 0.832f, 1.0f, -0.362f, 0.0f, -0.047f, 0.832f, 1.0f, -0.359f, 0.0f, -0.047f, 0.831f, 1.0f, -0.355f, 0.0f, -0.048f, 0.831f, 1.0f, + -0.352f, 0.0f, -0.048f, 0.83f, 1.0f, -0.348f, 0.0f, -0.048f, 0.83f, 1.0f, -0.345f, 0.0f, -0.049f, 0.829f, 1.0f, -0.341f, 0.0f, -0.049f, 0.828f, 1.0f, + -0.338f, 0.0f, -0.049f, 0.827f, 1.0f, -0.334f, 0.0f, -0.049f, 0.826f, 1.0f, -0.331f, 0.0f, -0.049f, 0.823f, 1.0f, -0.327f, 0.0f, -0.049f, 0.82f, 1.0f, + -0.323f, 0.0f, -0.048f, 0.816f, 1.0f, -0.32f, 0.0f, -0.048f, 0.811f, 1.0f, -0.316f, 0.0f, -0.048f, 0.804f, 1.0f, -0.313f, 0.0f, -0.048f, 0.797f, 1.0f, + -0.309f, 0.0f, -0.047f, 0.79f, 1.0f, -0.306f, 0.0f, -0.047f, 0.782f, 1.0f, -0.302f, 0.0f, -0.046f, 0.774f, 1.0f, -0.299f, 0.0f, -0.045f, 0.767f, 1.0f, + -0.295f, 0.0f, -0.044f, 0.76f, 1.0f, -0.292f, 0.0f, -0.044f, 0.753f, 1.0f, -0.288f, 0.0f, -0.043f, 0.748f, 1.0f, -0.285f, 0.0f, -0.042f, 0.742f, 1.0f, + -0.282f, 0.0f, -0.041f, 0.738f, 1.0f, -0.278f, 0.0f, -0.04f, 0.734f, 1.0f, -0.275f, 0.0f, -0.039f, 0.73f, 1.0f, -0.272f, 0.0f, -0.037f, 0.726f, 1.0f, + -0.269f, 0.0f, -0.036f, 0.723f, 1.0f, -0.266f, 0.0f, -0.035f, 0.72f, 1.0f, -0.263f, 0.0f, -0.034f, 0.717f, 1.0f, -0.26f, 0.0f, -0.032f, 0.713f, 1.0f, + -0.257f, 0.0f, -0.031f, 0.71f, 1.0f, -0.255f, 0.0f, -0.029f, 0.706f, 1.0f, -0.252f, 0.0f, -0.028f, 0.702f, 1.0f, -0.249f, 0.0f, -0.026f, 0.698f, 1.0f, + -0.247f, 0.0f, -0.025f, 0.693f, 1.0f, -0.244f, 0.0f, -0.023f, 0.688f, 1.0f, -0.242f, 0.0f, -0.021f, 0.684f, 1.0f, -0.239f, 0.0f, -0.02f, 0.679f, 1.0f, + -0.237f, 0.0f, -0.018f, 0.675f, 1.0f, -0.234f, 0.0f, -0.016f, 0.671f, 1.0f, -0.232f, 0.0f, -0.014f, 0.667f, 1.0f, -0.23f, 0.0f, -0.013f, 0.663f, 1.0f, + -0.228f, 0.0f, -0.011f, 0.66f, 1.0f, -0.225f, 0.0f, -0.009f, 0.657f, 1.0f, -0.223f, 0.0f, -0.007f, 0.654f, 1.0f, -0.221f, 0.0f, -0.005f, 0.651f, 1.0f, + -0.219f, 0.0f, -0.003f, 0.649f, 1.0f, -0.217f, 0.0f, -0.001f, 0.645f, 1.0f, -0.215f, 0.0f, 0.002f, 0.642f, 1.0f, -0.213f, 0.0f, 0.004f, 0.639f, 1.0f, + -0.211f, 0.0f, 0.006f, 0.635f, 1.0f, -0.209f, 0.0f, 0.008f, 0.631f, 1.0f, -0.207f, 0.0f, 0.011f, 0.627f, 1.0f, -0.206f, 0.0f, 0.013f, 0.623f, 1.0f, + -0.204f, 0.0f, 0.016f, 0.619f, 1.0f, -0.202f, 0.0f, 0.018f, 0.615f, 1.0f, -0.2f, 0.0f, 0.021f, 0.61f, 1.0f, -0.199f, 0.0f, 0.023f, 0.606f, 1.0f, + -0.197f, 0.0f, 0.026f, 0.602f, 1.0f, -0.195f, 0.0f, 0.029f, 0.598f, 1.0f, -0.194f, 0.0f, 0.032f, 0.595f, 1.0f, -0.192f, 0.0f, 0.034f, 0.592f, 1.0f, + -0.191f, 0.0f, 0.037f, 0.589f, 1.0f, -0.19f, 0.0f, 0.04f, 0.587f, 1.0f, -0.188f, 0.0f, 0.043f, 0.585f, 1.0f, -0.187f, 0.0f, 0.046f, 0.584f, 1.0f, + -0.186f, 0.0f, 0.05f, 0.583f, 1.0f, -0.185f, 0.0f, 0.053f, 0.582f, 1.0f, -0.183f, 0.0f, 0.056f, 0.581f, 1.0f, -0.182f, 0.0f, 0.059f, 0.581f, 1.0f, + -0.181f, 0.0f, 0.062f, 0.581f, 1.0f, -0.18f, 0.0f, 0.066f, 0.581f, 1.0f, -0.179f, 0.0f, 0.069f, 0.58f, 1.0f, -0.178f, 0.0f, 0.072f, 0.58f, 1.0f, + -0.177f, 0.0f, 0.076f, 0.58f, 1.0f, -0.177f, 0.0f, 0.079f, 0.58f, 1.0f, -0.176f, 0.0f, 0.083f, 0.58f, 1.0f, -0.175f, 0.0f, 0.086f, 0.58f, 1.0f, + -0.174f, 0.0f, 0.09f, 0.58f, 1.0f, -0.174f, 0.0f, 0.093f, 0.58f, 1.0f, -0.173f, 0.0f, 0.097f, 0.58f, 1.0f, -0.172f, 0.0f, 0.1f, 0.58f, 1.0f, + -0.172f, 0.0f, 0.104f, 0.58f, 1.0f, -0.171f, 0.0f, 0.108f, 0.579f, 1.0f, -0.171f, 0.0f, 0.111f, 0.579f, 1.0f, -0.17f, 0.0f, 0.115f, 0.578f, 1.0f, + -0.17f, 0.0f, 0.119f, 0.578f, 1.0f, -0.17f, 0.0f, 0.122f, 0.577f, 1.0f, -0.169f, 0.0f, 0.126f, 0.577f, 1.0f, -0.169f, 0.0f, 0.13f, 0.576f, 1.0f, + -0.169f, 0.0f, 0.134f, 0.576f, 1.0f, -0.169f, 0.0f, 0.137f, 0.575f, 1.0f, -0.169f, 0.0f, 0.141f, 0.575f, 1.0f, -0.169f, 0.0f, 0.145f, 0.574f, 1.0f, + -0.169f, 0.0f, 0.149f, 0.572f, 1.0f, -0.169f, 0.0f, 0.153f, 0.571f, 1.0f, -0.169f, 0.0f, 0.157f, 0.569f, 1.0f, -0.169f, 0.0f, 0.16f, 0.566f, 1.0f, + -0.169f, 0.0f, 0.164f, 0.562f, 1.0f, -0.17f, 0.0f, 0.168f, 0.558f, 1.0f, -0.17f, 0.0f, 0.172f, 0.553f, 1.0f, -0.17f, 0.0f, 0.176f, 0.547f, 1.0f, + -0.171f, 0.0f, 0.18f, 0.539f, 1.0f, -0.171f, 0.0f, 0.183f, 0.531f, 1.0f, -0.172f, 0.0f, 0.187f, 0.522f, 1.0f, -0.172f, 0.0f, 0.191f, 0.513f, 1.0f, + -0.173f, 0.0f, 0.194f, 0.503f, 1.0f, -0.173f, 0.0f, 0.198f, 0.493f, 1.0f, -0.174f, 0.0f, 0.202f, 0.483f, 1.0f, -0.175f, 0.0f, 0.205f, 0.473f, 1.0f, + -0.176f, 0.0f, 0.209f, 0.464f, 1.0f, -0.177f, 0.0f, 0.212f, 0.455f, 1.0f, -0.178f, 0.0f, 0.215f, 0.446f, 1.0f, -0.178f, 0.0f, 0.219f, 0.438f, 1.0f, + -0.179f, 0.0f, 0.222f, 0.428f, 1.0f, -0.18f, 0.0f, 0.226f, 0.418f, 1.0f, -0.182f, 0.0f, 0.229f, 0.407f, 1.0f, -0.183f, 0.0f, 0.232f, 0.394f, 1.0f, + -0.184f, 0.0f, 0.236f, 0.38f, 1.0f, -0.185f, 0.0f, 0.239f, 0.364f, 1.0f, -0.186f, 0.0f, 0.242f, 0.348f, 1.0f, -0.187f, 0.0f, 0.245f, 0.33f, 1.0f, + -0.188f, 0.0f, 0.249f, 0.311f, 1.0f, -0.19f, 0.0f, 0.252f, 0.293f, 1.0f, -0.191f, 0.0f, 0.255f, 0.275f, 1.0f, -0.192f, 0.0f, 0.258f, 0.258f, 1.0f, + -0.194f, 0.0f, 0.261f, 0.242f, 1.0f, -0.195f, 0.0f, 0.264f, 0.228f, 1.0f, -0.196f, 0.0f, 0.267f, 0.214f, 1.0f, -0.198f, 0.0f, 0.27f, 0.202f, 1.0f, + -0.199f, 0.0f, 0.273f, 0.191f, 1.0f, -0.201f, 0.0f, 0.276f, 0.181f, 1.0f, -0.202f, 0.0f, 0.279f, 0.171f, 1.0f, -0.204f, 0.0f, 0.282f, 0.162f, 1.0f, + -0.205f, 0.0f, 0.285f, 0.152f, 1.0f, -0.206f, 0.0f, 0.287f, 0.143f, 1.0f, -0.208f, 0.0f, 0.29f, 0.134f, 1.0f, -0.21f, 0.0f, 0.293f, 0.126f, 1.0f, + -0.211f, 0.0f, 0.295f, 0.117f, 1.0f, -0.213f, 0.0f, 0.298f, 0.109f, 1.0f, -0.214f, 0.0f, 0.301f, 0.101f, 1.0f, -0.216f, 0.0f, 0.303f, 0.094f, 1.0f, + -0.217f, 0.0f, 0.306f, 0.087f, 1.0f, -0.219f, 0.0f, 0.308f, 0.081f, 1.0f, -0.221f, 0.0f, 0.311f, 0.076f, 1.0f, -0.223f, 0.0f, 0.313f, 0.071f, 1.0f, + -0.224f, 0.0f, 0.316f, 0.067f, 1.0f, -0.226f, 0.0f, 0.318f, 0.065f, 1.0f, -0.228f, 0.0f, 0.321f, 0.062f, 1.0f, -0.23f, 0.0f, 0.323f, 0.061f, 1.0f, + -0.232f, 0.0f, 0.326f, 0.06f, 1.0f, -0.233f, 0.0f, 0.328f, 0.06f, 1.0f, -0.235f, 0.0f, 0.331f, 0.061f, 1.0f, -0.237f, 0.0f, 0.334f, 0.061f, 1.0f, + -0.239f, 0.0f, 0.336f, 0.062f, 1.0f, -0.241f, 0.0f, 0.339f, 0.063f, 1.0f, -0.243f, 0.0f, 0.341f, 0.064f, 1.0f, -0.245f, 0.0f, 0.344f, 0.065f, 1.0f, + -0.248f, 0.0f, 0.346f, 0.065f, 1.0f, -0.25f, 0.0f, 0.349f, 0.065f, 1.0f, -0.252f, 0.0f, 0.351f, 0.064f, 1.0f, -0.254f, 0.0f, 0.354f, 0.062f, 1.0f, + -0.256f, 0.0f, 0.356f, 0.06f, 1.0f, -0.258f, 0.0f, 0.359f, 0.058f, 1.0f, -0.261f, 0.0f, 0.361f, 0.055f, 1.0f, -0.263f, 0.0f, 0.364f, 0.051f, 1.0f, + -0.265f, 0.0f, 0.366f, 0.046f, 1.0f, -0.267f, 0.0f, 0.368f, 0.04f, 1.0f, -0.269f, 0.0f, 0.37f, 0.034f, 1.0f, -0.272f, 0.0f, 0.373f, 0.027f, 1.0f, + -0.274f, 0.0f, 0.375f, 0.019f, 1.0f, -0.276f, 0.0f, 0.377f, 0.012f, 1.0f, -0.278f, 0.0f, 0.379f, 0.007f, 1.0f, -0.28f, 0.0f, 0.381f, 0.003f, 1.0f, + -0.282f, 0.0f, 0.383f, 0.001f, 1.0f, -0.284f, 0.0f, 0.385f, 0.0f, 1.0f, -0.286f, 0.0f, 0.387f, 0.0f, 1.0f, -0.287f, 0.0f, 0.388f, 0.0f, 1.0f, + -0.289f, 0.0f, 0.39f, 0.0f, 1.0f, +}; + +static const float data22[309 * GP_PRIM_DATABUF_SIZE] = { + 0.294f, 0.0f, 0.372f, 0.0f, 1.0f, 0.291f, 0.0f, 0.37f, 0.001f, 1.0f, 0.289f, 0.0f, 0.368f, 0.002f, 1.0f, 0.286f, 0.0f, 0.366f, 0.003f, 1.0f, + 0.284f, 0.0f, 0.364f, 0.006f, 1.0f, 0.282f, 0.0f, 0.362f, 0.01f, 1.0f, 0.279f, 0.0f, 0.36f, 0.015f, 1.0f, 0.277f, 0.0f, 0.358f, 0.022f, 1.0f, + 0.274f, 0.0f, 0.356f, 0.03f, 1.0f, 0.272f, 0.0f, 0.353f, 0.04f, 1.0f, 0.269f, 0.0f, 0.351f, 0.051f, 1.0f, 0.267f, 0.0f, 0.349f, 0.062f, 1.0f, + 0.265f, 0.0f, 0.347f, 0.074f, 1.0f, 0.262f, 0.0f, 0.344f, 0.086f, 1.0f, 0.26f, 0.0f, 0.342f, 0.097f, 1.0f, 0.258f, 0.0f, 0.34f, 0.108f, 1.0f, + 0.256f, 0.0f, 0.337f, 0.119f, 1.0f, 0.253f, 0.0f, 0.335f, 0.128f, 1.0f, 0.251f, 0.0f, 0.333f, 0.137f, 1.0f, 0.249f, 0.0f, 0.33f, 0.145f, 1.0f, + 0.247f, 0.0f, 0.328f, 0.153f, 1.0f, 0.246f, 0.0f, 0.325f, 0.161f, 1.0f, 0.244f, 0.0f, 0.323f, 0.168f, 1.0f, 0.242f, 0.0f, 0.321f, 0.176f, 1.0f, + 0.24f, 0.0f, 0.318f, 0.183f, 1.0f, 0.239f, 0.0f, 0.316f, 0.191f, 1.0f, 0.237f, 0.0f, 0.314f, 0.198f, 1.0f, 0.235f, 0.0f, 0.311f, 0.206f, 1.0f, + 0.233f, 0.0f, 0.309f, 0.214f, 1.0f, 0.231f, 0.0f, 0.306f, 0.223f, 1.0f, 0.23f, 0.0f, 0.304f, 0.231f, 1.0f, 0.228f, 0.0f, 0.301f, 0.24f, 1.0f, + 0.226f, 0.0f, 0.299f, 0.248f, 1.0f, 0.224f, 0.0f, 0.296f, 0.256f, 1.0f, 0.223f, 0.0f, 0.294f, 0.264f, 1.0f, 0.221f, 0.0f, 0.291f, 0.272f, 1.0f, + 0.219f, 0.0f, 0.288f, 0.28f, 1.0f, 0.218f, 0.0f, 0.286f, 0.287f, 1.0f, 0.216f, 0.0f, 0.283f, 0.294f, 1.0f, 0.214f, 0.0f, 0.281f, 0.301f, 1.0f, + 0.213f, 0.0f, 0.278f, 0.307f, 1.0f, 0.211f, 0.0f, 0.275f, 0.314f, 1.0f, 0.21f, 0.0f, 0.273f, 0.32f, 1.0f, 0.208f, 0.0f, 0.27f, 0.327f, 1.0f, + 0.206f, 0.0f, 0.267f, 0.333f, 1.0f, 0.205f, 0.0f, 0.265f, 0.339f, 1.0f, 0.204f, 0.0f, 0.262f, 0.345f, 1.0f, 0.202f, 0.0f, 0.259f, 0.351f, 1.0f, + 0.201f, 0.0f, 0.256f, 0.357f, 1.0f, 0.199f, 0.0f, 0.253f, 0.362f, 1.0f, 0.198f, 0.0f, 0.25f, 0.368f, 1.0f, 0.197f, 0.0f, 0.247f, 0.373f, 1.0f, + 0.195f, 0.0f, 0.244f, 0.379f, 1.0f, 0.194f, 0.0f, 0.241f, 0.383f, 1.0f, 0.193f, 0.0f, 0.238f, 0.388f, 1.0f, 0.192f, 0.0f, 0.235f, 0.392f, 1.0f, + 0.191f, 0.0f, 0.232f, 0.396f, 1.0f, 0.19f, 0.0f, 0.229f, 0.399f, 1.0f, 0.189f, 0.0f, 0.226f, 0.402f, 1.0f, 0.188f, 0.0f, 0.222f, 0.405f, 1.0f, + 0.187f, 0.0f, 0.219f, 0.407f, 1.0f, 0.186f, 0.0f, 0.216f, 0.409f, 1.0f, 0.185f, 0.0f, 0.213f, 0.411f, 1.0f, 0.184f, 0.0f, 0.209f, 0.412f, 1.0f, + 0.183f, 0.0f, 0.206f, 0.413f, 1.0f, 0.183f, 0.0f, 0.203f, 0.414f, 1.0f, 0.182f, 0.0f, 0.199f, 0.415f, 1.0f, 0.181f, 0.0f, 0.196f, 0.416f, 1.0f, + 0.181f, 0.0f, 0.193f, 0.417f, 1.0f, 0.18f, 0.0f, 0.189f, 0.417f, 1.0f, 0.18f, 0.0f, 0.186f, 0.418f, 1.0f, 0.179f, 0.0f, 0.182f, 0.419f, 1.0f, + 0.179f, 0.0f, 0.179f, 0.421f, 1.0f, 0.179f, 0.0f, 0.176f, 0.422f, 1.0f, 0.178f, 0.0f, 0.172f, 0.423f, 1.0f, 0.178f, 0.0f, 0.169f, 0.425f, 1.0f, + 0.178f, 0.0f, 0.165f, 0.427f, 1.0f, 0.178f, 0.0f, 0.162f, 0.429f, 1.0f, 0.178f, 0.0f, 0.158f, 0.431f, 1.0f, 0.178f, 0.0f, 0.155f, 0.434f, 1.0f, + 0.178f, 0.0f, 0.152f, 0.436f, 1.0f, 0.178f, 0.0f, 0.148f, 0.439f, 1.0f, 0.178f, 0.0f, 0.145f, 0.442f, 1.0f, 0.178f, 0.0f, 0.141f, 0.446f, 1.0f, + 0.178f, 0.0f, 0.138f, 0.449f, 1.0f, 0.178f, 0.0f, 0.134f, 0.453f, 1.0f, 0.178f, 0.0f, 0.131f, 0.458f, 1.0f, 0.179f, 0.0f, 0.127f, 0.462f, 1.0f, + 0.179f, 0.0f, 0.124f, 0.467f, 1.0f, 0.179f, 0.0f, 0.12f, 0.472f, 1.0f, 0.18f, 0.0f, 0.117f, 0.478f, 1.0f, 0.18f, 0.0f, 0.113f, 0.483f, 1.0f, + 0.181f, 0.0f, 0.11f, 0.489f, 1.0f, 0.182f, 0.0f, 0.106f, 0.494f, 1.0f, 0.182f, 0.0f, 0.103f, 0.5f, 1.0f, 0.183f, 0.0f, 0.099f, 0.505f, 1.0f, + 0.184f, 0.0f, 0.096f, 0.511f, 1.0f, 0.185f, 0.0f, 0.092f, 0.516f, 1.0f, 0.185f, 0.0f, 0.089f, 0.521f, 1.0f, 0.186f, 0.0f, 0.086f, 0.525f, 1.0f, + 0.187f, 0.0f, 0.082f, 0.53f, 1.0f, 0.188f, 0.0f, 0.079f, 0.534f, 1.0f, 0.189f, 0.0f, 0.076f, 0.537f, 1.0f, 0.191f, 0.0f, 0.073f, 0.541f, 1.0f, + 0.192f, 0.0f, 0.069f, 0.544f, 1.0f, 0.193f, 0.0f, 0.066f, 0.547f, 1.0f, 0.194f, 0.0f, 0.063f, 0.55f, 1.0f, 0.196f, 0.0f, 0.061f, 0.553f, 1.0f, + 0.197f, 0.0f, 0.058f, 0.556f, 1.0f, 0.198f, 0.0f, 0.055f, 0.559f, 1.0f, 0.2f, 0.0f, 0.052f, 0.562f, 1.0f, 0.201f, 0.0f, 0.049f, 0.564f, 1.0f, + 0.203f, 0.0f, 0.047f, 0.566f, 1.0f, 0.205f, 0.0f, 0.044f, 0.569f, 1.0f, 0.206f, 0.0f, 0.042f, 0.571f, 1.0f, 0.208f, 0.0f, 0.039f, 0.573f, 1.0f, + 0.21f, 0.0f, 0.037f, 0.575f, 1.0f, 0.212f, 0.0f, 0.035f, 0.576f, 1.0f, 0.214f, 0.0f, 0.032f, 0.578f, 1.0f, 0.215f, 0.0f, 0.03f, 0.579f, 1.0f, + 0.217f, 0.0f, 0.028f, 0.581f, 1.0f, 0.22f, 0.0f, 0.025f, 0.582f, 1.0f, 0.222f, 0.0f, 0.023f, 0.583f, 1.0f, 0.224f, 0.0f, 0.021f, 0.585f, 1.0f, + 0.226f, 0.0f, 0.019f, 0.587f, 1.0f, 0.228f, 0.0f, 0.016f, 0.589f, 1.0f, 0.231f, 0.0f, 0.014f, 0.592f, 1.0f, 0.233f, 0.0f, 0.012f, 0.596f, 1.0f, + 0.236f, 0.0f, 0.01f, 0.599f, 1.0f, 0.238f, 0.0f, 0.008f, 0.604f, 1.0f, 0.241f, 0.0f, 0.006f, 0.608f, 1.0f, 0.243f, 0.0f, 0.004f, 0.612f, 1.0f, + 0.246f, 0.0f, 0.002f, 0.615f, 1.0f, 0.249f, 0.0f, 0.0f, 0.619f, 1.0f, 0.251f, 0.0f, -0.002f, 0.622f, 1.0f, 0.254f, 0.0f, -0.003f, 0.624f, 1.0f, + 0.257f, 0.0f, -0.005f, 0.626f, 1.0f, 0.26f, 0.0f, -0.007f, 0.628f, 1.0f, 0.263f, 0.0f, -0.008f, 0.63f, 1.0f, 0.266f, 0.0f, -0.01f, 0.632f, 1.0f, + 0.269f, 0.0f, -0.011f, 0.634f, 1.0f, 0.272f, 0.0f, -0.013f, 0.636f, 1.0f, 0.275f, 0.0f, -0.014f, 0.638f, 1.0f, 0.278f, 0.0f, -0.015f, 0.64f, 1.0f, + 0.281f, 0.0f, -0.017f, 0.642f, 1.0f, 0.284f, 0.0f, -0.018f, 0.644f, 1.0f, 0.288f, 0.0f, -0.019f, 0.647f, 1.0f, 0.291f, 0.0f, -0.02f, 0.649f, 1.0f, + 0.294f, 0.0f, -0.021f, 0.651f, 1.0f, 0.297f, 0.0f, -0.022f, 0.653f, 1.0f, 0.301f, 0.0f, -0.023f, 0.656f, 1.0f, 0.304f, 0.0f, -0.024f, 0.658f, 1.0f, + 0.307f, 0.0f, -0.025f, 0.659f, 1.0f, 0.31f, 0.0f, -0.026f, 0.661f, 1.0f, 0.314f, 0.0f, -0.027f, 0.662f, 1.0f, 0.317f, 0.0f, -0.027f, 0.664f, 1.0f, + 0.32f, 0.0f, -0.028f, 0.665f, 1.0f, 0.324f, 0.0f, -0.028f, 0.665f, 1.0f, 0.327f, 0.0f, -0.029f, 0.666f, 1.0f, 0.33f, 0.0f, -0.029f, 0.666f, 1.0f, + 0.334f, 0.0f, -0.029f, 0.667f, 1.0f, 0.337f, 0.0f, -0.03f, 0.667f, 1.0f, 0.341f, 0.0f, -0.03f, 0.668f, 1.0f, 0.344f, 0.0f, -0.03f, 0.668f, 1.0f, + 0.348f, 0.0f, -0.03f, 0.668f, 1.0f, 0.351f, 0.0f, -0.03f, 0.668f, 1.0f, 0.354f, 0.0f, -0.03f, 0.668f, 1.0f, 0.358f, 0.0f, -0.029f, 0.668f, 1.0f, + 0.361f, 0.0f, -0.029f, 0.668f, 1.0f, 0.365f, 0.0f, -0.029f, 0.668f, 1.0f, 0.368f, 0.0f, -0.028f, 0.668f, 1.0f, 0.372f, 0.0f, -0.028f, 0.668f, 1.0f, + 0.375f, 0.0f, -0.027f, 0.668f, 1.0f, 0.378f, 0.0f, -0.027f, 0.668f, 1.0f, 0.382f, 0.0f, -0.026f, 0.667f, 1.0f, 0.385f, 0.0f, -0.025f, 0.667f, 1.0f, + 0.388f, 0.0f, -0.025f, 0.666f, 1.0f, 0.392f, 0.0f, -0.024f, 0.666f, 1.0f, 0.395f, 0.0f, -0.023f, 0.665f, 1.0f, 0.398f, 0.0f, -0.022f, 0.664f, 1.0f, + 0.401f, 0.0f, -0.021f, 0.664f, 1.0f, 0.405f, 0.0f, -0.02f, 0.663f, 1.0f, 0.408f, 0.0f, -0.019f, 0.663f, 1.0f, 0.411f, 0.0f, -0.018f, 0.662f, 1.0f, + 0.414f, 0.0f, -0.017f, 0.662f, 1.0f, 0.417f, 0.0f, -0.016f, 0.662f, 1.0f, 0.42f, 0.0f, -0.015f, 0.662f, 1.0f, 0.423f, 0.0f, -0.014f, 0.661f, 1.0f, + 0.426f, 0.0f, -0.012f, 0.661f, 1.0f, 0.429f, 0.0f, -0.011f, 0.661f, 1.0f, 0.432f, 0.0f, -0.01f, 0.661f, 1.0f, 0.434f, 0.0f, -0.009f, 0.66f, 1.0f, + 0.437f, 0.0f, -0.007f, 0.66f, 1.0f, 0.44f, 0.0f, -0.006f, 0.659f, 1.0f, 0.442f, 0.0f, -0.005f, 0.659f, 1.0f, 0.445f, 0.0f, -0.003f, 0.658f, 1.0f, + 0.448f, 0.0f, -0.002f, 0.658f, 1.0f, 0.45f, 0.0f, -0.001f, 0.657f, 1.0f, 0.452f, 0.0f, 0.001f, 0.656f, 1.0f, 0.455f, 0.0f, 0.002f, 0.655f, 1.0f, + 0.457f, 0.0f, 0.004f, 0.654f, 1.0f, 0.459f, 0.0f, 0.005f, 0.653f, 1.0f, 0.462f, 0.0f, 0.007f, 0.652f, 1.0f, 0.464f, 0.0f, 0.009f, 0.651f, 1.0f, + 0.466f, 0.0f, 0.01f, 0.65f, 1.0f, 0.468f, 0.0f, 0.012f, 0.65f, 1.0f, 0.47f, 0.0f, 0.014f, 0.649f, 1.0f, 0.472f, 0.0f, 0.016f, 0.648f, 1.0f, + 0.474f, 0.0f, 0.018f, 0.647f, 1.0f, 0.476f, 0.0f, 0.019f, 0.646f, 1.0f, 0.478f, 0.0f, 0.021f, 0.645f, 1.0f, 0.479f, 0.0f, 0.023f, 0.644f, 1.0f, + 0.481f, 0.0f, 0.025f, 0.643f, 1.0f, 0.483f, 0.0f, 0.027f, 0.642f, 1.0f, 0.485f, 0.0f, 0.03f, 0.642f, 1.0f, 0.486f, 0.0f, 0.032f, 0.641f, 1.0f, + 0.488f, 0.0f, 0.034f, 0.64f, 1.0f, 0.49f, 0.0f, 0.036f, 0.639f, 1.0f, 0.491f, 0.0f, 0.038f, 0.638f, 1.0f, 0.493f, 0.0f, 0.041f, 0.637f, 1.0f, + 0.494f, 0.0f, 0.043f, 0.636f, 1.0f, 0.496f, 0.0f, 0.045f, 0.635f, 1.0f, 0.497f, 0.0f, 0.048f, 0.635f, 1.0f, 0.499f, 0.0f, 0.05f, 0.634f, 1.0f, + 0.5f, 0.0f, 0.053f, 0.633f, 1.0f, 0.502f, 0.0f, 0.055f, 0.632f, 1.0f, 0.503f, 0.0f, 0.058f, 0.631f, 1.0f, 0.505f, 0.0f, 0.06f, 0.63f, 1.0f, + 0.506f, 0.0f, 0.063f, 0.63f, 1.0f, 0.507f, 0.0f, 0.066f, 0.629f, 1.0f, 0.509f, 0.0f, 0.068f, 0.628f, 1.0f, 0.51f, 0.0f, 0.071f, 0.628f, 1.0f, + 0.511f, 0.0f, 0.074f, 0.627f, 1.0f, 0.513f, 0.0f, 0.077f, 0.626f, 1.0f, 0.514f, 0.0f, 0.079f, 0.625f, 1.0f, 0.515f, 0.0f, 0.082f, 0.625f, 1.0f, + 0.516f, 0.0f, 0.085f, 0.624f, 1.0f, 0.518f, 0.0f, 0.088f, 0.623f, 1.0f, 0.519f, 0.0f, 0.091f, 0.622f, 1.0f, 0.52f, 0.0f, 0.094f, 0.62f, 1.0f, + 0.521f, 0.0f, 0.098f, 0.619f, 1.0f, 0.522f, 0.0f, 0.101f, 0.617f, 1.0f, 0.523f, 0.0f, 0.104f, 0.615f, 1.0f, 0.524f, 0.0f, 0.107f, 0.613f, 1.0f, + 0.525f, 0.0f, 0.111f, 0.611f, 1.0f, 0.526f, 0.0f, 0.114f, 0.609f, 1.0f, 0.527f, 0.0f, 0.118f, 0.607f, 1.0f, 0.527f, 0.0f, 0.121f, 0.605f, 1.0f, + 0.528f, 0.0f, 0.124f, 0.603f, 1.0f, 0.529f, 0.0f, 0.128f, 0.602f, 1.0f, 0.529f, 0.0f, 0.132f, 0.6f, 1.0f, 0.53f, 0.0f, 0.135f, 0.599f, 1.0f, + 0.531f, 0.0f, 0.139f, 0.598f, 1.0f, 0.531f, 0.0f, 0.142f, 0.598f, 1.0f, 0.531f, 0.0f, 0.146f, 0.597f, 1.0f, 0.532f, 0.0f, 0.15f, 0.596f, 1.0f, + 0.532f, 0.0f, 0.154f, 0.596f, 1.0f, 0.532f, 0.0f, 0.157f, 0.595f, 1.0f, 0.532f, 0.0f, 0.161f, 0.595f, 1.0f, 0.532f, 0.0f, 0.165f, 0.594f, 1.0f, + 0.532f, 0.0f, 0.169f, 0.593f, 1.0f, 0.532f, 0.0f, 0.173f, 0.592f, 1.0f, 0.532f, 0.0f, 0.177f, 0.591f, 1.0f, 0.532f, 0.0f, 0.181f, 0.59f, 1.0f, + 0.531f, 0.0f, 0.185f, 0.589f, 1.0f, 0.531f, 0.0f, 0.189f, 0.588f, 1.0f, 0.53f, 0.0f, 0.194f, 0.587f, 1.0f, 0.529f, 0.0f, 0.198f, 0.586f, 1.0f, + 0.528f, 0.0f, 0.202f, 0.585f, 1.0f, 0.527f, 0.0f, 0.207f, 0.584f, 1.0f, 0.526f, 0.0f, 0.211f, 0.584f, 1.0f, 0.525f, 0.0f, 0.215f, 0.583f, 1.0f, + 0.523f, 0.0f, 0.22f, 0.583f, 1.0f, 0.522f, 0.0f, 0.224f, 0.583f, 1.0f, 0.52f, 0.0f, 0.229f, 0.582f, 1.0f, 0.518f, 0.0f, 0.234f, 0.582f, 1.0f, + 0.515f, 0.0f, 0.238f, 0.582f, 1.0f, 0.513f, 0.0f, 0.243f, 0.581f, 1.0f, 0.51f, 0.0f, 0.247f, 0.58f, 1.0f, 0.508f, 0.0f, 0.252f, 0.579f, 1.0f, + 0.505f, 0.0f, 0.257f, 0.578f, 1.0f, 0.502f, 0.0f, 0.261f, 0.576f, 1.0f, 0.499f, 0.0f, 0.266f, 0.573f, 1.0f, 0.496f, 0.0f, 0.27f, 0.57f, 1.0f, + 0.492f, 0.0f, 0.275f, 0.566f, 1.0f, 0.489f, 0.0f, 0.279f, 0.561f, 1.0f, 0.485f, 0.0f, 0.284f, 0.555f, 1.0f, 0.481f, 0.0f, 0.288f, 0.548f, 1.0f, + 0.478f, 0.0f, 0.293f, 0.54f, 1.0f, 0.473f, 0.0f, 0.297f, 0.531f, 1.0f, 0.469f, 0.0f, 0.301f, 0.521f, 1.0f, 0.465f, 0.0f, 0.305f, 0.509f, 1.0f, + 0.461f, 0.0f, 0.309f, 0.496f, 1.0f, 0.456f, 0.0f, 0.313f, 0.481f, 1.0f, 0.452f, 0.0f, 0.317f, 0.464f, 1.0f, 0.448f, 0.0f, 0.321f, 0.445f, 1.0f, + 0.443f, 0.0f, 0.324f, 0.424f, 1.0f, 0.438f, 0.0f, 0.328f, 0.401f, 1.0f, 0.434f, 0.0f, 0.331f, 0.374f, 1.0f, 0.429f, 0.0f, 0.334f, 0.346f, 1.0f, + 0.425f, 0.0f, 0.337f, 0.314f, 1.0f, 0.421f, 0.0f, 0.34f, 0.281f, 1.0f, 0.416f, 0.0f, 0.343f, 0.245f, 1.0f, 0.412f, 0.0f, 0.346f, 0.208f, 1.0f, + 0.408f, 0.0f, 0.349f, 0.169f, 1.0f, 0.404f, 0.0f, 0.351f, 0.13f, 1.0f, 0.401f, 0.0f, 0.354f, 0.089f, 1.0f, 0.398f, 0.0f, 0.356f, 0.054f, 1.0f, + 0.394f, 0.0f, 0.359f, 0.0f, 1.0f, +}; + +static const float data23[209 * GP_PRIM_DATABUF_SIZE] = { + -0.751f, 0.0f, 0.173f, 0.0f, 1.0f, -0.751f, 0.0f, 0.168f, 0.0f, 1.0f, -0.75f, 0.0f, 0.164f, 0.0f, 1.0f, -0.75f, 0.0f, 0.16f, 0.0f, 1.0f, + -0.75f, 0.0f, 0.156f, 0.0f, 1.0f, -0.749f, 0.0f, 0.152f, 0.0f, 1.0f, -0.749f, 0.0f, 0.148f, 0.0f, 1.0f, -0.748f, 0.0f, 0.144f, 0.0f, 1.0f, + -0.747f, 0.0f, 0.14f, 0.001f, 1.0f, -0.747f, 0.0f, 0.137f, 0.002f, 1.0f, -0.746f, 0.0f, 0.133f, 0.005f, 1.0f, -0.745f, 0.0f, 0.129f, 0.008f, 1.0f, + -0.745f, 0.0f, 0.125f, 0.013f, 1.0f, -0.744f, 0.0f, 0.122f, 0.02f, 1.0f, -0.743f, 0.0f, 0.118f, 0.028f, 1.0f, -0.742f, 0.0f, 0.115f, 0.038f, 1.0f, + -0.741f, 0.0f, 0.111f, 0.049f, 1.0f, -0.74f, 0.0f, 0.108f, 0.061f, 1.0f, -0.739f, 0.0f, 0.105f, 0.073f, 1.0f, -0.738f, 0.0f, 0.101f, 0.085f, 1.0f, + -0.736f, 0.0f, 0.098f, 0.097f, 1.0f, -0.735f, 0.0f, 0.095f, 0.109f, 1.0f, -0.734f, 0.0f, 0.091f, 0.119f, 1.0f, -0.732f, 0.0f, 0.088f, 0.129f, 1.0f, + -0.731f, 0.0f, 0.085f, 0.138f, 1.0f, -0.729f, 0.0f, 0.082f, 0.146f, 1.0f, -0.728f, 0.0f, 0.079f, 0.153f, 1.0f, -0.726f, 0.0f, 0.076f, 0.158f, 1.0f, + -0.725f, 0.0f, 0.073f, 0.163f, 1.0f, -0.723f, 0.0f, 0.07f, 0.167f, 1.0f, -0.722f, 0.0f, 0.067f, 0.17f, 1.0f, -0.72f, 0.0f, 0.065f, 0.173f, 1.0f, + -0.718f, 0.0f, 0.062f, 0.174f, 1.0f, -0.717f, 0.0f, 0.059f, 0.175f, 1.0f, -0.715f, 0.0f, 0.057f, 0.176f, 1.0f, -0.714f, 0.0f, 0.054f, 0.176f, 1.0f, + -0.712f, 0.0f, 0.051f, 0.176f, 1.0f, -0.71f, 0.0f, 0.049f, 0.176f, 1.0f, -0.709f, 0.0f, 0.046f, 0.176f, 1.0f, -0.707f, 0.0f, 0.043f, 0.176f, 1.0f, + -0.705f, 0.0f, 0.041f, 0.176f, 1.0f, -0.703f, 0.0f, 0.038f, 0.176f, 1.0f, -0.701f, 0.0f, 0.035f, 0.176f, 1.0f, -0.7f, 0.0f, 0.033f, 0.177f, 1.0f, + -0.698f, 0.0f, 0.03f, 0.177f, 1.0f, -0.696f, 0.0f, 0.027f, 0.178f, 1.0f, -0.694f, 0.0f, 0.024f, 0.179f, 1.0f, -0.692f, 0.0f, 0.022f, 0.18f, 1.0f, + -0.69f, 0.0f, 0.019f, 0.181f, 1.0f, -0.688f, 0.0f, 0.016f, 0.182f, 1.0f, -0.685f, 0.0f, 0.013f, 0.184f, 1.0f, -0.683f, 0.0f, 0.01f, 0.187f, 1.0f, + -0.681f, 0.0f, 0.007f, 0.19f, 1.0f, -0.679f, 0.0f, 0.004f, 0.194f, 1.0f, -0.677f, 0.0f, 0.001f, 0.198f, 1.0f, -0.675f, 0.0f, -0.002f, 0.203f, 1.0f, + -0.673f, 0.0f, -0.005f, 0.209f, 1.0f, -0.67f, 0.0f, -0.008f, 0.215f, 1.0f, -0.668f, 0.0f, -0.011f, 0.222f, 1.0f, -0.666f, 0.0f, -0.014f, 0.229f, 1.0f, + -0.664f, 0.0f, -0.017f, 0.237f, 1.0f, -0.661f, 0.0f, -0.02f, 0.246f, 1.0f, -0.659f, 0.0f, -0.023f, 0.255f, 1.0f, -0.657f, 0.0f, -0.025f, 0.264f, 1.0f, + -0.654f, 0.0f, -0.028f, 0.275f, 1.0f, -0.652f, 0.0f, -0.031f, 0.285f, 1.0f, -0.65f, 0.0f, -0.034f, 0.297f, 1.0f, -0.647f, 0.0f, -0.037f, 0.309f, 1.0f, + -0.644f, 0.0f, -0.04f, 0.322f, 1.0f, -0.642f, 0.0f, -0.043f, 0.335f, 1.0f, -0.639f, 0.0f, -0.046f, 0.348f, 1.0f, -0.636f, 0.0f, -0.049f, 0.361f, 1.0f, + -0.633f, 0.0f, -0.052f, 0.374f, 1.0f, -0.63f, 0.0f, -0.055f, 0.386f, 1.0f, -0.627f, 0.0f, -0.058f, 0.397f, 1.0f, -0.624f, 0.0f, -0.061f, 0.408f, 1.0f, + -0.62f, 0.0f, -0.064f, 0.418f, 1.0f, -0.617f, 0.0f, -0.067f, 0.427f, 1.0f, -0.614f, 0.0f, -0.07f, 0.435f, 1.0f, -0.611f, 0.0f, -0.073f, 0.443f, 1.0f, + -0.607f, 0.0f, -0.075f, 0.451f, 1.0f, -0.604f, 0.0f, -0.078f, 0.458f, 1.0f, -0.6f, 0.0f, -0.081f, 0.465f, 1.0f, -0.597f, 0.0f, -0.084f, 0.472f, 1.0f, + -0.593f, 0.0f, -0.086f, 0.479f, 1.0f, -0.59f, 0.0f, -0.089f, 0.486f, 1.0f, -0.586f, 0.0f, -0.092f, 0.492f, 1.0f, -0.583f, 0.0f, -0.094f, 0.499f, 1.0f, + -0.579f, 0.0f, -0.097f, 0.505f, 1.0f, -0.575f, 0.0f, -0.099f, 0.512f, 1.0f, -0.571f, 0.0f, -0.102f, 0.518f, 1.0f, -0.567f, 0.0f, -0.105f, 0.524f, 1.0f, + -0.563f, 0.0f, -0.107f, 0.53f, 1.0f, -0.559f, 0.0f, -0.11f, 0.536f, 1.0f, -0.555f, 0.0f, -0.112f, 0.541f, 1.0f, -0.551f, 0.0f, -0.115f, 0.546f, 1.0f, + -0.546f, 0.0f, -0.117f, 0.551f, 1.0f, -0.542f, 0.0f, -0.12f, 0.555f, 1.0f, -0.538f, 0.0f, -0.122f, 0.559f, 1.0f, -0.533f, 0.0f, -0.125f, 0.562f, 1.0f, + -0.529f, 0.0f, -0.127f, 0.565f, 1.0f, -0.525f, 0.0f, -0.129f, 0.568f, 1.0f, -0.52f, 0.0f, -0.132f, 0.57f, 1.0f, -0.516f, 0.0f, -0.134f, 0.572f, 1.0f, + -0.512f, 0.0f, -0.137f, 0.574f, 1.0f, -0.508f, 0.0f, -0.139f, 0.576f, 1.0f, -0.503f, 0.0f, -0.141f, 0.577f, 1.0f, -0.499f, 0.0f, -0.144f, 0.578f, 1.0f, + -0.495f, 0.0f, -0.146f, 0.579f, 1.0f, -0.491f, 0.0f, -0.148f, 0.579f, 1.0f, -0.487f, 0.0f, -0.151f, 0.578f, 1.0f, -0.483f, 0.0f, -0.153f, 0.577f, 1.0f, + -0.479f, 0.0f, -0.155f, 0.574f, 1.0f, -0.475f, 0.0f, -0.158f, 0.571f, 1.0f, -0.471f, 0.0f, -0.16f, 0.567f, 1.0f, -0.467f, 0.0f, -0.162f, 0.561f, 1.0f, + -0.463f, 0.0f, -0.165f, 0.555f, 1.0f, -0.459f, 0.0f, -0.167f, 0.548f, 1.0f, -0.456f, 0.0f, -0.169f, 0.54f, 1.0f, -0.452f, 0.0f, -0.172f, 0.532f, 1.0f, + -0.448f, 0.0f, -0.174f, 0.523f, 1.0f, -0.445f, 0.0f, -0.176f, 0.514f, 1.0f, -0.441f, 0.0f, -0.179f, 0.505f, 1.0f, -0.438f, 0.0f, -0.181f, 0.497f, 1.0f, + -0.435f, 0.0f, -0.183f, 0.488f, 1.0f, -0.431f, 0.0f, -0.185f, 0.48f, 1.0f, -0.428f, 0.0f, -0.188f, 0.472f, 1.0f, -0.425f, 0.0f, -0.19f, 0.464f, 1.0f, + -0.422f, 0.0f, -0.192f, 0.457f, 1.0f, -0.419f, 0.0f, -0.194f, 0.451f, 1.0f, -0.416f, 0.0f, -0.196f, 0.444f, 1.0f, -0.413f, 0.0f, -0.198f, 0.439f, 1.0f, + -0.41f, 0.0f, -0.2f, 0.434f, 1.0f, -0.407f, 0.0f, -0.202f, 0.429f, 1.0f, -0.404f, 0.0f, -0.204f, 0.426f, 1.0f, -0.401f, 0.0f, -0.206f, 0.422f, 1.0f, + -0.398f, 0.0f, -0.208f, 0.419f, 1.0f, -0.396f, 0.0f, -0.21f, 0.417f, 1.0f, -0.393f, 0.0f, -0.212f, 0.415f, 1.0f, -0.39f, 0.0f, -0.213f, 0.413f, 1.0f, + -0.388f, 0.0f, -0.215f, 0.412f, 1.0f, -0.385f, 0.0f, -0.217f, 0.411f, 1.0f, -0.382f, 0.0f, -0.219f, 0.41f, 1.0f, -0.38f, 0.0f, -0.221f, 0.41f, 1.0f, + -0.377f, 0.0f, -0.222f, 0.409f, 1.0f, -0.375f, 0.0f, -0.224f, 0.409f, 1.0f, -0.372f, 0.0f, -0.226f, 0.409f, 1.0f, -0.37f, 0.0f, -0.228f, 0.409f, 1.0f, + -0.367f, 0.0f, -0.229f, 0.409f, 1.0f, -0.365f, 0.0f, -0.231f, 0.409f, 1.0f, -0.362f, 0.0f, -0.233f, 0.409f, 1.0f, -0.36f, 0.0f, -0.235f, 0.409f, 1.0f, + -0.357f, 0.0f, -0.236f, 0.409f, 1.0f, -0.355f, 0.0f, -0.238f, 0.409f, 1.0f, -0.352f, 0.0f, -0.24f, 0.408f, 1.0f, -0.35f, 0.0f, -0.242f, 0.408f, 1.0f, + -0.348f, 0.0f, -0.243f, 0.407f, 1.0f, -0.345f, 0.0f, -0.245f, 0.406f, 1.0f, -0.343f, 0.0f, -0.247f, 0.405f, 1.0f, -0.34f, 0.0f, -0.249f, 0.404f, 1.0f, + -0.338f, 0.0f, -0.251f, 0.403f, 1.0f, -0.336f, 0.0f, -0.253f, 0.401f, 1.0f, -0.333f, 0.0f, -0.255f, 0.399f, 1.0f, -0.331f, 0.0f, -0.256f, 0.397f, 1.0f, + -0.329f, 0.0f, -0.258f, 0.394f, 1.0f, -0.327f, 0.0f, -0.26f, 0.391f, 1.0f, -0.324f, 0.0f, -0.262f, 0.387f, 1.0f, -0.322f, 0.0f, -0.264f, 0.383f, 1.0f, + -0.32f, 0.0f, -0.266f, 0.379f, 1.0f, -0.318f, 0.0f, -0.268f, 0.374f, 1.0f, -0.316f, 0.0f, -0.27f, 0.368f, 1.0f, -0.314f, 0.0f, -0.272f, 0.362f, 1.0f, + -0.312f, 0.0f, -0.275f, 0.356f, 1.0f, -0.309f, 0.0f, -0.277f, 0.349f, 1.0f, -0.307f, 0.0f, -0.279f, 0.341f, 1.0f, -0.305f, 0.0f, -0.281f, 0.333f, 1.0f, + -0.303f, 0.0f, -0.283f, 0.325f, 1.0f, -0.301f, 0.0f, -0.286f, 0.316f, 1.0f, -0.299f, 0.0f, -0.288f, 0.307f, 1.0f, -0.297f, 0.0f, -0.29f, 0.298f, 1.0f, + -0.295f, 0.0f, -0.293f, 0.289f, 1.0f, -0.293f, 0.0f, -0.295f, 0.279f, 1.0f, -0.291f, 0.0f, -0.298f, 0.269f, 1.0f, -0.29f, 0.0f, -0.3f, 0.259f, 1.0f, + -0.288f, 0.0f, -0.303f, 0.249f, 1.0f, -0.286f, 0.0f, -0.306f, 0.238f, 1.0f, -0.284f, 0.0f, -0.308f, 0.227f, 1.0f, -0.282f, 0.0f, -0.311f, 0.215f, 1.0f, + -0.28f, 0.0f, -0.314f, 0.203f, 1.0f, -0.278f, 0.0f, -0.317f, 0.191f, 1.0f, -0.277f, 0.0f, -0.32f, 0.178f, 1.0f, -0.275f, 0.0f, -0.323f, 0.165f, 1.0f, + -0.273f, 0.0f, -0.326f, 0.151f, 1.0f, -0.271f, 0.0f, -0.33f, 0.138f, 1.0f, -0.27f, 0.0f, -0.333f, 0.124f, 1.0f, -0.268f, 0.0f, -0.336f, 0.11f, 1.0f, + -0.267f, 0.0f, -0.34f, 0.097f, 1.0f, -0.265f, 0.0f, -0.343f, 0.085f, 1.0f, -0.264f, 0.0f, -0.346f, 0.073f, 1.0f, -0.262f, 0.0f, -0.35f, 0.062f, 1.0f, + -0.261f, 0.0f, -0.353f, 0.052f, 1.0f, -0.259f, 0.0f, -0.357f, 0.043f, 1.0f, -0.258f, 0.0f, -0.36f, 0.035f, 1.0f, -0.257f, 0.0f, -0.363f, 0.028f, 1.0f, + -0.255f, 0.0f, -0.366f, 0.021f, 1.0f, -0.254f, 0.0f, -0.369f, 0.016f, 1.0f, -0.253f, 0.0f, -0.372f, 0.01f, 1.0f, -0.252f, 0.0f, -0.375f, 0.006f, 1.0f, + -0.251f, 0.0f, -0.379f, 0.0f, 1.0f, +}; + +static const float data24[133 * GP_PRIM_DATABUF_SIZE] = { + 0.233f, 0.0f, -0.376f, 0.021f, 1.0f, 0.234f, 0.0f, -0.372f, 0.08f, 1.0f, 0.234f, 0.0f, -0.369f, 0.116f, 1.0f, 0.234f, 0.0f, -0.366f, 0.156f, 1.0f, + 0.235f, 0.0f, -0.362f, 0.191f, 1.0f, 0.236f, 0.0f, -0.359f, 0.222f, 1.0f, 0.236f, 0.0f, -0.356f, 0.248f, 1.0f, 0.237f, 0.0f, -0.353f, 0.27f, 1.0f, + 0.238f, 0.0f, -0.35f, 0.289f, 1.0f, 0.239f, 0.0f, -0.346f, 0.304f, 1.0f, 0.24f, 0.0f, -0.343f, 0.319f, 1.0f, 0.241f, 0.0f, -0.34f, 0.334f, 1.0f, + 0.242f, 0.0f, -0.337f, 0.35f, 1.0f, 0.243f, 0.0f, -0.335f, 0.367f, 1.0f, 0.244f, 0.0f, -0.332f, 0.385f, 1.0f, 0.245f, 0.0f, -0.329f, 0.401f, 1.0f, + 0.247f, 0.0f, -0.327f, 0.415f, 1.0f, 0.248f, 0.0f, -0.324f, 0.426f, 1.0f, 0.249f, 0.0f, -0.322f, 0.435f, 1.0f, 0.251f, 0.0f, -0.32f, 0.443f, 1.0f, + 0.252f, 0.0f, -0.318f, 0.449f, 1.0f, 0.254f, 0.0f, -0.316f, 0.455f, 1.0f, 0.255f, 0.0f, -0.314f, 0.461f, 1.0f, 0.257f, 0.0f, -0.312f, 0.467f, 1.0f, + 0.258f, 0.0f, -0.311f, 0.474f, 1.0f, 0.26f, 0.0f, -0.309f, 0.48f, 1.0f, 0.262f, 0.0f, -0.307f, 0.487f, 1.0f, 0.263f, 0.0f, -0.305f, 0.493f, 1.0f, + 0.265f, 0.0f, -0.303f, 0.499f, 1.0f, 0.267f, 0.0f, -0.3f, 0.505f, 1.0f, 0.269f, 0.0f, -0.298f, 0.511f, 1.0f, 0.271f, 0.0f, -0.296f, 0.518f, 1.0f, + 0.273f, 0.0f, -0.294f, 0.524f, 1.0f, 0.276f, 0.0f, -0.291f, 0.531f, 1.0f, 0.278f, 0.0f, -0.289f, 0.539f, 1.0f, 0.281f, 0.0f, -0.287f, 0.546f, 1.0f, + 0.283f, 0.0f, -0.284f, 0.552f, 1.0f, 0.286f, 0.0f, -0.281f, 0.557f, 1.0f, 0.289f, 0.0f, -0.279f, 0.561f, 1.0f, 0.292f, 0.0f, -0.276f, 0.565f, 1.0f, + 0.294f, 0.0f, -0.274f, 0.568f, 1.0f, 0.297f, 0.0f, -0.271f, 0.57f, 1.0f, 0.3f, 0.0f, -0.269f, 0.572f, 1.0f, 0.303f, 0.0f, -0.267f, 0.574f, 1.0f, + 0.306f, 0.0f, -0.264f, 0.575f, 1.0f, 0.308f, 0.0f, -0.262f, 0.576f, 1.0f, 0.311f, 0.0f, -0.26f, 0.577f, 1.0f, 0.314f, 0.0f, -0.257f, 0.578f, 1.0f, + 0.316f, 0.0f, -0.255f, 0.578f, 1.0f, 0.319f, 0.0f, -0.253f, 0.579f, 1.0f, 0.322f, 0.0f, -0.25f, 0.579f, 1.0f, 0.325f, 0.0f, -0.248f, 0.58f, 1.0f, + 0.328f, 0.0f, -0.246f, 0.58f, 1.0f, 0.331f, 0.0f, -0.243f, 0.58f, 1.0f, 0.334f, 0.0f, -0.241f, 0.58f, 1.0f, 0.337f, 0.0f, -0.239f, 0.58f, 1.0f, + 0.341f, 0.0f, -0.236f, 0.58f, 1.0f, 0.344f, 0.0f, -0.233f, 0.581f, 1.0f, 0.348f, 0.0f, -0.231f, 0.581f, 1.0f, 0.352f, 0.0f, -0.228f, 0.581f, 1.0f, + 0.356f, 0.0f, -0.225f, 0.582f, 1.0f, 0.36f, 0.0f, -0.222f, 0.582f, 1.0f, 0.365f, 0.0f, -0.219f, 0.582f, 1.0f, 0.369f, 0.0f, -0.216f, 0.582f, 1.0f, + 0.374f, 0.0f, -0.214f, 0.582f, 1.0f, 0.378f, 0.0f, -0.211f, 0.582f, 1.0f, 0.383f, 0.0f, -0.208f, 0.583f, 1.0f, 0.387f, 0.0f, -0.205f, 0.583f, 1.0f, + 0.392f, 0.0f, -0.202f, 0.583f, 1.0f, 0.397f, 0.0f, -0.199f, 0.583f, 1.0f, 0.401f, 0.0f, -0.197f, 0.583f, 1.0f, 0.406f, 0.0f, -0.194f, 0.583f, 1.0f, + 0.411f, 0.0f, -0.191f, 0.583f, 1.0f, 0.416f, 0.0f, -0.188f, 0.583f, 1.0f, 0.42f, 0.0f, -0.186f, 0.583f, 1.0f, 0.425f, 0.0f, -0.183f, 0.583f, 1.0f, + 0.43f, 0.0f, -0.18f, 0.583f, 1.0f, 0.434f, 0.0f, -0.178f, 0.583f, 1.0f, 0.439f, 0.0f, -0.175f, 0.583f, 1.0f, 0.444f, 0.0f, -0.172f, 0.583f, 1.0f, + 0.449f, 0.0f, -0.17f, 0.584f, 1.0f, 0.453f, 0.0f, -0.167f, 0.584f, 1.0f, 0.458f, 0.0f, -0.164f, 0.584f, 1.0f, 0.463f, 0.0f, -0.161f, 0.585f, 1.0f, + 0.468f, 0.0f, -0.158f, 0.585f, 1.0f, 0.473f, 0.0f, -0.155f, 0.585f, 1.0f, 0.478f, 0.0f, -0.152f, 0.585f, 1.0f, 0.483f, 0.0f, -0.149f, 0.585f, 1.0f, + 0.488f, 0.0f, -0.146f, 0.585f, 1.0f, 0.492f, 0.0f, -0.143f, 0.585f, 1.0f, 0.497f, 0.0f, -0.14f, 0.586f, 1.0f, 0.501f, 0.0f, -0.137f, 0.586f, 1.0f, + 0.506f, 0.0f, -0.134f, 0.586f, 1.0f, 0.51f, 0.0f, -0.13f, 0.586f, 1.0f, 0.515f, 0.0f, -0.127f, 0.586f, 1.0f, 0.52f, 0.0f, -0.124f, 0.586f, 1.0f, + 0.524f, 0.0f, -0.12f, 0.586f, 1.0f, 0.529f, 0.0f, -0.117f, 0.586f, 1.0f, 0.534f, 0.0f, -0.113f, 0.586f, 1.0f, 0.539f, 0.0f, -0.109f, 0.586f, 1.0f, + 0.544f, 0.0f, -0.105f, 0.586f, 1.0f, 0.55f, 0.0f, -0.1f, 0.586f, 1.0f, 0.555f, 0.0f, -0.095f, 0.586f, 1.0f, 0.561f, 0.0f, -0.09f, 0.586f, 1.0f, + 0.567f, 0.0f, -0.084f, 0.587f, 1.0f, 0.573f, 0.0f, -0.078f, 0.587f, 1.0f, 0.579f, 0.0f, -0.071f, 0.587f, 1.0f, 0.586f, 0.0f, -0.063f, 0.588f, 1.0f, + 0.593f, 0.0f, -0.055f, 0.588f, 1.0f, 0.6f, 0.0f, -0.047f, 0.588f, 1.0f, 0.607f, 0.0f, -0.038f, 0.589f, 1.0f, 0.614f, 0.0f, -0.028f, 0.589f, 1.0f, + 0.621f, 0.0f, -0.018f, 0.589f, 1.0f, 0.629f, 0.0f, -0.007f, 0.589f, 1.0f, 0.636f, 0.0f, 0.004f, 0.589f, 1.0f, 0.643f, 0.0f, 0.015f, 0.59f, 1.0f, + 0.65f, 0.0f, 0.026f, 0.589f, 1.0f, 0.656f, 0.0f, 0.038f, 0.589f, 1.0f, 0.663f, 0.0f, 0.049f, 0.588f, 1.0f, 0.669f, 0.0f, 0.06f, 0.587f, 1.0f, + 0.676f, 0.0f, 0.072f, 0.584f, 1.0f, 0.682f, 0.0f, 0.084f, 0.579f, 1.0f, 0.688f, 0.0f, 0.096f, 0.571f, 1.0f, 0.694f, 0.0f, 0.108f, 0.558f, 1.0f, + 0.7f, 0.0f, 0.12f, 0.54f, 1.0f, 0.706f, 0.0f, 0.133f, 0.514f, 1.0f, 0.712f, 0.0f, 0.145f, 0.478f, 1.0f, 0.718f, 0.0f, 0.158f, 0.431f, 1.0f, + 0.723f, 0.0f, 0.17f, 0.369f, 1.0f, 0.728f, 0.0f, 0.182f, 0.294f, 1.0f, 0.733f, 0.0f, 0.194f, 0.205f, 1.0f, 0.737f, 0.0f, 0.204f, 0.125f, 1.0f, + 0.743f, 0.0f, 0.218f, 0.0f, 1.0f, +}; + +static const float data25[389 * GP_PRIM_DATABUF_SIZE] = { + -0.284f, 0.0f, -0.444f, 0.0f, 1.0f, -0.285f, 0.0f, -0.448f, 0.0f, 1.0f, -0.285f, 0.0f, -0.45f, 0.0f, 1.0f, -0.286f, 0.0f, -0.454f, 0.0f, 1.0f, + -0.286f, 0.0f, -0.457f, 0.0f, 1.0f, -0.287f, 0.0f, -0.46f, 0.0f, 1.0f, -0.288f, 0.0f, -0.463f, 0.0f, 1.0f, -0.289f, 0.0f, -0.466f, 0.0f, 1.0f, + -0.289f, 0.0f, -0.47f, 0.0f, 1.0f, -0.29f, 0.0f, -0.473f, 0.0f, 1.0f, -0.291f, 0.0f, -0.476f, 0.0f, 1.0f, -0.292f, 0.0f, -0.48f, 0.0f, 1.0f, + -0.293f, 0.0f, -0.484f, 0.0f, 1.0f, -0.294f, 0.0f, -0.487f, 0.0f, 1.0f, -0.295f, 0.0f, -0.491f, 0.0f, 1.0f, -0.296f, 0.0f, -0.494f, 0.0f, 1.0f, + -0.297f, 0.0f, -0.498f, 0.0f, 1.0f, -0.298f, 0.0f, -0.502f, 0.0f, 1.0f, -0.299f, 0.0f, -0.505f, 0.0f, 1.0f, -0.3f, 0.0f, -0.509f, 0.0f, 1.0f, + -0.301f, 0.0f, -0.513f, 0.0f, 1.0f, -0.302f, 0.0f, -0.517f, 0.0f, 1.0f, -0.303f, 0.0f, -0.52f, 0.0f, 1.0f, -0.304f, 0.0f, -0.524f, 0.0f, 1.0f, + -0.305f, 0.0f, -0.528f, 0.0f, 1.0f, -0.306f, 0.0f, -0.532f, 0.0f, 1.0f, -0.307f, 0.0f, -0.535f, 0.0f, 1.0f, -0.308f, 0.0f, -0.539f, 0.0f, 1.0f, + -0.309f, 0.0f, -0.543f, 0.0f, 1.0f, -0.31f, 0.0f, -0.547f, 0.0f, 1.0f, -0.311f, 0.0f, -0.55f, 0.0f, 1.0f, -0.312f, 0.0f, -0.554f, 0.0f, 1.0f, + -0.313f, 0.0f, -0.558f, 0.0f, 1.0f, -0.314f, 0.0f, -0.562f, 0.0f, 1.0f, -0.315f, 0.0f, -0.565f, 0.0f, 1.0f, -0.316f, 0.0f, -0.569f, 0.0f, 1.0f, + -0.317f, 0.0f, -0.573f, 0.0f, 1.0f, -0.318f, 0.0f, -0.576f, 0.0f, 1.0f, -0.319f, 0.0f, -0.58f, 0.0f, 1.0f, -0.32f, 0.0f, -0.583f, 0.0f, 1.0f, + -0.321f, 0.0f, -0.587f, 0.0f, 1.0f, -0.322f, 0.0f, -0.591f, 0.0f, 1.0f, -0.323f, 0.0f, -0.594f, 0.0f, 1.0f, -0.323f, 0.0f, -0.598f, 0.0f, 1.0f, + -0.324f, 0.0f, -0.601f, 0.0f, 1.0f, -0.325f, 0.0f, -0.605f, 0.0f, 1.0f, -0.326f, 0.0f, -0.608f, 0.0f, 1.0f, -0.326f, 0.0f, -0.612f, 0.0f, 1.0f, + -0.327f, 0.0f, -0.615f, 0.0f, 1.0f, -0.328f, 0.0f, -0.619f, 0.0f, 1.0f, -0.328f, 0.0f, -0.622f, 0.0f, 1.0f, -0.329f, 0.0f, -0.625f, 0.0f, 1.0f, + -0.33f, 0.0f, -0.629f, 0.0f, 1.0f, -0.33f, 0.0f, -0.632f, 0.0f, 1.0f, -0.331f, 0.0f, -0.635f, 0.001f, 1.0f, -0.331f, 0.0f, -0.639f, 0.001f, 1.0f, + -0.332f, 0.0f, -0.642f, 0.002f, 1.0f, -0.332f, 0.0f, -0.645f, 0.002f, 1.0f, -0.333f, 0.0f, -0.649f, 0.003f, 1.0f, -0.333f, 0.0f, -0.652f, 0.005f, 1.0f, + -0.334f, 0.0f, -0.655f, 0.006f, 1.0f, -0.334f, 0.0f, -0.658f, 0.009f, 1.0f, -0.335f, 0.0f, -0.662f, 0.011f, 1.0f, -0.335f, 0.0f, -0.665f, 0.015f, 1.0f, + -0.335f, 0.0f, -0.668f, 0.019f, 1.0f, -0.336f, 0.0f, -0.672f, 0.024f, 1.0f, -0.336f, 0.0f, -0.675f, 0.031f, 1.0f, -0.337f, 0.0f, -0.678f, 0.038f, 1.0f, + -0.337f, 0.0f, -0.682f, 0.046f, 1.0f, -0.337f, 0.0f, -0.685f, 0.056f, 1.0f, -0.338f, 0.0f, -0.689f, 0.067f, 1.0f, -0.338f, 0.0f, -0.692f, 0.079f, 1.0f, + -0.338f, 0.0f, -0.696f, 0.093f, 1.0f, -0.339f, 0.0f, -0.699f, 0.107f, 1.0f, -0.339f, 0.0f, -0.703f, 0.123f, 1.0f, -0.34f, 0.0f, -0.706f, 0.139f, 1.0f, + -0.34f, 0.0f, -0.71f, 0.157f, 1.0f, -0.34f, 0.0f, -0.714f, 0.174f, 1.0f, -0.34f, 0.0f, -0.717f, 0.193f, 1.0f, -0.341f, 0.0f, -0.721f, 0.211f, 1.0f, + -0.341f, 0.0f, -0.725f, 0.23f, 1.0f, -0.341f, 0.0f, -0.729f, 0.248f, 1.0f, -0.342f, 0.0f, -0.732f, 0.266f, 1.0f, -0.342f, 0.0f, -0.736f, 0.284f, 1.0f, + -0.342f, 0.0f, -0.74f, 0.302f, 1.0f, -0.342f, 0.0f, -0.744f, 0.318f, 1.0f, -0.342f, 0.0f, -0.748f, 0.334f, 1.0f, -0.342f, 0.0f, -0.752f, 0.349f, 1.0f, + -0.343f, 0.0f, -0.756f, 0.364f, 1.0f, -0.343f, 0.0f, -0.76f, 0.377f, 1.0f, -0.343f, 0.0f, -0.763f, 0.389f, 1.0f, -0.343f, 0.0f, -0.767f, 0.401f, 1.0f, + -0.343f, 0.0f, -0.771f, 0.411f, 1.0f, -0.343f, 0.0f, -0.775f, 0.421f, 1.0f, -0.342f, 0.0f, -0.779f, 0.429f, 1.0f, -0.342f, 0.0f, -0.783f, 0.437f, 1.0f, + -0.342f, 0.0f, -0.786f, 0.444f, 1.0f, -0.342f, 0.0f, -0.79f, 0.451f, 1.0f, -0.342f, 0.0f, -0.794f, 0.456f, 1.0f, -0.341f, 0.0f, -0.797f, 0.461f, 1.0f, + -0.341f, 0.0f, -0.801f, 0.466f, 1.0f, -0.34f, 0.0f, -0.805f, 0.469f, 1.0f, -0.34f, 0.0f, -0.808f, 0.473f, 1.0f, -0.339f, 0.0f, -0.812f, 0.476f, 1.0f, + -0.339f, 0.0f, -0.815f, 0.478f, 1.0f, -0.338f, 0.0f, -0.818f, 0.48f, 1.0f, -0.338f, 0.0f, -0.822f, 0.482f, 1.0f, -0.337f, 0.0f, -0.825f, 0.483f, 1.0f, + -0.336f, 0.0f, -0.828f, 0.484f, 1.0f, -0.335f, 0.0f, -0.831f, 0.485f, 1.0f, -0.334f, 0.0f, -0.834f, 0.486f, 1.0f, -0.333f, 0.0f, -0.837f, 0.487f, 1.0f, + -0.332f, 0.0f, -0.84f, 0.487f, 1.0f, -0.331f, 0.0f, -0.843f, 0.487f, 1.0f, -0.33f, 0.0f, -0.846f, 0.488f, 1.0f, -0.329f, 0.0f, -0.849f, 0.488f, 1.0f, + -0.328f, 0.0f, -0.852f, 0.488f, 1.0f, -0.326f, 0.0f, -0.855f, 0.488f, 1.0f, -0.325f, 0.0f, -0.857f, 0.488f, 1.0f, -0.324f, 0.0f, -0.86f, 0.488f, 1.0f, + -0.322f, 0.0f, -0.863f, 0.488f, 1.0f, -0.321f, 0.0f, -0.865f, 0.488f, 1.0f, -0.319f, 0.0f, -0.868f, 0.488f, 1.0f, -0.318f, 0.0f, -0.871f, 0.488f, 1.0f, + -0.316f, 0.0f, -0.873f, 0.489f, 1.0f, -0.314f, 0.0f, -0.876f, 0.489f, 1.0f, -0.312f, 0.0f, -0.878f, 0.489f, 1.0f, -0.311f, 0.0f, -0.881f, 0.489f, 1.0f, + -0.309f, 0.0f, -0.883f, 0.489f, 1.0f, -0.307f, 0.0f, -0.885f, 0.489f, 1.0f, -0.305f, 0.0f, -0.888f, 0.49f, 1.0f, -0.303f, 0.0f, -0.89f, 0.491f, 1.0f, + -0.301f, 0.0f, -0.892f, 0.491f, 1.0f, -0.298f, 0.0f, -0.894f, 0.492f, 1.0f, -0.296f, 0.0f, -0.897f, 0.494f, 1.0f, -0.294f, 0.0f, -0.899f, 0.495f, 1.0f, + -0.292f, 0.0f, -0.901f, 0.497f, 1.0f, -0.289f, 0.0f, -0.903f, 0.5f, 1.0f, -0.287f, 0.0f, -0.905f, 0.502f, 1.0f, -0.284f, 0.0f, -0.907f, 0.505f, 1.0f, + -0.282f, 0.0f, -0.909f, 0.509f, 1.0f, -0.279f, 0.0f, -0.912f, 0.512f, 1.0f, -0.277f, 0.0f, -0.914f, 0.517f, 1.0f, -0.274f, 0.0f, -0.916f, 0.521f, 1.0f, + -0.271f, 0.0f, -0.918f, 0.526f, 1.0f, -0.269f, 0.0f, -0.919f, 0.531f, 1.0f, -0.266f, 0.0f, -0.921f, 0.537f, 1.0f, -0.263f, 0.0f, -0.923f, 0.543f, 1.0f, + -0.26f, 0.0f, -0.925f, 0.548f, 1.0f, -0.257f, 0.0f, -0.927f, 0.554f, 1.0f, -0.255f, 0.0f, -0.929f, 0.56f, 1.0f, -0.252f, 0.0f, -0.931f, 0.566f, 1.0f, + -0.249f, 0.0f, -0.932f, 0.571f, 1.0f, -0.246f, 0.0f, -0.934f, 0.577f, 1.0f, -0.243f, 0.0f, -0.936f, 0.582f, 1.0f, -0.24f, 0.0f, -0.938f, 0.587f, 1.0f, + -0.237f, 0.0f, -0.939f, 0.592f, 1.0f, -0.234f, 0.0f, -0.941f, 0.597f, 1.0f, -0.231f, 0.0f, -0.943f, 0.601f, 1.0f, -0.228f, 0.0f, -0.944f, 0.605f, 1.0f, + -0.225f, 0.0f, -0.946f, 0.609f, 1.0f, -0.222f, 0.0f, -0.948f, 0.613f, 1.0f, -0.219f, 0.0f, -0.949f, 0.617f, 1.0f, -0.216f, 0.0f, -0.951f, 0.62f, 1.0f, + -0.213f, 0.0f, -0.953f, 0.624f, 1.0f, -0.21f, 0.0f, -0.954f, 0.627f, 1.0f, -0.207f, 0.0f, -0.956f, 0.63f, 1.0f, -0.204f, 0.0f, -0.958f, 0.633f, 1.0f, + -0.201f, 0.0f, -0.959f, 0.636f, 1.0f, -0.198f, 0.0f, -0.961f, 0.639f, 1.0f, -0.195f, 0.0f, -0.962f, 0.641f, 1.0f, -0.191f, 0.0f, -0.964f, 0.643f, 1.0f, + -0.188f, 0.0f, -0.965f, 0.646f, 1.0f, -0.185f, 0.0f, -0.967f, 0.648f, 1.0f, -0.181f, 0.0f, -0.968f, 0.649f, 1.0f, -0.178f, 0.0f, -0.969f, 0.651f, 1.0f, + -0.175f, 0.0f, -0.971f, 0.653f, 1.0f, -0.171f, 0.0f, -0.972f, 0.654f, 1.0f, -0.168f, 0.0f, -0.973f, 0.655f, 1.0f, -0.165f, 0.0f, -0.974f, 0.657f, 1.0f, + -0.161f, 0.0f, -0.976f, 0.658f, 1.0f, -0.158f, 0.0f, -0.977f, 0.659f, 1.0f, -0.154f, 0.0f, -0.978f, 0.66f, 1.0f, -0.151f, 0.0f, -0.979f, 0.661f, 1.0f, + -0.148f, 0.0f, -0.98f, 0.662f, 1.0f, -0.144f, 0.0f, -0.981f, 0.664f, 1.0f, -0.141f, 0.0f, -0.982f, 0.665f, 1.0f, -0.137f, 0.0f, -0.983f, 0.667f, 1.0f, + -0.134f, 0.0f, -0.984f, 0.669f, 1.0f, -0.13f, 0.0f, -0.985f, 0.671f, 1.0f, -0.127f, 0.0f, -0.986f, 0.673f, 1.0f, -0.124f, 0.0f, -0.987f, 0.675f, 1.0f, + -0.12f, 0.0f, -0.988f, 0.678f, 1.0f, -0.117f, 0.0f, -0.989f, 0.68f, 1.0f, -0.113f, 0.0f, -0.99f, 0.683f, 1.0f, -0.11f, 0.0f, -0.991f, 0.685f, 1.0f, + -0.107f, 0.0f, -0.992f, 0.688f, 1.0f, -0.103f, 0.0f, -0.992f, 0.691f, 1.0f, -0.1f, 0.0f, -0.993f, 0.693f, 1.0f, -0.097f, 0.0f, -0.994f, 0.696f, 1.0f, + -0.093f, 0.0f, -0.995f, 0.698f, 1.0f, -0.09f, 0.0f, -0.996f, 0.701f, 1.0f, -0.087f, 0.0f, -0.997f, 0.703f, 1.0f, -0.084f, 0.0f, -0.997f, 0.705f, 1.0f, + -0.08f, 0.0f, -0.998f, 0.707f, 1.0f, -0.077f, 0.0f, -0.999f, 0.708f, 1.0f, -0.074f, 0.0f, -1.0f, 0.71f, 1.0f, -0.07f, 0.0f, -1.0f, 0.712f, 1.0f, + -0.067f, 0.0f, -1.001f, 0.713f, 1.0f, -0.063f, 0.0f, -1.002f, 0.715f, 1.0f, -0.06f, 0.0f, -1.002f, 0.717f, 1.0f, -0.056f, 0.0f, -1.003f, 0.718f, 1.0f, + -0.053f, 0.0f, -1.003f, 0.72f, 1.0f, -0.049f, 0.0f, -1.004f, 0.723f, 1.0f, -0.045f, 0.0f, -1.004f, 0.725f, 1.0f, -0.041f, 0.0f, -1.005f, 0.728f, 1.0f, + -0.038f, 0.0f, -1.005f, 0.73f, 1.0f, -0.034f, 0.0f, -1.006f, 0.733f, 1.0f, -0.03f, 0.0f, -1.006f, 0.736f, 1.0f, -0.026f, 0.0f, -1.007f, 0.738f, 1.0f, + -0.022f, 0.0f, -1.007f, 0.741f, 1.0f, -0.018f, 0.0f, -1.007f, 0.743f, 1.0f, -0.014f, 0.0f, -1.008f, 0.746f, 1.0f, -0.01f, 0.0f, -1.008f, 0.748f, 1.0f, + -0.006f, 0.0f, -1.009f, 0.75f, 1.0f, -0.001f, 0.0f, -1.009f, 0.752f, 1.0f, 0.003f, 0.0f, -1.009f, 0.754f, 1.0f, 0.007f, 0.0f, -1.01f, 0.755f, 1.0f, + 0.011f, 0.0f, -1.01f, 0.757f, 1.0f, 0.015f, 0.0f, -1.01f, 0.758f, 1.0f, 0.02f, 0.0f, -1.011f, 0.759f, 1.0f, 0.024f, 0.0f, -1.011f, 0.76f, 1.0f, + 0.028f, 0.0f, -1.011f, 0.761f, 1.0f, 0.033f, 0.0f, -1.011f, 0.761f, 1.0f, 0.037f, 0.0f, -1.012f, 0.762f, 1.0f, 0.041f, 0.0f, -1.012f, 0.762f, 1.0f, + 0.045f, 0.0f, -1.012f, 0.763f, 1.0f, 0.05f, 0.0f, -1.012f, 0.763f, 1.0f, 0.054f, 0.0f, -1.012f, 0.764f, 1.0f, 0.058f, 0.0f, -1.013f, 0.764f, 1.0f, + 0.062f, 0.0f, -1.013f, 0.764f, 1.0f, 0.066f, 0.0f, -1.013f, 0.764f, 1.0f, 0.071f, 0.0f, -1.013f, 0.764f, 1.0f, 0.075f, 0.0f, -1.013f, 0.765f, 1.0f, + 0.079f, 0.0f, -1.013f, 0.765f, 1.0f, 0.083f, 0.0f, -1.013f, 0.765f, 1.0f, 0.087f, 0.0f, -1.013f, 0.765f, 1.0f, 0.091f, 0.0f, -1.013f, 0.765f, 1.0f, + 0.095f, 0.0f, -1.013f, 0.765f, 1.0f, 0.099f, 0.0f, -1.013f, 0.766f, 1.0f, 0.103f, 0.0f, -1.013f, 0.766f, 1.0f, 0.108f, 0.0f, -1.012f, 0.766f, 1.0f, + 0.112f, 0.0f, -1.012f, 0.766f, 1.0f, 0.116f, 0.0f, -1.012f, 0.766f, 1.0f, 0.119f, 0.0f, -1.012f, 0.767f, 1.0f, 0.123f, 0.0f, -1.011f, 0.767f, 1.0f, + 0.127f, 0.0f, -1.011f, 0.767f, 1.0f, 0.131f, 0.0f, -1.01f, 0.767f, 1.0f, 0.135f, 0.0f, -1.01f, 0.767f, 1.0f, 0.139f, 0.0f, -1.009f, 0.768f, 1.0f, + 0.143f, 0.0f, -1.009f, 0.768f, 1.0f, 0.147f, 0.0f, -1.008f, 0.768f, 1.0f, 0.151f, 0.0f, -1.007f, 0.769f, 1.0f, 0.154f, 0.0f, -1.007f, 0.769f, 1.0f, + 0.158f, 0.0f, -1.006f, 0.769f, 1.0f, 0.162f, 0.0f, -1.005f, 0.769f, 1.0f, 0.166f, 0.0f, -1.004f, 0.77f, 1.0f, 0.17f, 0.0f, -1.003f, 0.77f, 1.0f, + 0.173f, 0.0f, -1.003f, 0.77f, 1.0f, 0.177f, 0.0f, -1.002f, 0.771f, 1.0f, 0.181f, 0.0f, -1.001f, 0.771f, 1.0f, 0.184f, 0.0f, -1.0f, 0.772f, 1.0f, + 0.188f, 0.0f, -0.999f, 0.772f, 1.0f, 0.192f, 0.0f, -0.998f, 0.773f, 1.0f, 0.195f, 0.0f, -0.997f, 0.773f, 1.0f, 0.199f, 0.0f, -0.996f, 0.774f, 1.0f, + 0.202f, 0.0f, -0.995f, 0.774f, 1.0f, 0.206f, 0.0f, -0.994f, 0.775f, 1.0f, 0.209f, 0.0f, -0.993f, 0.776f, 1.0f, 0.213f, 0.0f, -0.992f, 0.776f, 1.0f, + 0.216f, 0.0f, -0.991f, 0.777f, 1.0f, 0.22f, 0.0f, -0.99f, 0.777f, 1.0f, 0.223f, 0.0f, -0.988f, 0.778f, 1.0f, 0.227f, 0.0f, -0.987f, 0.778f, 1.0f, + 0.23f, 0.0f, -0.986f, 0.778f, 1.0f, 0.233f, 0.0f, -0.985f, 0.779f, 1.0f, 0.237f, 0.0f, -0.983f, 0.779f, 1.0f, 0.24f, 0.0f, -0.982f, 0.779f, 1.0f, + 0.243f, 0.0f, -0.981f, 0.779f, 1.0f, 0.246f, 0.0f, -0.979f, 0.778f, 1.0f, 0.249f, 0.0f, -0.978f, 0.778f, 1.0f, 0.252f, 0.0f, -0.976f, 0.777f, 1.0f, + 0.255f, 0.0f, -0.975f, 0.777f, 1.0f, 0.258f, 0.0f, -0.973f, 0.776f, 1.0f, 0.261f, 0.0f, -0.972f, 0.775f, 1.0f, 0.264f, 0.0f, -0.97f, 0.773f, 1.0f, + 0.267f, 0.0f, -0.968f, 0.772f, 1.0f, 0.269f, 0.0f, -0.967f, 0.77f, 1.0f, 0.272f, 0.0f, -0.965f, 0.769f, 1.0f, 0.275f, 0.0f, -0.963f, 0.767f, 1.0f, + 0.277f, 0.0f, -0.961f, 0.765f, 1.0f, 0.279f, 0.0f, -0.959f, 0.763f, 1.0f, 0.282f, 0.0f, -0.957f, 0.761f, 1.0f, 0.284f, 0.0f, -0.955f, 0.759f, 1.0f, + 0.286f, 0.0f, -0.953f, 0.756f, 1.0f, 0.288f, 0.0f, -0.951f, 0.754f, 1.0f, 0.29f, 0.0f, -0.948f, 0.752f, 1.0f, 0.292f, 0.0f, -0.946f, 0.749f, 1.0f, + 0.294f, 0.0f, -0.944f, 0.746f, 1.0f, 0.296f, 0.0f, -0.941f, 0.744f, 1.0f, 0.298f, 0.0f, -0.939f, 0.741f, 1.0f, 0.3f, 0.0f, -0.937f, 0.738f, 1.0f, + 0.302f, 0.0f, -0.934f, 0.736f, 1.0f, 0.303f, 0.0f, -0.932f, 0.733f, 1.0f, 0.305f, 0.0f, -0.929f, 0.73f, 1.0f, 0.306f, 0.0f, -0.926f, 0.727f, 1.0f, + 0.308f, 0.0f, -0.924f, 0.724f, 1.0f, 0.309f, 0.0f, -0.921f, 0.721f, 1.0f, 0.311f, 0.0f, -0.918f, 0.719f, 1.0f, 0.312f, 0.0f, -0.916f, 0.716f, 1.0f, + 0.313f, 0.0f, -0.913f, 0.713f, 1.0f, 0.315f, 0.0f, -0.91f, 0.71f, 1.0f, 0.316f, 0.0f, -0.907f, 0.707f, 1.0f, 0.317f, 0.0f, -0.904f, 0.704f, 1.0f, + 0.318f, 0.0f, -0.901f, 0.7f, 1.0f, 0.319f, 0.0f, -0.898f, 0.697f, 1.0f, 0.32f, 0.0f, -0.895f, 0.693f, 1.0f, 0.321f, 0.0f, -0.892f, 0.69f, 1.0f, + 0.322f, 0.0f, -0.889f, 0.686f, 1.0f, 0.323f, 0.0f, -0.886f, 0.681f, 1.0f, 0.324f, 0.0f, -0.883f, 0.677f, 1.0f, 0.325f, 0.0f, -0.88f, 0.672f, 1.0f, + 0.326f, 0.0f, -0.876f, 0.667f, 1.0f, 0.326f, 0.0f, -0.873f, 0.661f, 1.0f, 0.327f, 0.0f, -0.87f, 0.655f, 1.0f, 0.328f, 0.0f, -0.867f, 0.649f, 1.0f, + 0.329f, 0.0f, -0.864f, 0.643f, 1.0f, 0.329f, 0.0f, -0.861f, 0.637f, 1.0f, 0.33f, 0.0f, -0.857f, 0.63f, 1.0f, 0.331f, 0.0f, -0.854f, 0.624f, 1.0f, + 0.331f, 0.0f, -0.851f, 0.618f, 1.0f, 0.332f, 0.0f, -0.848f, 0.613f, 1.0f, 0.333f, 0.0f, -0.845f, 0.607f, 1.0f, 0.333f, 0.0f, -0.841f, 0.603f, 1.0f, + 0.334f, 0.0f, -0.838f, 0.598f, 1.0f, 0.334f, 0.0f, -0.835f, 0.594f, 1.0f, 0.335f, 0.0f, -0.832f, 0.591f, 1.0f, 0.335f, 0.0f, -0.828f, 0.588f, 1.0f, + 0.335f, 0.0f, -0.825f, 0.586f, 1.0f, 0.336f, 0.0f, -0.821f, 0.584f, 1.0f, 0.336f, 0.0f, -0.818f, 0.582f, 1.0f, 0.336f, 0.0f, -0.814f, 0.581f, 1.0f, + 0.337f, 0.0f, -0.811f, 0.58f, 1.0f, 0.337f, 0.0f, -0.807f, 0.58f, 1.0f, 0.337f, 0.0f, -0.803f, 0.579f, 1.0f, 0.337f, 0.0f, -0.799f, 0.579f, 1.0f, + 0.337f, 0.0f, -0.795f, 0.578f, 1.0f, 0.337f, 0.0f, -0.79f, 0.578f, 1.0f, 0.337f, 0.0f, -0.786f, 0.578f, 1.0f, 0.338f, 0.0f, -0.782f, 0.577f, 1.0f, + 0.338f, 0.0f, -0.777f, 0.576f, 1.0f, 0.337f, 0.0f, -0.772f, 0.574f, 1.0f, 0.337f, 0.0f, -0.767f, 0.572f, 1.0f, 0.337f, 0.0f, -0.762f, 0.569f, 1.0f, + 0.337f, 0.0f, -0.756f, 0.565f, 1.0f, 0.337f, 0.0f, -0.751f, 0.559f, 1.0f, 0.337f, 0.0f, -0.745f, 0.553f, 1.0f, 0.336f, 0.0f, -0.739f, 0.544f, 1.0f, + 0.336f, 0.0f, -0.732f, 0.534f, 1.0f, 0.335f, 0.0f, -0.725f, 0.521f, 1.0f, 0.334f, 0.0f, -0.718f, 0.505f, 1.0f, 0.333f, 0.0f, -0.711f, 0.487f, 1.0f, + 0.332f, 0.0f, -0.703f, 0.466f, 1.0f, 0.331f, 0.0f, -0.694f, 0.441f, 1.0f, 0.33f, 0.0f, -0.686f, 0.413f, 1.0f, 0.328f, 0.0f, -0.677f, 0.383f, 1.0f, + 0.326f, 0.0f, -0.667f, 0.35f, 1.0f, 0.325f, 0.0f, -0.657f, 0.316f, 1.0f, 0.323f, 0.0f, -0.647f, 0.281f, 1.0f, 0.32f, 0.0f, -0.636f, 0.246f, 1.0f, + 0.318f, 0.0f, -0.625f, 0.212f, 1.0f, 0.316f, 0.0f, -0.614f, 0.18f, 1.0f, 0.313f, 0.0f, -0.603f, 0.149f, 1.0f, 0.311f, 0.0f, -0.592f, 0.12f, 1.0f, + 0.308f, 0.0f, -0.581f, 0.093f, 1.0f, 0.306f, 0.0f, -0.57f, 0.069f, 1.0f, 0.303f, 0.0f, -0.559f, 0.046f, 1.0f, 0.301f, 0.0f, -0.55f, 0.027f, 1.0f, + 0.298f, 0.0f, -0.537f, 0.0f, 1.0f, +}; + +static const float data26[41 * GP_PRIM_DATABUF_SIZE] = { + -0.104f, 0.0f, -0.795f, 0.258f, 1.0f, -0.1f, 0.0f, -0.799f, 0.28f, 1.0f, -0.097f, 0.0f, -0.801f, 0.294f, 1.0f, -0.094f, 0.0f, -0.805f, 0.312f, 1.0f, + -0.09f, 0.0f, -0.808f, 0.328f, 1.0f, -0.086f, 0.0f, -0.811f, 0.345f, 1.0f, -0.082f, 0.0f, -0.815f, 0.361f, 1.0f, -0.078f, 0.0f, -0.818f, 0.377f, 1.0f, + -0.073f, 0.0f, -0.821f, 0.392f, 1.0f, -0.068f, 0.0f, -0.824f, 0.407f, 1.0f, -0.063f, 0.0f, -0.827f, 0.421f, 1.0f, -0.057f, 0.0f, -0.83f, 0.435f, 1.0f, + -0.051f, 0.0f, -0.833f, 0.448f, 1.0f, -0.045f, 0.0f, -0.835f, 0.46f, 1.0f, -0.039f, 0.0f, -0.837f, 0.471f, 1.0f, -0.033f, 0.0f, -0.839f, 0.481f, 1.0f, + -0.026f, 0.0f, -0.841f, 0.491f, 1.0f, -0.019f, 0.0f, -0.842f, 0.5f, 1.0f, -0.012f, 0.0f, -0.843f, 0.508f, 1.0f, -0.005f, 0.0f, -0.843f, 0.515f, 1.0f, + 0.002f, 0.0f, -0.843f, 0.522f, 1.0f, 0.009f, 0.0f, -0.843f, 0.527f, 1.0f, 0.016f, 0.0f, -0.842f, 0.532f, 1.0f, 0.023f, 0.0f, -0.841f, 0.535f, 1.0f, + 0.03f, 0.0f, -0.839f, 0.538f, 1.0f, 0.037f, 0.0f, -0.837f, 0.538f, 1.0f, 0.044f, 0.0f, -0.835f, 0.537f, 1.0f, 0.05f, 0.0f, -0.833f, 0.532f, 1.0f, + 0.056f, 0.0f, -0.83f, 0.524f, 1.0f, 0.062f, 0.0f, -0.827f, 0.513f, 1.0f, 0.068f, 0.0f, -0.823f, 0.496f, 1.0f, 0.074f, 0.0f, -0.82f, 0.474f, 1.0f, + 0.079f, 0.0f, -0.817f, 0.446f, 1.0f, 0.084f, 0.0f, -0.813f, 0.411f, 1.0f, 0.089f, 0.0f, -0.809f, 0.37f, 1.0f, 0.093f, 0.0f, -0.806f, 0.323f, 1.0f, + 0.098f, 0.0f, -0.802f, 0.269f, 1.0f, 0.102f, 0.0f, -0.798f, 0.211f, 1.0f, 0.106f, 0.0f, -0.795f, 0.146f, 1.0f, 0.109f, 0.0f, -0.792f, 0.089f, 1.0f, + 0.114f, 0.0f, -0.787f, 0.0f, 1.0f, +}; + +static const float data27[77 * GP_PRIM_DATABUF_SIZE] = { + -0.105f, 0.0f, -0.259f, 0.214f, 1.0f, -0.103f, 0.0f, -0.253f, 0.263f, 1.0f, -0.101f, 0.0f, -0.249f, 0.291f, 1.0f, -0.099f, 0.0f, -0.244f, 0.324f, 1.0f, + -0.098f, 0.0f, -0.24f, 0.351f, 1.0f, -0.096f, 0.0f, -0.235f, 0.376f, 1.0f, -0.094f, 0.0f, -0.231f, 0.397f, 1.0f, -0.092f, 0.0f, -0.227f, 0.416f, 1.0f, + -0.09f, 0.0f, -0.222f, 0.432f, 1.0f, -0.088f, 0.0f, -0.218f, 0.446f, 1.0f, -0.086f, 0.0f, -0.215f, 0.458f, 1.0f, -0.084f, 0.0f, -0.211f, 0.469f, 1.0f, + -0.082f, 0.0f, -0.208f, 0.478f, 1.0f, -0.079f, 0.0f, -0.205f, 0.486f, 1.0f, -0.077f, 0.0f, -0.203f, 0.494f, 1.0f, -0.075f, 0.0f, -0.2f, 0.501f, 1.0f, + -0.073f, 0.0f, -0.198f, 0.508f, 1.0f, -0.071f, 0.0f, -0.197f, 0.515f, 1.0f, -0.068f, 0.0f, -0.195f, 0.521f, 1.0f, -0.066f, 0.0f, -0.194f, 0.528f, 1.0f, + -0.064f, 0.0f, -0.194f, 0.534f, 1.0f, -0.061f, 0.0f, -0.194f, 0.54f, 1.0f, -0.059f, 0.0f, -0.194f, 0.546f, 1.0f, -0.056f, 0.0f, -0.194f, 0.551f, 1.0f, + -0.054f, 0.0f, -0.195f, 0.555f, 1.0f, -0.051f, 0.0f, -0.196f, 0.559f, 1.0f, -0.049f, 0.0f, -0.198f, 0.562f, 1.0f, -0.046f, 0.0f, -0.2f, 0.565f, 1.0f, + -0.044f, 0.0f, -0.201f, 0.567f, 1.0f, -0.041f, 0.0f, -0.204f, 0.568f, 1.0f, -0.039f, 0.0f, -0.206f, 0.569f, 1.0f, -0.036f, 0.0f, -0.208f, 0.57f, 1.0f, + -0.034f, 0.0f, -0.21f, 0.571f, 1.0f, -0.032f, 0.0f, -0.213f, 0.571f, 1.0f, -0.029f, 0.0f, -0.215f, 0.571f, 1.0f, -0.027f, 0.0f, -0.217f, 0.572f, 1.0f, + -0.024f, 0.0f, -0.219f, 0.572f, 1.0f, -0.022f, 0.0f, -0.221f, 0.572f, 1.0f, -0.019f, 0.0f, -0.222f, 0.572f, 1.0f, -0.016f, 0.0f, -0.224f, 0.572f, 1.0f, + -0.013f, 0.0f, -0.225f, 0.572f, 1.0f, -0.01f, 0.0f, -0.226f, 0.573f, 1.0f, -0.007f, 0.0f, -0.227f, 0.573f, 1.0f, -0.004f, 0.0f, -0.227f, 0.573f, 1.0f, + -0.001f, 0.0f, -0.227f, 0.574f, 1.0f, 0.002f, 0.0f, -0.227f, 0.575f, 1.0f, 0.005f, 0.0f, -0.227f, 0.576f, 1.0f, 0.008f, 0.0f, -0.226f, 0.577f, 1.0f, + 0.011f, 0.0f, -0.225f, 0.578f, 1.0f, 0.015f, 0.0f, -0.224f, 0.579f, 1.0f, 0.018f, 0.0f, -0.222f, 0.58f, 1.0f, 0.021f, 0.0f, -0.221f, 0.581f, 1.0f, + 0.024f, 0.0f, -0.219f, 0.582f, 1.0f, 0.027f, 0.0f, -0.217f, 0.582f, 1.0f, 0.03f, 0.0f, -0.215f, 0.583f, 1.0f, 0.033f, 0.0f, -0.213f, 0.583f, 1.0f, + 0.036f, 0.0f, -0.212f, 0.583f, 1.0f, 0.039f, 0.0f, -0.21f, 0.583f, 1.0f, 0.042f, 0.0f, -0.208f, 0.583f, 1.0f, 0.045f, 0.0f, -0.207f, 0.583f, 1.0f, + 0.048f, 0.0f, -0.205f, 0.583f, 1.0f, 0.051f, 0.0f, -0.204f, 0.583f, 1.0f, 0.054f, 0.0f, -0.203f, 0.583f, 1.0f, 0.058f, 0.0f, -0.203f, 0.583f, 1.0f, + 0.061f, 0.0f, -0.202f, 0.583f, 1.0f, 0.064f, 0.0f, -0.202f, 0.574f, 1.0f, 0.067f, 0.0f, -0.202f, 0.565f, 1.0f, 0.07f, 0.0f, -0.203f, 0.556f, 1.0f, + 0.073f, 0.0f, -0.203f, 0.547f, 1.0f, 0.075f, 0.0f, -0.204f, 0.515f, 1.0f, 0.078f, 0.0f, -0.204f, 0.483f, 1.0f, 0.08f, 0.0f, -0.205f, 0.451f, 1.0f, + 0.083f, 0.0f, -0.206f, 0.419f, 1.0f, 0.085f, 0.0f, -0.207f, 0.314f, 1.0f, 0.087f, 0.0f, -0.208f, 0.21f, 1.0f, 0.089f, 0.0f, -0.209f, 0.105f, 1.0f, + 0.091f, 0.0f, -0.21f, 0.0f, 1.0f, +}; + +static const float data28[257 * GP_PRIM_DATABUF_SIZE] = { + -0.637f, 0.0f, -0.172f, 0.0f, 1.0f, -0.641f, 0.0f, -0.172f, 0.0f, 1.0f, -0.643f, 0.0f, -0.172f, 0.0f, 1.0f, -0.646f, 0.0f, -0.172f, 0.0f, 1.0f, + -0.65f, 0.0f, -0.172f, 0.0f, 1.0f, -0.653f, 0.0f, -0.172f, 0.0f, 1.0f, -0.657f, 0.0f, -0.172f, 0.0f, 1.0f, -0.66f, 0.0f, -0.172f, 0.0f, 1.0f, + -0.664f, 0.0f, -0.171f, 0.0f, 1.0f, -0.668f, 0.0f, -0.171f, 0.0f, 1.0f, -0.672f, 0.0f, -0.171f, 0.0f, 1.0f, -0.677f, 0.0f, -0.171f, 0.0f, 1.0f, + -0.681f, 0.0f, -0.171f, 0.0f, 1.0f, -0.685f, 0.0f, -0.171f, 0.0f, 1.0f, -0.69f, 0.0f, -0.17f, 0.0f, 1.0f, -0.694f, 0.0f, -0.17f, 0.0f, 1.0f, + -0.699f, 0.0f, -0.17f, 0.0f, 1.0f, -0.704f, 0.0f, -0.169f, 0.0f, 1.0f, -0.708f, 0.0f, -0.169f, 0.0f, 1.0f, -0.713f, 0.0f, -0.168f, 0.0f, 1.0f, + -0.717f, 0.0f, -0.168f, 0.0f, 1.0f, -0.722f, 0.0f, -0.167f, 0.0f, 1.0f, -0.727f, 0.0f, -0.167f, 0.0f, 1.0f, -0.731f, 0.0f, -0.166f, 0.0f, 1.0f, + -0.735f, 0.0f, -0.166f, 0.0f, 1.0f, -0.74f, 0.0f, -0.165f, 0.0f, 1.0f, -0.744f, 0.0f, -0.164f, 0.0f, 1.0f, -0.749f, 0.0f, -0.163f, 0.0f, 1.0f, + -0.753f, 0.0f, -0.163f, 0.0f, 1.0f, -0.757f, 0.0f, -0.162f, 0.0f, 1.0f, -0.761f, 0.0f, -0.161f, 0.0f, 1.0f, -0.765f, 0.0f, -0.16f, 0.0f, 1.0f, + -0.769f, 0.0f, -0.159f, 0.0f, 1.0f, -0.773f, 0.0f, -0.158f, 0.0f, 1.0f, -0.777f, 0.0f, -0.157f, 0.0f, 1.0f, -0.781f, 0.0f, -0.156f, 0.001f, 1.0f, + -0.785f, 0.0f, -0.155f, 0.001f, 1.0f, -0.789f, 0.0f, -0.154f, 0.002f, 1.0f, -0.793f, 0.0f, -0.153f, 0.003f, 1.0f, -0.797f, 0.0f, -0.152f, 0.004f, 1.0f, + -0.801f, 0.0f, -0.15f, 0.005f, 1.0f, -0.805f, 0.0f, -0.149f, 0.006f, 1.0f, -0.81f, 0.0f, -0.147f, 0.008f, 1.0f, -0.814f, 0.0f, -0.146f, 0.009f, 1.0f, + -0.818f, 0.0f, -0.144f, 0.011f, 1.0f, -0.823f, 0.0f, -0.143f, 0.014f, 1.0f, -0.827f, 0.0f, -0.141f, 0.016f, 1.0f, -0.831f, 0.0f, -0.139f, 0.019f, 1.0f, + -0.836f, 0.0f, -0.138f, 0.022f, 1.0f, -0.84f, 0.0f, -0.136f, 0.024f, 1.0f, -0.844f, 0.0f, -0.135f, 0.026f, 1.0f, -0.849f, 0.0f, -0.133f, 0.027f, 1.0f, + -0.853f, 0.0f, -0.131f, 0.027f, 1.0f, -0.857f, 0.0f, -0.13f, 0.027f, 1.0f, -0.861f, 0.0f, -0.128f, 0.027f, 1.0f, -0.865f, 0.0f, -0.126f, 0.027f, 1.0f, + -0.868f, 0.0f, -0.125f, 0.026f, 1.0f, -0.872f, 0.0f, -0.123f, 0.025f, 1.0f, -0.876f, 0.0f, -0.121f, 0.025f, 1.0f, -0.879f, 0.0f, -0.119f, 0.024f, 1.0f, + -0.883f, 0.0f, -0.118f, 0.023f, 1.0f, -0.886f, 0.0f, -0.116f, 0.022f, 1.0f, -0.89f, 0.0f, -0.114f, 0.022f, 1.0f, -0.894f, 0.0f, -0.112f, 0.021f, 1.0f, + -0.898f, 0.0f, -0.11f, 0.022f, 1.0f, -0.901f, 0.0f, -0.107f, 0.022f, 1.0f, -0.905f, 0.0f, -0.105f, 0.024f, 1.0f, -0.909f, 0.0f, -0.103f, 0.026f, 1.0f, + -0.913f, 0.0f, -0.1f, 0.029f, 1.0f, -0.917f, 0.0f, -0.098f, 0.032f, 1.0f, -0.921f, 0.0f, -0.095f, 0.035f, 1.0f, -0.926f, 0.0f, -0.092f, 0.039f, 1.0f, + -0.93f, 0.0f, -0.09f, 0.043f, 1.0f, -0.934f, 0.0f, -0.087f, 0.047f, 1.0f, -0.938f, 0.0f, -0.084f, 0.051f, 1.0f, -0.942f, 0.0f, -0.081f, 0.055f, 1.0f, + -0.946f, 0.0f, -0.078f, 0.06f, 1.0f, -0.95f, 0.0f, -0.075f, 0.065f, 1.0f, -0.954f, 0.0f, -0.073f, 0.07f, 1.0f, -0.958f, 0.0f, -0.07f, 0.075f, 1.0f, + -0.961f, 0.0f, -0.067f, 0.081f, 1.0f, -0.965f, 0.0f, -0.064f, 0.087f, 1.0f, -0.968f, 0.0f, -0.061f, 0.092f, 1.0f, -0.972f, 0.0f, -0.058f, 0.098f, 1.0f, + -0.975f, 0.0f, -0.055f, 0.103f, 1.0f, -0.979f, 0.0f, -0.053f, 0.108f, 1.0f, -0.982f, 0.0f, -0.05f, 0.112f, 1.0f, -0.985f, 0.0f, -0.047f, 0.116f, 1.0f, + -0.988f, 0.0f, -0.045f, 0.12f, 1.0f, -0.991f, 0.0f, -0.042f, 0.123f, 1.0f, -0.994f, 0.0f, -0.039f, 0.126f, 1.0f, -0.997f, 0.0f, -0.037f, 0.129f, 1.0f, + -1.0f, 0.0f, -0.034f, 0.131f, 1.0f, -1.003f, 0.0f, -0.031f, 0.133f, 1.0f, -1.005f, 0.0f, -0.029f, 0.135f, 1.0f, -1.008f, 0.0f, -0.026f, 0.137f, 1.0f, + -1.01f, 0.0f, -0.024f, 0.139f, 1.0f, -1.013f, 0.0f, -0.021f, 0.141f, 1.0f, -1.016f, 0.0f, -0.018f, 0.143f, 1.0f, -1.018f, 0.0f, -0.016f, 0.144f, 1.0f, + -1.02f, 0.0f, -0.013f, 0.146f, 1.0f, -1.023f, 0.0f, -0.011f, 0.148f, 1.0f, -1.025f, 0.0f, -0.008f, 0.149f, 1.0f, -1.027f, 0.0f, -0.006f, 0.151f, 1.0f, + -1.029f, 0.0f, -0.003f, 0.152f, 1.0f, -1.032f, 0.0f, -0.001f, 0.154f, 1.0f, -1.034f, 0.0f, 0.001f, 0.154f, 1.0f, -1.036f, 0.0f, 0.004f, 0.155f, 1.0f, + -1.038f, 0.0f, 0.006f, 0.156f, 1.0f, -1.041f, 0.0f, 0.008f, 0.156f, 1.0f, -1.043f, 0.0f, 0.01f, 0.157f, 1.0f, -1.045f, 0.0f, 0.013f, 0.157f, 1.0f, + -1.047f, 0.0f, 0.015f, 0.157f, 1.0f, -1.049f, 0.0f, 0.018f, 0.158f, 1.0f, -1.051f, 0.0f, 0.02f, 0.158f, 1.0f, -1.053f, 0.0f, 0.023f, 0.158f, 1.0f, + -1.055f, 0.0f, 0.025f, 0.158f, 1.0f, -1.057f, 0.0f, 0.028f, 0.158f, 1.0f, -1.059f, 0.0f, 0.03f, 0.158f, 1.0f, -1.061f, 0.0f, 0.033f, 0.158f, 1.0f, + -1.063f, 0.0f, 0.036f, 0.158f, 1.0f, -1.065f, 0.0f, 0.038f, 0.158f, 1.0f, -1.067f, 0.0f, 0.041f, 0.158f, 1.0f, -1.069f, 0.0f, 0.044f, 0.157f, 1.0f, + -1.071f, 0.0f, 0.047f, 0.157f, 1.0f, -1.073f, 0.0f, 0.049f, 0.156f, 1.0f, -1.074f, 0.0f, 0.052f, 0.155f, 1.0f, -1.076f, 0.0f, 0.055f, 0.154f, 1.0f, + -1.078f, 0.0f, 0.058f, 0.153f, 1.0f, -1.08f, 0.0f, 0.061f, 0.152f, 1.0f, -1.082f, 0.0f, 0.064f, 0.15f, 1.0f, -1.083f, 0.0f, 0.067f, 0.148f, 1.0f, + -1.085f, 0.0f, 0.07f, 0.146f, 1.0f, -1.087f, 0.0f, 0.073f, 0.144f, 1.0f, -1.089f, 0.0f, 0.076f, 0.142f, 1.0f, -1.091f, 0.0f, 0.08f, 0.14f, 1.0f, + -1.092f, 0.0f, 0.083f, 0.138f, 1.0f, -1.094f, 0.0f, 0.086f, 0.136f, 1.0f, -1.096f, 0.0f, 0.09f, 0.135f, 1.0f, -1.097f, 0.0f, 0.093f, 0.134f, 1.0f, + -1.099f, 0.0f, 0.096f, 0.134f, 1.0f, -1.101f, 0.0f, 0.1f, 0.134f, 1.0f, -1.103f, 0.0f, 0.103f, 0.136f, 1.0f, -1.104f, 0.0f, 0.107f, 0.139f, 1.0f, + -1.106f, 0.0f, 0.111f, 0.144f, 1.0f, -1.107f, 0.0f, 0.114f, 0.15f, 1.0f, -1.109f, 0.0f, 0.118f, 0.158f, 1.0f, -1.11f, 0.0f, 0.122f, 0.167f, 1.0f, + -1.111f, 0.0f, 0.126f, 0.178f, 1.0f, -1.113f, 0.0f, 0.13f, 0.191f, 1.0f, -1.114f, 0.0f, 0.134f, 0.205f, 1.0f, -1.115f, 0.0f, 0.138f, 0.22f, 1.0f, + -1.116f, 0.0f, 0.142f, 0.237f, 1.0f, -1.117f, 0.0f, 0.146f, 0.254f, 1.0f, -1.118f, 0.0f, 0.15f, 0.272f, 1.0f, -1.119f, 0.0f, 0.155f, 0.291f, 1.0f, + -1.119f, 0.0f, 0.159f, 0.31f, 1.0f, -1.12f, 0.0f, 0.163f, 0.329f, 1.0f, -1.121f, 0.0f, 0.167f, 0.348f, 1.0f, -1.121f, 0.0f, 0.172f, 0.367f, 1.0f, + -1.122f, 0.0f, 0.176f, 0.386f, 1.0f, -1.122f, 0.0f, 0.18f, 0.405f, 1.0f, -1.123f, 0.0f, 0.184f, 0.423f, 1.0f, -1.123f, 0.0f, 0.189f, 0.441f, 1.0f, + -1.124f, 0.0f, 0.193f, 0.458f, 1.0f, -1.124f, 0.0f, 0.197f, 0.475f, 1.0f, -1.124f, 0.0f, 0.202f, 0.492f, 1.0f, -1.124f, 0.0f, 0.206f, 0.508f, 1.0f, + -1.125f, 0.0f, 0.21f, 0.524f, 1.0f, -1.125f, 0.0f, 0.214f, 0.539f, 1.0f, -1.125f, 0.0f, 0.218f, 0.554f, 1.0f, -1.124f, 0.0f, 0.223f, 0.568f, 1.0f, + -1.124f, 0.0f, 0.227f, 0.581f, 1.0f, -1.124f, 0.0f, 0.231f, 0.593f, 1.0f, -1.124f, 0.0f, 0.235f, 0.604f, 1.0f, -1.123f, 0.0f, 0.239f, 0.614f, 1.0f, + -1.123f, 0.0f, 0.243f, 0.624f, 1.0f, -1.122f, 0.0f, 0.247f, 0.632f, 1.0f, -1.122f, 0.0f, 0.251f, 0.64f, 1.0f, -1.121f, 0.0f, 0.255f, 0.646f, 1.0f, + -1.121f, 0.0f, 0.258f, 0.653f, 1.0f, -1.12f, 0.0f, 0.262f, 0.658f, 1.0f, -1.119f, 0.0f, 0.266f, 0.663f, 1.0f, -1.118f, 0.0f, 0.269f, 0.668f, 1.0f, + -1.117f, 0.0f, 0.272f, 0.673f, 1.0f, -1.117f, 0.0f, 0.276f, 0.678f, 1.0f, -1.116f, 0.0f, 0.279f, 0.682f, 1.0f, -1.115f, 0.0f, 0.282f, 0.687f, 1.0f, + -1.113f, 0.0f, 0.285f, 0.692f, 1.0f, -1.112f, 0.0f, 0.289f, 0.697f, 1.0f, -1.111f, 0.0f, 0.292f, 0.702f, 1.0f, -1.11f, 0.0f, 0.294f, 0.708f, 1.0f, + -1.109f, 0.0f, 0.297f, 0.713f, 1.0f, -1.108f, 0.0f, 0.3f, 0.718f, 1.0f, -1.106f, 0.0f, 0.303f, 0.724f, 1.0f, -1.105f, 0.0f, 0.306f, 0.73f, 1.0f, + -1.104f, 0.0f, 0.309f, 0.735f, 1.0f, -1.102f, 0.0f, 0.312f, 0.741f, 1.0f, -1.101f, 0.0f, 0.315f, 0.746f, 1.0f, -1.099f, 0.0f, 0.318f, 0.751f, 1.0f, + -1.098f, 0.0f, 0.321f, 0.756f, 1.0f, -1.096f, 0.0f, 0.323f, 0.761f, 1.0f, -1.094f, 0.0f, 0.326f, 0.766f, 1.0f, -1.093f, 0.0f, 0.329f, 0.771f, 1.0f, + -1.091f, 0.0f, 0.332f, 0.776f, 1.0f, -1.089f, 0.0f, 0.335f, 0.781f, 1.0f, -1.087f, 0.0f, 0.338f, 0.786f, 1.0f, -1.085f, 0.0f, 0.341f, 0.791f, 1.0f, + -1.082f, 0.0f, 0.344f, 0.797f, 1.0f, -1.08f, 0.0f, 0.347f, 0.802f, 1.0f, -1.078f, 0.0f, 0.349f, 0.808f, 1.0f, -1.075f, 0.0f, 0.352f, 0.814f, 1.0f, + -1.072f, 0.0f, 0.355f, 0.82f, 1.0f, -1.069f, 0.0f, 0.358f, 0.826f, 1.0f, -1.066f, 0.0f, 0.36f, 0.831f, 1.0f, -1.063f, 0.0f, 0.363f, 0.837f, 1.0f, + -1.059f, 0.0f, 0.366f, 0.842f, 1.0f, -1.055f, 0.0f, 0.368f, 0.847f, 1.0f, -1.051f, 0.0f, 0.371f, 0.851f, 1.0f, -1.047f, 0.0f, 0.373f, 0.856f, 1.0f, + -1.042f, 0.0f, 0.375f, 0.86f, 1.0f, -1.037f, 0.0f, 0.378f, 0.863f, 1.0f, -1.031f, 0.0f, 0.38f, 0.866f, 1.0f, -1.026f, 0.0f, 0.382f, 0.869f, 1.0f, + -1.02f, 0.0f, 0.384f, 0.871f, 1.0f, -1.014f, 0.0f, 0.386f, 0.873f, 1.0f, -1.007f, 0.0f, 0.387f, 0.875f, 1.0f, -1.0f, 0.0f, 0.389f, 0.876f, 1.0f, + -0.994f, 0.0f, 0.39f, 0.877f, 1.0f, -0.987f, 0.0f, 0.392f, 0.878f, 1.0f, -0.979f, 0.0f, 0.393f, 0.879f, 1.0f, -0.972f, 0.0f, 0.394f, 0.88f, 1.0f, + -0.964f, 0.0f, 0.395f, 0.881f, 1.0f, -0.956f, 0.0f, 0.395f, 0.881f, 1.0f, -0.948f, 0.0f, 0.395f, 0.882f, 1.0f, -0.94f, 0.0f, 0.395f, 0.882f, 1.0f, + -0.932f, 0.0f, 0.395f, 0.883f, 1.0f, -0.923f, 0.0f, 0.394f, 0.883f, 1.0f, -0.915f, 0.0f, 0.393f, 0.883f, 1.0f, -0.906f, 0.0f, 0.391f, 0.883f, 1.0f, + -0.896f, 0.0f, 0.389f, 0.881f, 1.0f, -0.887f, 0.0f, 0.386f, 0.876f, 1.0f, -0.877f, 0.0f, 0.382f, 0.866f, 1.0f, -0.867f, 0.0f, 0.378f, 0.85f, 1.0f, + -0.857f, 0.0f, 0.373f, 0.828f, 1.0f, -0.848f, 0.0f, 0.368f, 0.799f, 1.0f, -0.838f, 0.0f, 0.363f, 0.764f, 1.0f, -0.829f, 0.0f, 0.357f, 0.723f, 1.0f, + -0.819f, 0.0f, 0.352f, 0.679f, 1.0f, -0.811f, 0.0f, 0.347f, 0.631f, 1.0f, -0.802f, 0.0f, 0.342f, 0.579f, 1.0f, -0.794f, 0.0f, 0.338f, 0.525f, 1.0f, + -0.786f, 0.0f, 0.333f, 0.469f, 1.0f, -0.779f, 0.0f, 0.329f, 0.412f, 1.0f, -0.772f, 0.0f, 0.325f, 0.351f, 1.0f, -0.766f, 0.0f, 0.321f, 0.3f, 1.0f, + -0.757f, 0.0f, 0.317f, 0.219f, 1.0f, +}; + +static const float data29[205 * GP_PRIM_DATABUF_SIZE] = { + 0.816f, 0.0f, 0.326f, 0.285f, 1.0f, 0.819f, 0.0f, 0.328f, 0.287f, 1.0f, 0.821f, 0.0f, 0.33f, 0.29f, 1.0f, 0.823f, 0.0f, 0.331f, 0.295f, 1.0f, + 0.825f, 0.0f, 0.333f, 0.304f, 1.0f, 0.828f, 0.0f, 0.335f, 0.315f, 1.0f, 0.83f, 0.0f, 0.337f, 0.328f, 1.0f, 0.833f, 0.0f, 0.339f, 0.341f, 1.0f, + 0.836f, 0.0f, 0.341f, 0.355f, 1.0f, 0.839f, 0.0f, 0.343f, 0.368f, 1.0f, 0.842f, 0.0f, 0.345f, 0.38f, 1.0f, 0.845f, 0.0f, 0.347f, 0.392f, 1.0f, + 0.848f, 0.0f, 0.349f, 0.402f, 1.0f, 0.851f, 0.0f, 0.351f, 0.412f, 1.0f, 0.854f, 0.0f, 0.352f, 0.421f, 1.0f, 0.857f, 0.0f, 0.354f, 0.429f, 1.0f, + 0.861f, 0.0f, 0.356f, 0.437f, 1.0f, 0.865f, 0.0f, 0.357f, 0.444f, 1.0f, 0.869f, 0.0f, 0.359f, 0.452f, 1.0f, 0.872f, 0.0f, 0.36f, 0.46f, 1.0f, + 0.876f, 0.0f, 0.361f, 0.47f, 1.0f, 0.881f, 0.0f, 0.363f, 0.481f, 1.0f, 0.885f, 0.0f, 0.364f, 0.491f, 1.0f, 0.889f, 0.0f, 0.365f, 0.501f, 1.0f, + 0.893f, 0.0f, 0.366f, 0.511f, 1.0f, 0.898f, 0.0f, 0.367f, 0.52f, 1.0f, 0.902f, 0.0f, 0.368f, 0.528f, 1.0f, 0.906f, 0.0f, 0.37f, 0.535f, 1.0f, + 0.911f, 0.0f, 0.371f, 0.542f, 1.0f, 0.915f, 0.0f, 0.372f, 0.548f, 1.0f, 0.92f, 0.0f, 0.373f, 0.554f, 1.0f, 0.924f, 0.0f, 0.374f, 0.559f, 1.0f, + 0.929f, 0.0f, 0.375f, 0.564f, 1.0f, 0.933f, 0.0f, 0.376f, 0.567f, 1.0f, 0.938f, 0.0f, 0.377f, 0.57f, 1.0f, 0.943f, 0.0f, 0.378f, 0.572f, 1.0f, + 0.947f, 0.0f, 0.378f, 0.574f, 1.0f, 0.952f, 0.0f, 0.379f, 0.576f, 1.0f, 0.956f, 0.0f, 0.38f, 0.577f, 1.0f, 0.961f, 0.0f, 0.38f, 0.579f, 1.0f, + 0.966f, 0.0f, 0.381f, 0.581f, 1.0f, 0.971f, 0.0f, 0.381f, 0.585f, 1.0f, 0.975f, 0.0f, 0.382f, 0.588f, 1.0f, 0.98f, 0.0f, 0.382f, 0.591f, 1.0f, + 0.985f, 0.0f, 0.382f, 0.595f, 1.0f, 0.989f, 0.0f, 0.382f, 0.597f, 1.0f, 0.994f, 0.0f, 0.382f, 0.6f, 1.0f, 0.999f, 0.0f, 0.382f, 0.603f, 1.0f, + 1.003f, 0.0f, 0.382f, 0.605f, 1.0f, 1.008f, 0.0f, 0.381f, 0.607f, 1.0f, 1.013f, 0.0f, 0.381f, 0.61f, 1.0f, 1.017f, 0.0f, 0.381f, 0.611f, 1.0f, + 1.021f, 0.0f, 0.381f, 0.613f, 1.0f, 1.025f, 0.0f, 0.38f, 0.613f, 1.0f, 1.029f, 0.0f, 0.38f, 0.614f, 1.0f, 1.033f, 0.0f, 0.379f, 0.614f, 1.0f, + 1.037f, 0.0f, 0.379f, 0.614f, 1.0f, 1.041f, 0.0f, 0.378f, 0.614f, 1.0f, 1.044f, 0.0f, 0.378f, 0.614f, 1.0f, 1.048f, 0.0f, 0.377f, 0.614f, 1.0f, + 1.051f, 0.0f, 0.376f, 0.613f, 1.0f, 1.054f, 0.0f, 0.375f, 0.612f, 1.0f, 1.057f, 0.0f, 0.374f, 0.611f, 1.0f, 1.06f, 0.0f, 0.373f, 0.61f, 1.0f, + 1.063f, 0.0f, 0.372f, 0.609f, 1.0f, 1.066f, 0.0f, 0.371f, 0.609f, 1.0f, 1.068f, 0.0f, 0.37f, 0.608f, 1.0f, 1.071f, 0.0f, 0.368f, 0.608f, 1.0f, + 1.073f, 0.0f, 0.367f, 0.608f, 1.0f, 1.076f, 0.0f, 0.365f, 0.608f, 1.0f, 1.078f, 0.0f, 0.364f, 0.607f, 1.0f, 1.081f, 0.0f, 0.362f, 0.607f, 1.0f, + 1.083f, 0.0f, 0.36f, 0.607f, 1.0f, 1.085f, 0.0f, 0.358f, 0.606f, 1.0f, 1.087f, 0.0f, 0.356f, 0.606f, 1.0f, 1.09f, 0.0f, 0.354f, 0.606f, 1.0f, + 1.092f, 0.0f, 0.352f, 0.606f, 1.0f, 1.094f, 0.0f, 0.35f, 0.606f, 1.0f, 1.096f, 0.0f, 0.348f, 0.606f, 1.0f, 1.097f, 0.0f, 0.346f, 0.606f, 1.0f, + 1.099f, 0.0f, 0.344f, 0.606f, 1.0f, 1.101f, 0.0f, 0.341f, 0.606f, 1.0f, 1.103f, 0.0f, 0.339f, 0.606f, 1.0f, 1.104f, 0.0f, 0.337f, 0.607f, 1.0f, + 1.106f, 0.0f, 0.335f, 0.607f, 1.0f, 1.108f, 0.0f, 0.332f, 0.607f, 1.0f, 1.109f, 0.0f, 0.33f, 0.608f, 1.0f, 1.111f, 0.0f, 0.327f, 0.608f, 1.0f, + 1.113f, 0.0f, 0.324f, 0.608f, 1.0f, 1.114f, 0.0f, 0.322f, 0.609f, 1.0f, 1.116f, 0.0f, 0.319f, 0.609f, 1.0f, 1.117f, 0.0f, 0.316f, 0.609f, 1.0f, + 1.118f, 0.0f, 0.313f, 0.609f, 1.0f, 1.12f, 0.0f, 0.31f, 0.609f, 1.0f, 1.121f, 0.0f, 0.307f, 0.609f, 1.0f, 1.123f, 0.0f, 0.304f, 0.608f, 1.0f, + 1.124f, 0.0f, 0.301f, 0.608f, 1.0f, 1.125f, 0.0f, 0.297f, 0.607f, 1.0f, 1.126f, 0.0f, 0.294f, 0.606f, 1.0f, 1.127f, 0.0f, 0.29f, 0.605f, 1.0f, + 1.129f, 0.0f, 0.287f, 0.603f, 1.0f, 1.13f, 0.0f, 0.283f, 0.601f, 1.0f, 1.131f, 0.0f, 0.279f, 0.599f, 1.0f, 1.132f, 0.0f, 0.276f, 0.597f, 1.0f, + 1.132f, 0.0f, 0.272f, 0.595f, 1.0f, 1.133f, 0.0f, 0.268f, 0.593f, 1.0f, 1.134f, 0.0f, 0.264f, 0.592f, 1.0f, 1.135f, 0.0f, 0.26f, 0.591f, 1.0f, + 1.135f, 0.0f, 0.256f, 0.59f, 1.0f, 1.136f, 0.0f, 0.252f, 0.589f, 1.0f, 1.136f, 0.0f, 0.248f, 0.588f, 1.0f, 1.137f, 0.0f, 0.244f, 0.587f, 1.0f, + 1.137f, 0.0f, 0.24f, 0.586f, 1.0f, 1.138f, 0.0f, 0.236f, 0.585f, 1.0f, 1.138f, 0.0f, 0.232f, 0.584f, 1.0f, 1.138f, 0.0f, 0.228f, 0.582f, 1.0f, + 1.138f, 0.0f, 0.224f, 0.581f, 1.0f, 1.138f, 0.0f, 0.22f, 0.579f, 1.0f, 1.138f, 0.0f, 0.216f, 0.578f, 1.0f, 1.138f, 0.0f, 0.212f, 0.576f, 1.0f, + 1.138f, 0.0f, 0.208f, 0.575f, 1.0f, 1.138f, 0.0f, 0.204f, 0.573f, 1.0f, 1.137f, 0.0f, 0.2f, 0.572f, 1.0f, 1.137f, 0.0f, 0.196f, 0.571f, 1.0f, + 1.137f, 0.0f, 0.192f, 0.569f, 1.0f, 1.136f, 0.0f, 0.188f, 0.568f, 1.0f, 1.136f, 0.0f, 0.184f, 0.567f, 1.0f, 1.135f, 0.0f, 0.18f, 0.566f, 1.0f, + 1.134f, 0.0f, 0.176f, 0.565f, 1.0f, 1.133f, 0.0f, 0.172f, 0.563f, 1.0f, 1.132f, 0.0f, 0.168f, 0.561f, 1.0f, 1.131f, 0.0f, 0.164f, 0.559f, 1.0f, + 1.13f, 0.0f, 0.16f, 0.556f, 1.0f, 1.129f, 0.0f, 0.156f, 0.552f, 1.0f, 1.128f, 0.0f, 0.152f, 0.548f, 1.0f, 1.127f, 0.0f, 0.148f, 0.543f, 1.0f, + 1.126f, 0.0f, 0.144f, 0.537f, 1.0f, 1.124f, 0.0f, 0.14f, 0.53f, 1.0f, 1.123f, 0.0f, 0.136f, 0.522f, 1.0f, 1.122f, 0.0f, 0.132f, 0.514f, 1.0f, + 1.12f, 0.0f, 0.128f, 0.505f, 1.0f, 1.118f, 0.0f, 0.123f, 0.495f, 1.0f, 1.117f, 0.0f, 0.119f, 0.486f, 1.0f, 1.115f, 0.0f, 0.115f, 0.476f, 1.0f, + 1.113f, 0.0f, 0.111f, 0.466f, 1.0f, 1.111f, 0.0f, 0.107f, 0.456f, 1.0f, 1.11f, 0.0f, 0.102f, 0.446f, 1.0f, 1.108f, 0.0f, 0.098f, 0.436f, 1.0f, + 1.105f, 0.0f, 0.094f, 0.425f, 1.0f, 1.103f, 0.0f, 0.09f, 0.414f, 1.0f, 1.101f, 0.0f, 0.085f, 0.402f, 1.0f, 1.099f, 0.0f, 0.081f, 0.389f, 1.0f, + 1.096f, 0.0f, 0.077f, 0.377f, 1.0f, 1.094f, 0.0f, 0.072f, 0.364f, 1.0f, 1.091f, 0.0f, 0.068f, 0.351f, 1.0f, 1.088f, 0.0f, 0.063f, 0.338f, 1.0f, + 1.085f, 0.0f, 0.059f, 0.325f, 1.0f, 1.082f, 0.0f, 0.054f, 0.313f, 1.0f, 1.079f, 0.0f, 0.05f, 0.301f, 1.0f, 1.075f, 0.0f, 0.045f, 0.29f, 1.0f, + 1.071f, 0.0f, 0.04f, 0.281f, 1.0f, 1.067f, 0.0f, 0.035f, 0.272f, 1.0f, 1.063f, 0.0f, 0.031f, 0.266f, 1.0f, 1.059f, 0.0f, 0.026f, 0.261f, 1.0f, + 1.054f, 0.0f, 0.021f, 0.258f, 1.0f, 1.049f, 0.0f, 0.016f, 0.257f, 1.0f, 1.043f, 0.0f, 0.011f, 0.259f, 1.0f, 1.037f, 0.0f, 0.006f, 0.264f, 1.0f, + 1.031f, 0.0f, 0.0f, 0.272f, 1.0f, 1.025f, 0.0f, -0.005f, 0.283f, 1.0f, 1.018f, 0.0f, -0.01f, 0.296f, 1.0f, 1.011f, 0.0f, -0.015f, 0.313f, 1.0f, + 1.003f, 0.0f, -0.021f, 0.33f, 1.0f, 0.996f, 0.0f, -0.026f, 0.348f, 1.0f, 0.988f, 0.0f, -0.032f, 0.365f, 1.0f, 0.979f, 0.0f, -0.038f, 0.379f, 1.0f, + 0.971f, 0.0f, -0.044f, 0.389f, 1.0f, 0.962f, 0.0f, -0.05f, 0.394f, 1.0f, 0.953f, 0.0f, -0.057f, 0.392f, 1.0f, 0.944f, 0.0f, -0.063f, 0.384f, 1.0f, + 0.934f, 0.0f, -0.069f, 0.368f, 1.0f, 0.924f, 0.0f, -0.075f, 0.347f, 1.0f, 0.914f, 0.0f, -0.081f, 0.32f, 1.0f, 0.903f, 0.0f, -0.087f, 0.289f, 1.0f, + 0.893f, 0.0f, -0.092f, 0.256f, 1.0f, 0.882f, 0.0f, -0.098f, 0.223f, 1.0f, 0.871f, 0.0f, -0.103f, 0.191f, 1.0f, 0.86f, 0.0f, -0.108f, 0.162f, 1.0f, + 0.849f, 0.0f, -0.112f, 0.136f, 1.0f, 0.838f, 0.0f, -0.117f, 0.112f, 1.0f, 0.827f, 0.0f, -0.121f, 0.091f, 1.0f, 0.815f, 0.0f, -0.125f, 0.074f, 1.0f, + 0.804f, 0.0f, -0.128f, 0.059f, 1.0f, 0.793f, 0.0f, -0.132f, 0.046f, 1.0f, 0.782f, 0.0f, -0.135f, 0.036f, 1.0f, 0.771f, 0.0f, -0.138f, 0.028f, 1.0f, + 0.76f, 0.0f, -0.141f, 0.021f, 1.0f, 0.749f, 0.0f, -0.144f, 0.016f, 1.0f, 0.738f, 0.0f, -0.147f, 0.012f, 1.0f, 0.728f, 0.0f, -0.149f, 0.009f, 1.0f, + 0.718f, 0.0f, -0.152f, 0.006f, 1.0f, 0.708f, 0.0f, -0.154f, 0.004f, 1.0f, 0.699f, 0.0f, -0.157f, 0.003f, 1.0f, 0.691f, 0.0f, -0.159f, 0.002f, 1.0f, + 0.68f, 0.0f, -0.162f, 0.0f, 1.0f, +}; + +static const float data30[33 * GP_PRIM_DATABUF_SIZE] = { + -1.02f, 0.0f, 0.179f, 0.21f, 1.0f, -1.014f, 0.0f, 0.182f, 0.301f, 1.0f, -1.01f, 0.0f, 0.184f, 0.36f, 1.0f, -1.004f, 0.0f, 0.186f, 0.426f, 1.0f, + -0.999f, 0.0f, 0.188f, 0.479f, 1.0f, -0.993f, 0.0f, 0.19f, 0.519f, 1.0f, -0.987f, 0.0f, 0.191f, 0.545f, 1.0f, -0.981f, 0.0f, 0.192f, 0.562f, 1.0f, + -0.975f, 0.0f, 0.193f, 0.575f, 1.0f, -0.968f, 0.0f, 0.193f, 0.582f, 1.0f, -0.961f, 0.0f, 0.193f, 0.587f, 1.0f, -0.954f, 0.0f, 0.191f, 0.592f, 1.0f, + -0.946f, 0.0f, 0.19f, 0.597f, 1.0f, -0.938f, 0.0f, 0.187f, 0.6f, 1.0f, -0.93f, 0.0f, 0.183f, 0.603f, 1.0f, -0.922f, 0.0f, 0.178f, 0.606f, 1.0f, + -0.913f, 0.0f, 0.173f, 0.608f, 1.0f, -0.905f, 0.0f, 0.168f, 0.61f, 1.0f, -0.898f, 0.0f, 0.162f, 0.612f, 1.0f, -0.89f, 0.0f, 0.156f, 0.613f, 1.0f, + -0.883f, 0.0f, 0.15f, 0.612f, 1.0f, -0.877f, 0.0f, 0.143f, 0.608f, 1.0f, -0.871f, 0.0f, 0.137f, 0.602f, 1.0f, -0.865f, 0.0f, 0.131f, 0.593f, 1.0f, + -0.86f, 0.0f, 0.125f, 0.577f, 1.0f, -0.855f, 0.0f, 0.12f, 0.554f, 1.0f, -0.85f, 0.0f, 0.114f, 0.524f, 1.0f, -0.846f, 0.0f, 0.109f, 0.487f, 1.0f, + -0.842f, 0.0f, 0.104f, 0.443f, 1.0f, -0.838f, 0.0f, 0.1f, 0.394f, 1.0f, -0.835f, 0.0f, 0.095f, 0.339f, 1.0f, -0.832f, 0.0f, 0.091f, 0.295f, 1.0f, + -0.828f, 0.0f, 0.086f, 0.227f, 1.0f, +}; + +static const float data31[37 * GP_PRIM_DATABUF_SIZE] = { + 0.777f, 0.0f, 0.096f, 0.278f, 1.0f, 0.779f, 0.0f, 0.1f, 0.307f, 1.0f, 0.781f, 0.0f, 0.103f, 0.326f, 1.0f, 0.782f, 0.0f, 0.106f, 0.349f, 1.0f, + 0.784f, 0.0f, 0.109f, 0.372f, 1.0f, 0.786f, 0.0f, 0.112f, 0.395f, 1.0f, 0.789f, 0.0f, 0.116f, 0.418f, 1.0f, 0.791f, 0.0f, 0.119f, 0.44f, 1.0f, + 0.794f, 0.0f, 0.123f, 0.462f, 1.0f, 0.798f, 0.0f, 0.127f, 0.484f, 1.0f, 0.801f, 0.0f, 0.13f, 0.504f, 1.0f, 0.806f, 0.0f, 0.134f, 0.522f, 1.0f, + 0.81f, 0.0f, 0.138f, 0.54f, 1.0f, 0.815f, 0.0f, 0.142f, 0.556f, 1.0f, 0.82f, 0.0f, 0.146f, 0.571f, 1.0f, 0.826f, 0.0f, 0.15f, 0.584f, 1.0f, + 0.832f, 0.0f, 0.154f, 0.596f, 1.0f, 0.839f, 0.0f, 0.159f, 0.607f, 1.0f, 0.846f, 0.0f, 0.163f, 0.616f, 1.0f, 0.854f, 0.0f, 0.166f, 0.623f, 1.0f, + 0.862f, 0.0f, 0.17f, 0.628f, 1.0f, 0.87f, 0.0f, 0.174f, 0.632f, 1.0f, 0.878f, 0.0f, 0.177f, 0.632f, 1.0f, 0.887f, 0.0f, 0.18f, 0.63f, 1.0f, + 0.895f, 0.0f, 0.183f, 0.623f, 1.0f, 0.903f, 0.0f, 0.186f, 0.611f, 1.0f, 0.912f, 0.0f, 0.188f, 0.592f, 1.0f, 0.92f, 0.0f, 0.19f, 0.567f, 1.0f, + 0.928f, 0.0f, 0.192f, 0.533f, 1.0f, 0.935f, 0.0f, 0.193f, 0.492f, 1.0f, 0.943f, 0.0f, 0.194f, 0.442f, 1.0f, 0.95f, 0.0f, 0.196f, 0.385f, 1.0f, + 0.957f, 0.0f, 0.197f, 0.321f, 1.0f, 0.963f, 0.0f, 0.197f, 0.253f, 1.0f, 0.97f, 0.0f, 0.198f, 0.175f, 1.0f, 0.975f, 0.0f, 0.199f, 0.107f, 1.0f, + 0.983f, 0.0f, 0.199f, 0.0f, 1.0f, +}; + +static const float data32[201 * GP_PRIM_DATABUF_SIZE] = { + -0.437f, 0.0f, 0.508f, 0.0f, 1.0f, -0.435f, 0.0f, 0.51f, 0.0f, 1.0f, -0.434f, 0.0f, 0.511f, 0.0f, 1.0f, -0.432f, 0.0f, 0.512f, 0.0f, 1.0f, + -0.43f, 0.0f, 0.513f, 0.0f, 1.0f, -0.428f, 0.0f, 0.514f, 0.001f, 1.0f, -0.426f, 0.0f, 0.515f, 0.002f, 1.0f, -0.424f, 0.0f, 0.517f, 0.004f, 1.0f, + -0.422f, 0.0f, 0.518f, 0.007f, 1.0f, -0.42f, 0.0f, 0.519f, 0.012f, 1.0f, -0.418f, 0.0f, 0.521f, 0.018f, 1.0f, -0.416f, 0.0f, 0.522f, 0.025f, 1.0f, + -0.414f, 0.0f, 0.523f, 0.034f, 1.0f, -0.411f, 0.0f, 0.525f, 0.043f, 1.0f, -0.409f, 0.0f, 0.526f, 0.053f, 1.0f, -0.407f, 0.0f, 0.528f, 0.063f, 1.0f, + -0.404f, 0.0f, 0.529f, 0.073f, 1.0f, -0.402f, 0.0f, 0.531f, 0.083f, 1.0f, -0.399f, 0.0f, 0.532f, 0.092f, 1.0f, -0.396f, 0.0f, 0.534f, 0.101f, 1.0f, + -0.394f, 0.0f, 0.535f, 0.11f, 1.0f, -0.391f, 0.0f, 0.536f, 0.118f, 1.0f, -0.388f, 0.0f, 0.538f, 0.126f, 1.0f, -0.386f, 0.0f, 0.539f, 0.133f, 1.0f, + -0.383f, 0.0f, 0.54f, 0.14f, 1.0f, -0.38f, 0.0f, 0.542f, 0.147f, 1.0f, -0.377f, 0.0f, 0.543f, 0.153f, 1.0f, -0.374f, 0.0f, 0.544f, 0.159f, 1.0f, + -0.37f, 0.0f, 0.545f, 0.166f, 1.0f, -0.367f, 0.0f, 0.546f, 0.172f, 1.0f, -0.364f, 0.0f, 0.547f, 0.179f, 1.0f, -0.361f, 0.0f, 0.548f, 0.186f, 1.0f, + -0.357f, 0.0f, 0.549f, 0.193f, 1.0f, -0.354f, 0.0f, 0.55f, 0.202f, 1.0f, -0.35f, 0.0f, 0.551f, 0.211f, 1.0f, -0.347f, 0.0f, 0.552f, 0.221f, 1.0f, + -0.343f, 0.0f, 0.552f, 0.233f, 1.0f, -0.339f, 0.0f, 0.553f, 0.245f, 1.0f, -0.336f, 0.0f, 0.553f, 0.258f, 1.0f, -0.332f, 0.0f, 0.554f, 0.272f, 1.0f, + -0.328f, 0.0f, 0.554f, 0.286f, 1.0f, -0.324f, 0.0f, 0.554f, 0.301f, 1.0f, -0.321f, 0.0f, 0.555f, 0.317f, 1.0f, -0.317f, 0.0f, 0.555f, 0.332f, 1.0f, + -0.313f, 0.0f, 0.555f, 0.348f, 1.0f, -0.309f, 0.0f, 0.555f, 0.364f, 1.0f, -0.305f, 0.0f, 0.555f, 0.38f, 1.0f, -0.302f, 0.0f, 0.555f, 0.396f, 1.0f, + -0.298f, 0.0f, 0.555f, 0.411f, 1.0f, -0.294f, 0.0f, 0.555f, 0.426f, 1.0f, -0.29f, 0.0f, 0.554f, 0.44f, 1.0f, -0.287f, 0.0f, 0.554f, 0.454f, 1.0f, + -0.283f, 0.0f, 0.554f, 0.467f, 1.0f, -0.28f, 0.0f, 0.553f, 0.479f, 1.0f, -0.276f, 0.0f, 0.553f, 0.49f, 1.0f, -0.273f, 0.0f, 0.552f, 0.5f, 1.0f, + -0.269f, 0.0f, 0.552f, 0.51f, 1.0f, -0.266f, 0.0f, 0.551f, 0.519f, 1.0f, -0.263f, 0.0f, 0.55f, 0.527f, 1.0f, -0.26f, 0.0f, 0.549f, 0.534f, 1.0f, + -0.256f, 0.0f, 0.549f, 0.541f, 1.0f, -0.253f, 0.0f, 0.548f, 0.547f, 1.0f, -0.25f, 0.0f, 0.547f, 0.552f, 1.0f, -0.247f, 0.0f, 0.546f, 0.557f, 1.0f, + -0.244f, 0.0f, 0.545f, 0.561f, 1.0f, -0.241f, 0.0f, 0.544f, 0.564f, 1.0f, -0.238f, 0.0f, 0.543f, 0.567f, 1.0f, -0.235f, 0.0f, 0.542f, 0.57f, 1.0f, + -0.233f, 0.0f, 0.541f, 0.572f, 1.0f, -0.23f, 0.0f, 0.54f, 0.574f, 1.0f, -0.227f, 0.0f, 0.539f, 0.575f, 1.0f, -0.224f, 0.0f, 0.538f, 0.576f, 1.0f, + -0.221f, 0.0f, 0.537f, 0.577f, 1.0f, -0.219f, 0.0f, 0.535f, 0.578f, 1.0f, -0.216f, 0.0f, 0.534f, 0.578f, 1.0f, -0.213f, 0.0f, 0.533f, 0.579f, 1.0f, + -0.211f, 0.0f, 0.532f, 0.579f, 1.0f, -0.208f, 0.0f, 0.53f, 0.579f, 1.0f, -0.206f, 0.0f, 0.529f, 0.578f, 1.0f, -0.203f, 0.0f, 0.528f, 0.578f, 1.0f, + -0.2f, 0.0f, 0.526f, 0.577f, 1.0f, -0.198f, 0.0f, 0.525f, 0.576f, 1.0f, -0.195f, 0.0f, 0.523f, 0.575f, 1.0f, -0.193f, 0.0f, 0.522f, 0.574f, 1.0f, + -0.19f, 0.0f, 0.52f, 0.572f, 1.0f, -0.188f, 0.0f, 0.518f, 0.571f, 1.0f, -0.185f, 0.0f, 0.517f, 0.569f, 1.0f, -0.182f, 0.0f, 0.515f, 0.568f, 1.0f, + -0.18f, 0.0f, 0.513f, 0.567f, 1.0f, -0.177f, 0.0f, 0.512f, 0.565f, 1.0f, -0.174f, 0.0f, 0.51f, 0.564f, 1.0f, -0.172f, 0.0f, 0.508f, 0.562f, 1.0f, + -0.169f, 0.0f, 0.506f, 0.56f, 1.0f, -0.166f, 0.0f, 0.504f, 0.559f, 1.0f, -0.164f, 0.0f, 0.502f, 0.556f, 1.0f, -0.161f, 0.0f, 0.501f, 0.554f, 1.0f, + -0.158f, 0.0f, 0.499f, 0.552f, 1.0f, -0.155f, 0.0f, 0.497f, 0.55f, 1.0f, -0.153f, 0.0f, 0.495f, 0.547f, 1.0f, -0.15f, 0.0f, 0.493f, 0.545f, 1.0f, + -0.147f, 0.0f, 0.491f, 0.543f, 1.0f, -0.144f, 0.0f, 0.489f, 0.54f, 1.0f, -0.142f, 0.0f, 0.487f, 0.538f, 1.0f, -0.139f, 0.0f, 0.485f, 0.536f, 1.0f, + -0.136f, 0.0f, 0.483f, 0.533f, 1.0f, -0.133f, 0.0f, 0.481f, 0.53f, 1.0f, -0.13f, 0.0f, 0.479f, 0.527f, 1.0f, -0.127f, 0.0f, 0.477f, 0.524f, 1.0f, + -0.124f, 0.0f, 0.475f, 0.521f, 1.0f, -0.121f, 0.0f, 0.473f, 0.519f, 1.0f, -0.118f, 0.0f, 0.471f, 0.516f, 1.0f, -0.115f, 0.0f, 0.469f, 0.514f, 1.0f, + -0.112f, 0.0f, 0.467f, 0.511f, 1.0f, -0.109f, 0.0f, 0.465f, 0.509f, 1.0f, -0.106f, 0.0f, 0.463f, 0.506f, 1.0f, -0.103f, 0.0f, 0.461f, 0.503f, 1.0f, + -0.099f, 0.0f, 0.458f, 0.501f, 1.0f, -0.096f, 0.0f, 0.456f, 0.5f, 1.0f, -0.093f, 0.0f, 0.454f, 0.498f, 1.0f, -0.09f, 0.0f, 0.452f, 0.497f, 1.0f, + -0.086f, 0.0f, 0.45f, 0.496f, 1.0f, -0.083f, 0.0f, 0.448f, 0.496f, 1.0f, -0.079f, 0.0f, 0.446f, 0.495f, 1.0f, -0.076f, 0.0f, 0.444f, 0.495f, 1.0f, + -0.072f, 0.0f, 0.442f, 0.494f, 1.0f, -0.069f, 0.0f, 0.44f, 0.494f, 1.0f, -0.065f, 0.0f, 0.438f, 0.494f, 1.0f, -0.062f, 0.0f, 0.436f, 0.494f, 1.0f, + -0.058f, 0.0f, 0.435f, 0.494f, 1.0f, -0.054f, 0.0f, 0.433f, 0.494f, 1.0f, -0.05f, 0.0f, 0.431f, 0.494f, 1.0f, -0.046f, 0.0f, 0.43f, 0.494f, 1.0f, + -0.042f, 0.0f, 0.428f, 0.494f, 1.0f, -0.038f, 0.0f, 0.427f, 0.494f, 1.0f, -0.033f, 0.0f, 0.426f, 0.494f, 1.0f, -0.029f, 0.0f, 0.425f, 0.494f, 1.0f, + -0.025f, 0.0f, 0.424f, 0.494f, 1.0f, -0.02f, 0.0f, 0.423f, 0.494f, 1.0f, -0.015f, 0.0f, 0.422f, 0.494f, 1.0f, -0.011f, 0.0f, 0.422f, 0.494f, 1.0f, + -0.006f, 0.0f, 0.421f, 0.494f, 1.0f, -0.001f, 0.0f, 0.421f, 0.495f, 1.0f, 0.004f, 0.0f, 0.421f, 0.495f, 1.0f, 0.009f, 0.0f, 0.421f, 0.495f, 1.0f, + 0.014f, 0.0f, 0.422f, 0.495f, 1.0f, 0.019f, 0.0f, 0.422f, 0.495f, 1.0f, 0.024f, 0.0f, 0.423f, 0.495f, 1.0f, 0.029f, 0.0f, 0.424f, 0.495f, 1.0f, + 0.034f, 0.0f, 0.426f, 0.495f, 1.0f, 0.039f, 0.0f, 0.427f, 0.495f, 1.0f, 0.044f, 0.0f, 0.429f, 0.496f, 1.0f, 0.049f, 0.0f, 0.43f, 0.497f, 1.0f, + 0.054f, 0.0f, 0.432f, 0.498f, 1.0f, 0.059f, 0.0f, 0.435f, 0.5f, 1.0f, 0.064f, 0.0f, 0.438f, 0.502f, 1.0f, 0.069f, 0.0f, 0.44f, 0.506f, 1.0f, + 0.074f, 0.0f, 0.443f, 0.51f, 1.0f, 0.08f, 0.0f, 0.446f, 0.516f, 1.0f, 0.085f, 0.0f, 0.45f, 0.522f, 1.0f, 0.09f, 0.0f, 0.453f, 0.528f, 1.0f, + 0.095f, 0.0f, 0.456f, 0.533f, 1.0f, 0.101f, 0.0f, 0.46f, 0.537f, 1.0f, 0.107f, 0.0f, 0.463f, 0.539f, 1.0f, 0.112f, 0.0f, 0.467f, 0.542f, 1.0f, + 0.118f, 0.0f, 0.471f, 0.543f, 1.0f, 0.124f, 0.0f, 0.475f, 0.545f, 1.0f, 0.13f, 0.0f, 0.478f, 0.546f, 1.0f, 0.137f, 0.0f, 0.482f, 0.546f, 1.0f, + 0.143f, 0.0f, 0.486f, 0.547f, 1.0f, 0.149f, 0.0f, 0.49f, 0.546f, 1.0f, 0.156f, 0.0f, 0.493f, 0.544f, 1.0f, 0.163f, 0.0f, 0.497f, 0.54f, 1.0f, + 0.17f, 0.0f, 0.5f, 0.533f, 1.0f, 0.176f, 0.0f, 0.503f, 0.525f, 1.0f, 0.183f, 0.0f, 0.507f, 0.515f, 1.0f, 0.191f, 0.0f, 0.509f, 0.503f, 1.0f, + 0.198f, 0.0f, 0.512f, 0.491f, 1.0f, 0.205f, 0.0f, 0.515f, 0.477f, 1.0f, 0.214f, 0.0f, 0.518f, 0.462f, 1.0f, 0.222f, 0.0f, 0.521f, 0.445f, 1.0f, + 0.23f, 0.0f, 0.524f, 0.427f, 1.0f, 0.238f, 0.0f, 0.527f, 0.409f, 1.0f, 0.245f, 0.0f, 0.529f, 0.388f, 1.0f, 0.254f, 0.0f, 0.531f, 0.366f, 1.0f, + 0.262f, 0.0f, 0.532f, 0.343f, 1.0f, 0.272f, 0.0f, 0.533f, 0.317f, 1.0f, 0.282f, 0.0f, 0.534f, 0.289f, 1.0f, 0.292f, 0.0f, 0.535f, 0.258f, 1.0f, + 0.301f, 0.0f, 0.535f, 0.224f, 1.0f, 0.311f, 0.0f, 0.536f, 0.189f, 1.0f, 0.32f, 0.0f, 0.536f, 0.153f, 1.0f, 0.328f, 0.0f, 0.536f, 0.117f, 1.0f, + 0.338f, 0.0f, 0.537f, 0.084f, 1.0f, 0.346f, 0.0f, 0.537f, 0.057f, 1.0f, 0.353f, 0.0f, 0.536f, 0.037f, 1.0f, 0.361f, 0.0f, 0.536f, 0.022f, 1.0f, + 0.37f, 0.0f, 0.537f, 0.013f, 1.0f, 0.376f, 0.0f, 0.536f, 0.007f, 1.0f, 0.384f, 0.0f, 0.536f, 0.004f, 1.0f, 0.39f, 0.0f, 0.536f, 0.002f, 1.0f, + 0.399f, 0.0f, 0.535f, 0.0f, 1.0f, +}; + +static const float data33[69 * GP_PRIM_DATABUF_SIZE] = { + -0.308f, 0.0f, 0.151f, 0.363f, 1.0f, -0.31f, 0.0f, 0.15f, 0.377f, 1.0f, -0.311f, 0.0f, 0.149f, 0.386f, 1.0f, -0.313f, 0.0f, 0.149f, 0.397f, 1.0f, + -0.314f, 0.0f, 0.149f, 0.408f, 1.0f, -0.316f, 0.0f, 0.148f, 0.42f, 1.0f, -0.318f, 0.0f, 0.148f, 0.431f, 1.0f, -0.32f, 0.0f, 0.148f, 0.443f, 1.0f, + -0.322f, 0.0f, 0.148f, 0.455f, 1.0f, -0.325f, 0.0f, 0.149f, 0.467f, 1.0f, -0.327f, 0.0f, 0.149f, 0.478f, 1.0f, -0.33f, 0.0f, 0.151f, 0.49f, 1.0f, + -0.333f, 0.0f, 0.152f, 0.501f, 1.0f, -0.336f, 0.0f, 0.154f, 0.512f, 1.0f, -0.34f, 0.0f, 0.157f, 0.522f, 1.0f, -0.343f, 0.0f, 0.161f, 0.533f, 1.0f, + -0.346f, 0.0f, 0.166f, 0.543f, 1.0f, -0.349f, 0.0f, 0.171f, 0.553f, 1.0f, -0.351f, 0.0f, 0.178f, 0.563f, 1.0f, -0.352f, 0.0f, 0.186f, 0.572f, 1.0f, + -0.353f, 0.0f, 0.193f, 0.582f, 1.0f, -0.352f, 0.0f, 0.2f, 0.591f, 1.0f, -0.351f, 0.0f, 0.206f, 0.6f, 1.0f, -0.349f, 0.0f, 0.211f, 0.608f, 1.0f, + -0.347f, 0.0f, 0.215f, 0.616f, 1.0f, -0.345f, 0.0f, 0.219f, 0.623f, 1.0f, -0.343f, 0.0f, 0.222f, 0.63f, 1.0f, -0.341f, 0.0f, 0.224f, 0.637f, 1.0f, + -0.339f, 0.0f, 0.226f, 0.642f, 1.0f, -0.337f, 0.0f, 0.228f, 0.647f, 1.0f, -0.335f, 0.0f, 0.229f, 0.652f, 1.0f, -0.333f, 0.0f, 0.23f, 0.656f, 1.0f, + -0.332f, 0.0f, 0.231f, 0.66f, 1.0f, -0.33f, 0.0f, 0.232f, 0.663f, 1.0f, -0.328f, 0.0f, 0.232f, 0.666f, 1.0f, -0.327f, 0.0f, 0.233f, 0.669f, 1.0f, + -0.325f, 0.0f, 0.233f, 0.672f, 1.0f, -0.324f, 0.0f, 0.234f, 0.676f, 1.0f, -0.322f, 0.0f, 0.234f, 0.679f, 1.0f, -0.321f, 0.0f, 0.234f, 0.682f, 1.0f, + -0.319f, 0.0f, 0.234f, 0.686f, 1.0f, -0.317f, 0.0f, 0.234f, 0.689f, 1.0f, -0.316f, 0.0f, 0.234f, 0.693f, 1.0f, -0.314f, 0.0f, 0.234f, 0.697f, 1.0f, + -0.312f, 0.0f, 0.233f, 0.701f, 1.0f, -0.31f, 0.0f, 0.232f, 0.705f, 1.0f, -0.307f, 0.0f, 0.231f, 0.709f, 1.0f, -0.305f, 0.0f, 0.23f, 0.713f, 1.0f, + -0.302f, 0.0f, 0.228f, 0.716f, 1.0f, -0.299f, 0.0f, 0.225f, 0.719f, 1.0f, -0.295f, 0.0f, 0.222f, 0.722f, 1.0f, -0.292f, 0.0f, 0.217f, 0.725f, 1.0f, + -0.289f, 0.0f, 0.21f, 0.727f, 1.0f, -0.287f, 0.0f, 0.202f, 0.728f, 1.0f, -0.285f, 0.0f, 0.194f, 0.729f, 1.0f, -0.286f, 0.0f, 0.185f, 0.729f, 1.0f, + -0.287f, 0.0f, 0.178f, 0.728f, 1.0f, -0.289f, 0.0f, 0.171f, 0.726f, 1.0f, -0.292f, 0.0f, 0.166f, 0.723f, 1.0f, -0.294f, 0.0f, 0.162f, 0.717f, 1.0f, + -0.297f, 0.0f, 0.159f, 0.71f, 1.0f, -0.299f, 0.0f, 0.157f, 0.701f, 1.0f, -0.301f, 0.0f, 0.155f, 0.689f, 1.0f, -0.303f, 0.0f, 0.154f, 0.675f, 1.0f, + -0.305f, 0.0f, 0.152f, 0.659f, 1.0f, -0.306f, 0.0f, 0.151f, 0.641f, 1.0f, -0.308f, 0.0f, 0.151f, 0.62f, 1.0f, -0.309f, 0.0f, 0.15f, 0.602f, 1.0f, + -0.31f, 0.0f, 0.15f, 0.572f, 1.0f, +}; + +static const float data34[57 * GP_PRIM_DATABUF_SIZE] = { + 0.302f, 0.0f, 0.166f, 0.25f, 1.0f, 0.301f, 0.0f, 0.167f, 0.319f, 1.0f, 0.3f, 0.0f, 0.167f, 0.363f, 1.0f, 0.299f, 0.0f, 0.167f, 0.414f, 1.0f, + 0.298f, 0.0f, 0.167f, 0.459f, 1.0f, 0.296f, 0.0f, 0.168f, 0.501f, 1.0f, 0.295f, 0.0f, 0.168f, 0.539f, 1.0f, 0.293f, 0.0f, 0.169f, 0.573f, 1.0f, + 0.291f, 0.0f, 0.17f, 0.603f, 1.0f, 0.289f, 0.0f, 0.171f, 0.629f, 1.0f, 0.286f, 0.0f, 0.173f, 0.652f, 1.0f, 0.283f, 0.0f, 0.176f, 0.672f, 1.0f, + 0.279f, 0.0f, 0.18f, 0.69f, 1.0f, 0.276f, 0.0f, 0.186f, 0.705f, 1.0f, 0.272f, 0.0f, 0.195f, 0.719f, 1.0f, 0.271f, 0.0f, 0.205f, 0.73f, 1.0f, + 0.272f, 0.0f, 0.217f, 0.741f, 1.0f, 0.275f, 0.0f, 0.227f, 0.75f, 1.0f, 0.279f, 0.0f, 0.234f, 0.758f, 1.0f, 0.283f, 0.0f, 0.24f, 0.765f, 1.0f, + 0.287f, 0.0f, 0.243f, 0.771f, 1.0f, 0.291f, 0.0f, 0.245f, 0.776f, 1.0f, 0.294f, 0.0f, 0.247f, 0.781f, 1.0f, 0.296f, 0.0f, 0.248f, 0.785f, 1.0f, + 0.299f, 0.0f, 0.249f, 0.789f, 1.0f, 0.301f, 0.0f, 0.249f, 0.793f, 1.0f, 0.303f, 0.0f, 0.249f, 0.796f, 1.0f, 0.305f, 0.0f, 0.25f, 0.799f, 1.0f, + 0.306f, 0.0f, 0.25f, 0.802f, 1.0f, 0.308f, 0.0f, 0.249f, 0.805f, 1.0f, 0.31f, 0.0f, 0.249f, 0.808f, 1.0f, 0.311f, 0.0f, 0.249f, 0.81f, 1.0f, + 0.313f, 0.0f, 0.249f, 0.813f, 1.0f, 0.314f, 0.0f, 0.248f, 0.816f, 1.0f, 0.316f, 0.0f, 0.248f, 0.819f, 1.0f, 0.317f, 0.0f, 0.247f, 0.822f, 1.0f, + 0.319f, 0.0f, 0.246f, 0.825f, 1.0f, 0.321f, 0.0f, 0.245f, 0.828f, 1.0f, 0.323f, 0.0f, 0.244f, 0.832f, 1.0f, 0.325f, 0.0f, 0.243f, 0.835f, 1.0f, + 0.328f, 0.0f, 0.24f, 0.838f, 1.0f, 0.33f, 0.0f, 0.237f, 0.841f, 1.0f, 0.333f, 0.0f, 0.233f, 0.844f, 1.0f, 0.337f, 0.0f, 0.228f, 0.847f, 1.0f, + 0.339f, 0.0f, 0.219f, 0.849f, 1.0f, 0.341f, 0.0f, 0.209f, 0.852f, 1.0f, 0.34f, 0.0f, 0.197f, 0.854f, 1.0f, 0.336f, 0.0f, 0.186f, 0.856f, 1.0f, + 0.331f, 0.0f, 0.178f, 0.858f, 1.0f, 0.325f, 0.0f, 0.173f, 0.86f, 1.0f, 0.321f, 0.0f, 0.17f, 0.861f, 1.0f, 0.318f, 0.0f, 0.169f, 0.862f, 1.0f, + 0.315f, 0.0f, 0.168f, 0.864f, 1.0f, 0.312f, 0.0f, 0.167f, 0.865f, 1.0f, 0.311f, 0.0f, 0.167f, 0.866f, 1.0f, 0.309f, 0.0f, 0.166f, 0.867f, 1.0f, + 0.308f, 0.0f, 0.166f, 0.868f, 1.0f, +}; + +static const float data35[261 * GP_PRIM_DATABUF_SIZE] = { + -0.685f, 0.0f, 0.408f, 0.0f, 1.0f, -0.683f, 0.0f, 0.41f, 0.023f, 1.0f, -0.681f, 0.0f, 0.412f, 0.051f, 1.0f, -0.679f, 0.0f, 0.414f, 0.092f, 1.0f, + -0.678f, 0.0f, 0.415f, 0.125f, 1.0f, -0.676f, 0.0f, 0.417f, 0.149f, 1.0f, -0.674f, 0.0f, 0.419f, 0.167f, 1.0f, -0.672f, 0.0f, 0.42f, 0.183f, 1.0f, + -0.67f, 0.0f, 0.422f, 0.199f, 1.0f, -0.668f, 0.0f, 0.424f, 0.218f, 1.0f, -0.666f, 0.0f, 0.426f, 0.237f, 1.0f, -0.664f, 0.0f, 0.429f, 0.257f, 1.0f, + -0.661f, 0.0f, 0.431f, 0.275f, 1.0f, -0.659f, 0.0f, 0.434f, 0.291f, 1.0f, -0.657f, 0.0f, 0.436f, 0.305f, 1.0f, -0.655f, 0.0f, 0.439f, 0.315f, 1.0f, + -0.653f, 0.0f, 0.442f, 0.322f, 1.0f, -0.65f, 0.0f, 0.444f, 0.327f, 1.0f, -0.648f, 0.0f, 0.447f, 0.331f, 1.0f, -0.646f, 0.0f, 0.45f, 0.334f, 1.0f, + -0.643f, 0.0f, 0.453f, 0.334f, 1.0f, -0.641f, 0.0f, 0.456f, 0.334f, 1.0f, -0.639f, 0.0f, 0.459f, 0.334f, 1.0f, -0.636f, 0.0f, 0.462f, 0.333f, 1.0f, + -0.634f, 0.0f, 0.466f, 0.332f, 1.0f, -0.631f, 0.0f, 0.469f, 0.332f, 1.0f, -0.628f, 0.0f, 0.473f, 0.332f, 1.0f, -0.625f, 0.0f, 0.476f, 0.333f, 1.0f, + -0.622f, 0.0f, 0.48f, 0.335f, 1.0f, -0.618f, 0.0f, 0.483f, 0.338f, 1.0f, -0.615f, 0.0f, 0.488f, 0.342f, 1.0f, -0.611f, 0.0f, 0.492f, 0.347f, 1.0f, + -0.608f, 0.0f, 0.495f, 0.352f, 1.0f, -0.605f, 0.0f, 0.5f, 0.358f, 1.0f, -0.601f, 0.0f, 0.505f, 0.363f, 1.0f, -0.597f, 0.0f, 0.509f, 0.366f, 1.0f, + -0.593f, 0.0f, 0.514f, 0.367f, 1.0f, -0.589f, 0.0f, 0.518f, 0.367f, 1.0f, -0.585f, 0.0f, 0.522f, 0.369f, 1.0f, -0.582f, 0.0f, 0.526f, 0.372f, 1.0f, + -0.578f, 0.0f, 0.531f, 0.376f, 1.0f, -0.575f, 0.0f, 0.535f, 0.382f, 1.0f, -0.571f, 0.0f, 0.539f, 0.388f, 1.0f, -0.567f, 0.0f, 0.543f, 0.394f, 1.0f, + -0.563f, 0.0f, 0.547f, 0.4f, 1.0f, -0.56f, 0.0f, 0.551f, 0.406f, 1.0f, -0.556f, 0.0f, 0.555f, 0.411f, 1.0f, -0.552f, 0.0f, 0.559f, 0.415f, 1.0f, + -0.548f, 0.0f, 0.563f, 0.418f, 1.0f, -0.544f, 0.0f, 0.566f, 0.419f, 1.0f, -0.54f, 0.0f, 0.569f, 0.42f, 1.0f, -0.537f, 0.0f, 0.572f, 0.421f, 1.0f, + -0.533f, 0.0f, 0.576f, 0.421f, 1.0f, -0.529f, 0.0f, 0.579f, 0.421f, 1.0f, -0.526f, 0.0f, 0.582f, 0.422f, 1.0f, -0.523f, 0.0f, 0.585f, 0.422f, 1.0f, + -0.52f, 0.0f, 0.588f, 0.423f, 1.0f, -0.516f, 0.0f, 0.591f, 0.426f, 1.0f, -0.513f, 0.0f, 0.594f, 0.43f, 1.0f, -0.51f, 0.0f, 0.597f, 0.435f, 1.0f, + -0.507f, 0.0f, 0.6f, 0.441f, 1.0f, -0.504f, 0.0f, 0.603f, 0.447f, 1.0f, -0.501f, 0.0f, 0.606f, 0.453f, 1.0f, -0.498f, 0.0f, 0.609f, 0.458f, 1.0f, + -0.496f, 0.0f, 0.611f, 0.461f, 1.0f, -0.493f, 0.0f, 0.614f, 0.465f, 1.0f, -0.49f, 0.0f, 0.616f, 0.468f, 1.0f, -0.487f, 0.0f, 0.619f, 0.472f, 1.0f, + -0.484f, 0.0f, 0.621f, 0.476f, 1.0f, -0.482f, 0.0f, 0.624f, 0.48f, 1.0f, -0.479f, 0.0f, 0.627f, 0.484f, 1.0f, -0.476f, 0.0f, 0.629f, 0.487f, 1.0f, + -0.473f, 0.0f, 0.632f, 0.491f, 1.0f, -0.471f, 0.0f, 0.634f, 0.495f, 1.0f, -0.468f, 0.0f, 0.637f, 0.499f, 1.0f, -0.465f, 0.0f, 0.639f, 0.504f, 1.0f, + -0.462f, 0.0f, 0.641f, 0.508f, 1.0f, -0.459f, 0.0f, 0.643f, 0.513f, 1.0f, -0.456f, 0.0f, 0.646f, 0.519f, 1.0f, -0.453f, 0.0f, 0.648f, 0.525f, 1.0f, + -0.45f, 0.0f, 0.65f, 0.533f, 1.0f, -0.447f, 0.0f, 0.652f, 0.54f, 1.0f, -0.444f, 0.0f, 0.655f, 0.546f, 1.0f, -0.441f, 0.0f, 0.657f, 0.553f, 1.0f, + -0.438f, 0.0f, 0.659f, 0.56f, 1.0f, -0.435f, 0.0f, 0.662f, 0.567f, 1.0f, -0.432f, 0.0f, 0.664f, 0.574f, 1.0f, -0.429f, 0.0f, 0.666f, 0.58f, 1.0f, + -0.426f, 0.0f, 0.669f, 0.585f, 1.0f, -0.423f, 0.0f, 0.671f, 0.591f, 1.0f, -0.419f, 0.0f, 0.673f, 0.595f, 1.0f, -0.416f, 0.0f, 0.675f, 0.6f, 1.0f, + -0.412f, 0.0f, 0.678f, 0.604f, 1.0f, -0.409f, 0.0f, 0.68f, 0.609f, 1.0f, -0.405f, 0.0f, 0.682f, 0.613f, 1.0f, -0.401f, 0.0f, 0.684f, 0.618f, 1.0f, + -0.398f, 0.0f, 0.687f, 0.622f, 1.0f, -0.394f, 0.0f, 0.689f, 0.627f, 1.0f, -0.39f, 0.0f, 0.692f, 0.632f, 1.0f, -0.386f, 0.0f, 0.694f, 0.638f, 1.0f, + -0.381f, 0.0f, 0.697f, 0.643f, 1.0f, -0.377f, 0.0f, 0.7f, 0.649f, 1.0f, -0.373f, 0.0f, 0.702f, 0.654f, 1.0f, -0.368f, 0.0f, 0.705f, 0.659f, 1.0f, + -0.363f, 0.0f, 0.707f, 0.663f, 1.0f, -0.359f, 0.0f, 0.71f, 0.667f, 1.0f, -0.354f, 0.0f, 0.712f, 0.671f, 1.0f, -0.349f, 0.0f, 0.715f, 0.674f, 1.0f, + -0.345f, 0.0f, 0.717f, 0.677f, 1.0f, -0.34f, 0.0f, 0.72f, 0.68f, 1.0f, -0.335f, 0.0f, 0.722f, 0.683f, 1.0f, -0.33f, 0.0f, 0.725f, 0.685f, 1.0f, + -0.326f, 0.0f, 0.727f, 0.687f, 1.0f, -0.321f, 0.0f, 0.73f, 0.689f, 1.0f, -0.316f, 0.0f, 0.732f, 0.691f, 1.0f, -0.312f, 0.0f, 0.734f, 0.693f, 1.0f, + -0.307f, 0.0f, 0.736f, 0.694f, 1.0f, -0.302f, 0.0f, 0.738f, 0.696f, 1.0f, -0.298f, 0.0f, 0.74f, 0.697f, 1.0f, -0.293f, 0.0f, 0.741f, 0.698f, 1.0f, + -0.288f, 0.0f, 0.743f, 0.699f, 1.0f, -0.284f, 0.0f, 0.745f, 0.699f, 1.0f, -0.279f, 0.0f, 0.746f, 0.7f, 1.0f, -0.275f, 0.0f, 0.748f, 0.701f, 1.0f, + -0.27f, 0.0f, 0.749f, 0.702f, 1.0f, -0.265f, 0.0f, 0.751f, 0.702f, 1.0f, -0.261f, 0.0f, 0.752f, 0.704f, 1.0f, -0.256f, 0.0f, 0.753f, 0.705f, 1.0f, + -0.252f, 0.0f, 0.755f, 0.706f, 1.0f, -0.247f, 0.0f, 0.756f, 0.707f, 1.0f, -0.242f, 0.0f, 0.757f, 0.709f, 1.0f, -0.237f, 0.0f, 0.758f, 0.711f, 1.0f, + -0.233f, 0.0f, 0.759f, 0.713f, 1.0f, -0.228f, 0.0f, 0.761f, 0.715f, 1.0f, -0.223f, 0.0f, 0.762f, 0.717f, 1.0f, -0.218f, 0.0f, 0.763f, 0.719f, 1.0f, + -0.213f, 0.0f, 0.764f, 0.721f, 1.0f, -0.209f, 0.0f, 0.765f, 0.723f, 1.0f, -0.204f, 0.0f, 0.765f, 0.726f, 1.0f, -0.199f, 0.0f, 0.766f, 0.728f, 1.0f, + -0.194f, 0.0f, 0.767f, 0.73f, 1.0f, -0.189f, 0.0f, 0.768f, 0.731f, 1.0f, -0.183f, 0.0f, 0.769f, 0.733f, 1.0f, -0.178f, 0.0f, 0.77f, 0.735f, 1.0f, + -0.173f, 0.0f, 0.77f, 0.736f, 1.0f, -0.168f, 0.0f, 0.771f, 0.738f, 1.0f, -0.163f, 0.0f, 0.772f, 0.739f, 1.0f, -0.158f, 0.0f, 0.772f, 0.741f, 1.0f, + -0.152f, 0.0f, 0.773f, 0.742f, 1.0f, -0.147f, 0.0f, 0.774f, 0.744f, 1.0f, -0.142f, 0.0f, 0.774f, 0.746f, 1.0f, -0.137f, 0.0f, 0.775f, 0.748f, 1.0f, + -0.132f, 0.0f, 0.775f, 0.749f, 1.0f, -0.127f, 0.0f, 0.776f, 0.751f, 1.0f, -0.122f, 0.0f, 0.776f, 0.752f, 1.0f, -0.117f, 0.0f, 0.776f, 0.753f, 1.0f, + -0.112f, 0.0f, 0.777f, 0.754f, 1.0f, -0.108f, 0.0f, 0.777f, 0.755f, 1.0f, -0.103f, 0.0f, 0.777f, 0.755f, 1.0f, -0.099f, 0.0f, 0.777f, 0.756f, 1.0f, + -0.095f, 0.0f, 0.778f, 0.757f, 1.0f, -0.09f, 0.0f, 0.778f, 0.758f, 1.0f, -0.086f, 0.0f, 0.778f, 0.759f, 1.0f, -0.082f, 0.0f, 0.778f, 0.759f, 1.0f, + -0.077f, 0.0f, 0.778f, 0.76f, 1.0f, -0.073f, 0.0f, 0.779f, 0.76f, 1.0f, -0.069f, 0.0f, 0.779f, 0.761f, 1.0f, -0.064f, 0.0f, 0.779f, 0.761f, 1.0f, + -0.06f, 0.0f, 0.779f, 0.761f, 1.0f, -0.055f, 0.0f, 0.78f, 0.762f, 1.0f, -0.051f, 0.0f, 0.78f, 0.762f, 1.0f, -0.046f, 0.0f, 0.78f, 0.762f, 1.0f, + -0.041f, 0.0f, 0.78f, 0.762f, 1.0f, -0.037f, 0.0f, 0.781f, 0.762f, 1.0f, -0.032f, 0.0f, 0.781f, 0.763f, 1.0f, -0.027f, 0.0f, 0.781f, 0.763f, 1.0f, + -0.022f, 0.0f, 0.781f, 0.763f, 1.0f, -0.017f, 0.0f, 0.781f, 0.764f, 1.0f, -0.012f, 0.0f, 0.782f, 0.764f, 1.0f, -0.006f, 0.0f, 0.782f, 0.764f, 1.0f, + -0.001f, 0.0f, 0.782f, 0.765f, 1.0f, 0.004f, 0.0f, 0.782f, 0.766f, 1.0f, 0.009f, 0.0f, 0.782f, 0.766f, 1.0f, 0.015f, 0.0f, 0.782f, 0.767f, 1.0f, + 0.02f, 0.0f, 0.782f, 0.768f, 1.0f, 0.025f, 0.0f, 0.782f, 0.769f, 1.0f, 0.031f, 0.0f, 0.782f, 0.77f, 1.0f, 0.036f, 0.0f, 0.782f, 0.771f, 1.0f, + 0.042f, 0.0f, 0.782f, 0.772f, 1.0f, 0.048f, 0.0f, 0.782f, 0.773f, 1.0f, 0.053f, 0.0f, 0.782f, 0.774f, 1.0f, 0.059f, 0.0f, 0.782f, 0.775f, 1.0f, + 0.065f, 0.0f, 0.782f, 0.775f, 1.0f, 0.07f, 0.0f, 0.782f, 0.776f, 1.0f, 0.076f, 0.0f, 0.782f, 0.776f, 1.0f, 0.082f, 0.0f, 0.782f, 0.776f, 1.0f, + 0.088f, 0.0f, 0.782f, 0.776f, 1.0f, 0.094f, 0.0f, 0.782f, 0.777f, 1.0f, 0.1f, 0.0f, 0.781f, 0.777f, 1.0f, 0.106f, 0.0f, 0.781f, 0.778f, 1.0f, + 0.111f, 0.0f, 0.781f, 0.779f, 1.0f, 0.117f, 0.0f, 0.781f, 0.779f, 1.0f, 0.123f, 0.0f, 0.781f, 0.78f, 1.0f, 0.129f, 0.0f, 0.78f, 0.78f, 1.0f, + 0.135f, 0.0f, 0.78f, 0.781f, 1.0f, 0.141f, 0.0f, 0.779f, 0.781f, 1.0f, 0.147f, 0.0f, 0.779f, 0.782f, 1.0f, 0.153f, 0.0f, 0.778f, 0.783f, 1.0f, + 0.159f, 0.0f, 0.777f, 0.784f, 1.0f, 0.165f, 0.0f, 0.776f, 0.785f, 1.0f, 0.171f, 0.0f, 0.775f, 0.786f, 1.0f, 0.178f, 0.0f, 0.774f, 0.787f, 1.0f, + 0.185f, 0.0f, 0.773f, 0.788f, 1.0f, 0.192f, 0.0f, 0.772f, 0.789f, 1.0f, 0.2f, 0.0f, 0.771f, 0.79f, 1.0f, 0.208f, 0.0f, 0.77f, 0.791f, 1.0f, + 0.218f, 0.0f, 0.768f, 0.793f, 1.0f, 0.228f, 0.0f, 0.766f, 0.796f, 1.0f, 0.239f, 0.0f, 0.764f, 0.799f, 1.0f, 0.25f, 0.0f, 0.762f, 0.802f, 1.0f, + 0.261f, 0.0f, 0.759f, 0.806f, 1.0f, 0.271f, 0.0f, 0.755f, 0.81f, 1.0f, 0.282f, 0.0f, 0.752f, 0.815f, 1.0f, 0.293f, 0.0f, 0.748f, 0.819f, 1.0f, + 0.304f, 0.0f, 0.744f, 0.825f, 1.0f, 0.315f, 0.0f, 0.74f, 0.83f, 1.0f, 0.326f, 0.0f, 0.736f, 0.836f, 1.0f, 0.337f, 0.0f, 0.731f, 0.843f, 1.0f, + 0.349f, 0.0f, 0.727f, 0.85f, 1.0f, 0.361f, 0.0f, 0.722f, 0.858f, 1.0f, 0.372f, 0.0f, 0.718f, 0.866f, 1.0f, 0.384f, 0.0f, 0.712f, 0.874f, 1.0f, + 0.395f, 0.0f, 0.706f, 0.882f, 1.0f, 0.407f, 0.0f, 0.7f, 0.89f, 1.0f, 0.418f, 0.0f, 0.693f, 0.898f, 1.0f, 0.43f, 0.0f, 0.685f, 0.905f, 1.0f, + 0.442f, 0.0f, 0.677f, 0.912f, 1.0f, 0.458f, 0.0f, 0.666f, 0.918f, 1.0f, 0.473f, 0.0f, 0.654f, 0.924f, 1.0f, 0.49f, 0.0f, 0.64f, 0.93f, 1.0f, + 0.506f, 0.0f, 0.625f, 0.935f, 1.0f, 0.522f, 0.0f, 0.611f, 0.939f, 1.0f, 0.538f, 0.0f, 0.596f, 0.941f, 1.0f, 0.554f, 0.0f, 0.58f, 0.942f, 1.0f, + 0.569f, 0.0f, 0.564f, 0.941f, 1.0f, 0.584f, 0.0f, 0.548f, 0.935f, 1.0f, 0.598f, 0.0f, 0.533f, 0.925f, 1.0f, 0.612f, 0.0f, 0.517f, 0.91f, 1.0f, + 0.625f, 0.0f, 0.501f, 0.891f, 1.0f, 0.638f, 0.0f, 0.484f, 0.868f, 1.0f, 0.65f, 0.0f, 0.468f, 0.839f, 1.0f, 0.662f, 0.0f, 0.452f, 0.806f, 1.0f, + 0.671f, 0.0f, 0.437f, 0.766f, 1.0f, 0.679f, 0.0f, 0.423f, 0.718f, 1.0f, 0.685f, 0.0f, 0.412f, 0.661f, 1.0f, 0.691f, 0.0f, 0.403f, 0.595f, 1.0f, + 0.697f, 0.0f, 0.396f, 0.519f, 1.0f, 0.701f, 0.0f, 0.391f, 0.44f, 1.0f, 0.704f, 0.0f, 0.387f, 0.344f, 1.0f, 0.707f, 0.0f, 0.384f, 0.264f, 1.0f, + 0.711f, 0.0f, 0.38f, 0.133f, 1.0f, +}; + +/* ***************************************************************** */ +/* Monkey Color Data */ + +static const ColorTemplate gp_monkey_pct_black = { + "Black", + {0.0f, 0.0f, 0.0f, 1.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, +}; + +static const ColorTemplate gp_monkey_pct_skin = { + "Skin", + {0.553f, 0.39f, 0.266f, 0.0f}, + {0.733f, 0.567f, 0.359f, 1.0f}, +}; + +static const ColorTemplate gp_monkey_pct_skin_light = { + "Skin_Light", + {0.553f, 0.39f, 0.266f, 0.0f}, + {0.913f, 0.828f, 0.637f, 1.0f}, +}; + +static const ColorTemplate gp_monkey_pct_skin_shadow = { + "Skin_Shadow", + {0.553f, 0.39f, 0.266f, 0.0f}, + {0.32f, 0.29f, 0.223f, 1.0f}, +}; + +static const ColorTemplate gp_monkey_pct_eyes = { + "Eyes", + {0.553f, 0.39f, 0.266f, 0.0f}, + {0.773f, 0.762f, 0.73f, 1.0f}, +}; + +static const ColorTemplate gp_monkey_pct_pupils = { + "Pupils", + {0.107f, 0.075f, 0.051f, 0.0f}, + {0.153f, 0.057f, 0.063f, 1.0f}, +}; + +/* ***************************************************************** */ +/* Monkey API */ + +/* add a 2D Suzanne (original model created by Matias Mendiola) */ +void ED_gpencil_create_monkey(bContext *C, float mat[4][4]) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + bGPdata *gpd = (bGPdata *)ob->data; + bGPDstroke *gps; + + /* create colors */ + int color_Black = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_black); + int color_Skin = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin); + int color_Skin_Light = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_light); + int color_Skin_Shadow = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_skin_shadow); + int color_Eyes = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_eyes); + int color_Pupils = gpencil_monkey_color(bmain, ob, &gp_monkey_pct_pupils); + + /* layers */ + /* NOTE: For now, we just add new layers, to make it easier to separate out old/new instances */ + bGPDlayer *Colors = BKE_gpencil_layer_addnew(gpd, "Colors", false); + bGPDlayer *Lines = BKE_gpencil_layer_addnew(gpd, "Lines", true); + + /* frames */ + /* NOTE: No need to check for existing, as this will tkae care of it for us */ + bGPDframe *frameColor = BKE_gpencil_frame_addnew(Colors, cfra_eval); + bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, cfra_eval); + + /* generate strokes */ + gps = BKE_gpencil_add_stroke(frameColor, color_Skin, 538, 3); + BKE_gpencil_stroke_add_points(gps, data0, 538, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Eyes, 136, 3); + BKE_gpencil_stroke_add_points(gps, data1, 136, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin, 2, 3); + BKE_gpencil_stroke_add_points(gps, data2, 2, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 1, 3); + BKE_gpencil_stroke_add_points(gps, data3, 1, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 1, 3); + BKE_gpencil_stroke_add_points(gps, data4, 1, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 48, 3); + BKE_gpencil_stroke_add_points(gps, data5, 48, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 47, 3); + BKE_gpencil_stroke_add_points(gps, data6, 47, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 162, 3); + BKE_gpencil_stroke_add_points(gps, data7, 162, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 55, 3); + BKE_gpencil_stroke_add_points(gps, data8, 55, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 70, 3); + BKE_gpencil_stroke_add_points(gps, data9, 70, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Light, 227, 3); + BKE_gpencil_stroke_add_points(gps, data10, 227, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 1, 3); + BKE_gpencil_stroke_add_points(gps, data11, 1, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 123, 3); + BKE_gpencil_stroke_add_points(gps, data12, 123, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 125, 3); + BKE_gpencil_stroke_add_points(gps, data13, 125, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 45, 3); + BKE_gpencil_stroke_add_points(gps, data14, 45, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 44, 3); + BKE_gpencil_stroke_add_points(gps, data15, 44, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 84, 3); + BKE_gpencil_stroke_add_points(gps, data16, 84, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 56, 3); + BKE_gpencil_stroke_add_points(gps, data17, 56, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 59, 3); + BKE_gpencil_stroke_add_points(gps, data18, 59, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Skin_Shadow, 100, 3); + BKE_gpencil_stroke_add_points(gps, data19, 100, mat); + + gps = BKE_gpencil_add_stroke(frameColor, color_Eyes, 136, 3); + BKE_gpencil_stroke_add_points(gps, data20, 136, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 353, 3); + BKE_gpencil_stroke_add_points(gps, data21, 353, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 309, 3); + BKE_gpencil_stroke_add_points(gps, data22, 309, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 209, 3); + BKE_gpencil_stroke_add_points(gps, data23, 209, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 133, 3); + BKE_gpencil_stroke_add_points(gps, data24, 133, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 389, 3); + BKE_gpencil_stroke_add_points(gps, data25, 389, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 41, 3); + BKE_gpencil_stroke_add_points(gps, data26, 41, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 77, 3); + BKE_gpencil_stroke_add_points(gps, data27, 77, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 257, 3); + BKE_gpencil_stroke_add_points(gps, data28, 257, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 205, 3); + BKE_gpencil_stroke_add_points(gps, data29, 205, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 3); + BKE_gpencil_stroke_add_points(gps, data30, 33, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 37, 3); + BKE_gpencil_stroke_add_points(gps, data31, 37, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 201, 3); + BKE_gpencil_stroke_add_points(gps, data32, 201, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 69, 3); + BKE_gpencil_stroke_add_points(gps, data33, 69, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 57, 3); + BKE_gpencil_stroke_add_points(gps, data34, 57, mat); + + gps = BKE_gpencil_add_stroke(frameLines, color_Black, 261, 3); + BKE_gpencil_stroke_add_points(gps, data35, 261, mat); + + /* update depsgraph */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + gpd->flag |= GP_DATA_CACHE_IS_DIRTY; +} + + +/* ***************************************************************** */ diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index bd9bfcf7025..52642fb2570 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -48,6 +48,7 @@ #include "BLT_translation.h" +#include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -60,6 +61,9 @@ #include "BKE_library.h" #include "BKE_report.h" #include "BKE_screen.h" +#include "BKE_object_deform.h" +#include "BKE_colortools.h" +#include "BKE_material.h" #include "UI_interface.h" @@ -80,6 +84,9 @@ #include "GPU_immediate_util.h" #include "GPU_state.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "gpencil_intern.h" /* ************************************************ */ @@ -89,7 +96,9 @@ typedef struct tGP_BrushEditData { /* Current editor/region/etc. */ /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */ + Depsgraph *depsgraph; Scene *scene; + Object *object; ScrArea *sa; ARegion *ar; @@ -114,6 +123,10 @@ typedef struct tGP_BrushEditData { /* Start of new sculpt stroke */ bool first; + /* Is multiframe editing enabled, and are we using falloff for that? */ + bool is_multiframe; + bool use_multiframe_falloff; + /* Current frame */ int cfra; @@ -128,6 +141,13 @@ typedef struct tGP_BrushEditData { /* - effect vector (e.g. 2D/3D translation for grab brush) */ float dvec[3]; + /* - multiframe falloff factor */ + float mf_falloff; + + /* active vertex group */ + int vrgroup; + + /* brush geometry (bounding box) */ rcti brush_rect; @@ -147,12 +167,34 @@ typedef struct tGP_BrushEditData { /* Callback for performing some brush operation on a single point */ -typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int i, +typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2]); /* ************************************************ */ /* Utility Functions */ +/* apply lock axis reset */ +static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, const float save_pt[3]) +{ + if (gso->sa->spacetype != SPACE_VIEW3D) { + return; + } + + ToolSettings *ts = gso->scene->toolsettings; + int axis = ts->gp_sculpt.lock_axis; + + /* lock axis control */ + if (axis == 1) { + pt->x = save_pt[0]; + } + if (axis == 2) { + pt->y = save_pt[1]; + } + if (axis == 3) { + pt->z = save_pt[2]; + } +} + /* Context ---------------------------------------- */ /* Get the sculpting settings */ @@ -162,10 +204,18 @@ static GP_BrushEdit_Settings *gpsculpt_get_settings(Scene *scene) } /* Get the active brush */ -static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene) +static GP_EditBrush_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode) { GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt; - return &gset->brush[gset->brushtype]; + GP_EditBrush_Data *brush = NULL; + if (is_weight_mode) { + brush = &gset->brush[gset->weighttype]; + } + else { + brush = &gset->brush[gset->brushtype]; + } + + return brush; } /* Brush Operations ------------------------------- */ @@ -181,6 +231,14 @@ static bool gp_brush_invert_check(tGP_BrushEditData *gso) invert ^= true; } + /* set temporary status */ + if (invert) { + gso->brush->flag |= GP_EDITBRUSH_FLAG_TMP_INVERT; + } + else { + gso->brush->flag &= ~GP_EDITBRUSH_FLAG_TMP_INVERT; + } + return invert; } @@ -208,6 +266,9 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c influence *= fac; } + /* apply multiframe falloff */ + influence *= gso->mf_falloff; + /* return influence */ return influence; } @@ -222,29 +283,34 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c /* Smooth Brush */ /* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */ -static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, - const int radius, const int co[2]) +static bool gp_brush_smooth_apply( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) { - GP_EditBrush_Data *brush = gso->brush; + // GP_EditBrush_Data *brush = gso->brush; float inf = gp_brush_influence_calc(gso, radius, co); - bool affect_pressure = (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) != 0; /* need one flag enabled by default */ - if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION | - GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | - GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0) + if ((gso->settings->flag & + (GP_BRUSHEDIT_FLAG_APPLY_POSITION | + GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | + GP_BRUSHEDIT_FLAG_APPLY_THICKNESS | + GP_BRUSHEDIT_FLAG_APPLY_UV)) == 0) { gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION; } /* perform smoothing */ if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_POSITION) { - gp_smooth_stroke(gps, i, inf, affect_pressure); + BKE_gpencil_smooth_stroke(gps, pt_index, inf); } if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_STRENGTH) { - gp_smooth_stroke_strength(gps, i, inf); + BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf); } if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_THICKNESS) { - gp_smooth_stroke_thickness(gps, i, inf); + BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf); + } + if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_UV) { + BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf); } return true; @@ -254,10 +320,11 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i /* Line Thickness Brush */ /* Make lines thicker or thinner by the specified amounts */ -static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, - const int radius, const int co[2]) +static bool gp_brush_thickness_apply( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) { - bGPDspoint *pt = gps->points + i; + bGPDspoint *pt = gps->points + pt_index; float inf; /* Compute strength of effect @@ -294,28 +361,29 @@ static bool gp_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in /* Make color more or less transparent by the specified amounts */ static bool gp_brush_strength_apply( - tGP_BrushEditData *gso, bGPDstroke *gps, int i, + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2]) { - bGPDspoint *pt = gps->points + i; + bGPDspoint *pt = gps->points + pt_index; float inf; /* Compute strength of effect - * - We divide the strength by 10, so that users can set "sane" values. + * - We divide the strength, so that users can set "sane" values. * Otherwise, good default values are in the range of 0.093 */ - inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; + inf = gp_brush_influence_calc(gso, radius, co) / 20.0f; /* apply */ - // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff if (gp_brush_invert_check(gso)) { - /* make line thinner - reduce stroke pressure */ + /* make line more transparent - reduce alpha factor */ pt->strength -= inf; } else { - /* make line thicker - increase stroke pressure */ + /* make line more opaque - increase stroke strength */ pt->strength += inf; } + /* smooth the strength */ + BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf); /* Strength should stay within [0.0, 1.0] */ CLAMP(pt->strength, 0.0f, 1.0f); @@ -382,8 +450,9 @@ static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps) } /* store references to stroke points in the initial stage */ -static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, int i, - const int radius, const int co[2]) +static bool gp_brush_grab_store_points( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) { tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); float inf = gp_brush_influence_calc(gso, radius, co); @@ -392,7 +461,7 @@ static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, BLI_assert(data->size < data->capacity); /* insert this point into the set of affected points */ - data->points[data->size] = i; + data->points[data->size] = pt_index; data->weights[data->size] = inf; data->size++; @@ -431,7 +500,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso) /* Apply grab transform to all relevant points of the affected strokes */ static void gp_brush_grab_apply_cached( - tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, float diff_mat[4][4]) + tGP_BrushEditData *gso, bGPDstroke *gps, float diff_mat[4][4]) { tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); int i; @@ -443,23 +512,21 @@ static void gp_brush_grab_apply_cached( /* adjust the amount of displacement to apply */ mul_v3_v3fl(delta, gso->dvec, data->weights[i]); - if (!parented) { - /* apply */ - add_v3_v3(&pt->x, delta); - } - else { - float fpt[3]; - /* apply transformation */ - mul_v3_m4v3(fpt, diff_mat, &pt->x); - /* apply */ - add_v3_v3(fpt, delta); - copy_v3_v3(&pt->x, fpt); - /* undo transformation to the init parent position */ - float inverse_diff_mat[4][4]; - invert_m4_m4(inverse_diff_mat, diff_mat); - mul_m4_v3(inverse_diff_mat, &pt->x); - } + float fpt[3]; + float save_pt[3]; + copy_v3_v3(save_pt, &pt->x); + /* apply transformation */ + mul_v3_m4v3(fpt, diff_mat, &pt->x); + /* apply */ + add_v3_v3v3(&pt->x, fpt, delta); + /* undo transformation to the init parent position */ + float inverse_diff_mat[4][4]; + invert_m4_m4(inverse_diff_mat, diff_mat); + mul_m4_v3(inverse_diff_mat, &pt->x); + + /* compute lock axis */ + gpsculpt_compute_lock_axis(gso, pt, save_pt); } } @@ -480,10 +547,14 @@ static void gp_brush_grab_stroke_free(void *ptr) /* Push Brush */ /* NOTE: Depends on gp_brush_grab_calc_dvec() */ -static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, - const int radius, const int co[2]) +static bool gp_brush_push_apply( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) { - bGPDspoint *pt = gps->points + i; + bGPDspoint *pt = gps->points + pt_index; + float save_pt[3]; + copy_v3_v3(save_pt, &pt->x); + float inf = gp_brush_influence_calc(gso, radius, co); float delta[3] = {0.0f}; @@ -493,6 +564,9 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, /* apply */ add_v3_v3(&pt->x, delta); + /* compute lock axis */ + gpsculpt_compute_lock_axis(gso, pt, save_pt); + /* done */ return true; } @@ -512,7 +586,8 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso) float *rvec = ED_view3d_cursor3d_get(gso->scene, v3d)->location; float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); - float mval_f[2] = {UNPACK2(gso->mval)}; + float mval_f[2]; + copy_v2fl_v2i(mval_f, gso->mval); float mval_prj[2]; float dvec[3]; @@ -536,12 +611,15 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso) } /* Shrink distance between midpoint and this point... */ -static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, - const int radius, const int co[2]) +static bool gp_brush_pinch_apply( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) { - bGPDspoint *pt = gps->points + i; + bGPDspoint *pt = gps->points + pt_index; float fac, inf; float vec[3]; + float save_pt[3]; + copy_v3_v3(save_pt, &pt->x); /* Scale down standard influence value to get it more manageable... * - No damping = Unmanageable at > 0.5 strength @@ -571,6 +649,9 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, /* 3) Translate back to original space, with the shrinkage applied */ add_v3_v3v3(&pt->x, gso->dvec, vec); + /* compute lock axis */ + gpsculpt_compute_lock_axis(gso, pt, save_pt); + /* done */ return true; } @@ -582,11 +663,14 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, * convert the rotated point and convert it into "data" space */ -static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, - const int radius, const int co[2]) +static bool gp_brush_twist_apply( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) { - bGPDspoint *pt = gps->points + i; + bGPDspoint *pt = gps->points + pt_index; float angle, inf; + float save_pt[3]; + copy_v3_v3(save_pt, &pt->x); /* Angle to rotate by */ inf = gp_brush_influence_calc(gso, radius, co); @@ -615,6 +699,9 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center (center is stored in dvec) */ mul_m3_v3(rmat, vec); add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */ + + /* compute lock axis */ + gpsculpt_compute_lock_axis(gso, pt, save_pt); } else { const float axis[3] = {0.0f, 0.0f, 1.0f}; @@ -654,10 +741,13 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, /* Randomize Brush */ /* Apply some random jitter to the point */ -static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i, - const int radius, const int co[2]) +static bool gp_brush_randomize_apply( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) { - bGPDspoint *pt = gps->points + i; + bGPDspoint *pt = gps->points + pt_index; + float save_pt[3]; + copy_v3_v3(save_pt, &pt->x); /* Amount of jitter to apply depends on the distance of the point to the cursor, * as well as the strength of the brush @@ -667,7 +757,8 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in /* need one flag enabled by default */ if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION | GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | - GP_BRUSHEDIT_FLAG_APPLY_THICKNESS)) == 0) + GP_BRUSHEDIT_FLAG_APPLY_THICKNESS | + GP_BRUSHEDIT_FLAG_APPLY_UV)) == 0) { gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION; } @@ -710,6 +801,8 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in float dvec[3]; ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac); add_v3_v3(&pt->x, dvec); + /* compute lock axis */ + gpsculpt_compute_lock_axis(gso, pt, save_pt); } } else { @@ -749,11 +842,76 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, in /* only limit lower value */ CLAMP_MIN(pt->pressure, 0.0f); } + /* apply random to UV (use pressure) */ + if (gso->settings->flag & GP_BRUSHEDIT_FLAG_APPLY_UV) { + if (BLI_rng_get_float(gso->rng) > 0.5f) { + pt->uv_rot += fac; + } + else { + pt->uv_rot -= fac; + } + CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); + } /* done */ return true; } +/* Weight Paint Brush */ + +/* Change weight paint for vertex groups */ +static bool gp_brush_weight_apply( + tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, + const int radius, const int co[2]) +{ + bGPDspoint *pt = gps->points + pt_index; + MDeformVert *dvert = gps->dvert + pt_index; + float inf; + + /* Compute strength of effect + * - We divide the strength by 10, so that users can set "sane" values. + * Otherwise, good default values are in the range of 0.093 + */ + inf = gp_brush_influence_calc(gso, radius, co) / 10.0f; + + /* need a vertex group */ + if (gso->vrgroup == -1) { + if (gso->object) { + BKE_object_defgroup_add(gso->object); + gso->vrgroup = 0; + } + } + /* get current weight */ + float curweight = 0.0f; + for (int i = 0; i < dvert->totweight; i++) { + MDeformWeight *gpw = &dvert->dw[i]; + if (gpw->def_nr == gso->vrgroup) { + curweight = gpw->weight; + break; + } + } + + if (gp_brush_invert_check(gso)) { + /* reduce weight */ + curweight -= inf; + } + else { + /* increase weight */ + curweight += inf; + } + + CLAMP(curweight, 0.0f, 1.0f); + BKE_gpencil_vgroup_add_point_weight(dvert, gso->vrgroup, curweight); + + /* weight should stay within [0.0, 1.0] */ + if (pt->pressure < 0.0f) + pt->pressure = 0.0f; + + return true; +} + + + /* ************************************************ */ /* Non Callback-Based Brushes */ @@ -827,7 +985,7 @@ static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso) /* Init colormap for mapping between the pasted stroke's source colour(names) * and the final colours that will be used here instead... */ - data->new_colors = gp_copybuf_validate_colormap(gso->gpd); + data->new_colors = gp_copybuf_validate_colormap(C); } /* Free custom data used for "clone" brush */ @@ -857,9 +1015,12 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; - Scene *scene = gso->scene; + Object *ob = CTX_data_active_object(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, true); bGPDstroke *gps; float delta[3]; @@ -882,17 +1043,22 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) new_stroke = MEM_dupallocN(gps); new_stroke->points = MEM_dupallocN(gps->points); + new_stroke->dvert = MEM_dupallocN(gps->dvert); + BKE_gpencil_stroke_weights_duplicate(gps, new_stroke); new_stroke->triangles = MEM_dupallocN(gps->triangles); new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); /* Fix color references */ - BLI_assert(new_stroke->colorname[0] != '\0'); - new_stroke->palcolor = BLI_ghash_lookup(data->new_colors, new_stroke->colorname); - - BLI_assert(new_stroke->palcolor != NULL); - BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname)); + Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr); + if ((ma) && (BKE_object_material_slot_find_index(ob, ma) > 0)) { + gps->mat_nr = BKE_object_material_slot_find_index(ob, ma) - 1; + CLAMP_MIN(gps->mat_nr, 0); + } + else { + gps->mat_nr = 0; /* only if the color is not found */ + } /* Adjust all the stroke's points, so that the strokes * get pasted relative to where the cursor is now @@ -976,57 +1142,6 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso) return true; } -/* ************************************************ */ -/* Cursor drawing */ - -/* Helper callback for drawing the cursor itself */ -static void gp_brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)) -{ - GP_EditBrush_Data *brush = gpsculpt_get_brush(CTX_data_scene(C)); - - if (brush) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - GPU_line_smooth(true); - GPU_blend(true); - - /* Inner Ring: Light color for action of the brush */ - /* TODO: toggle between add and remove? */ - immUniformColor4ub(255, 255, 255, 200); - imm_draw_circle_wire_2d(pos, x, y, brush->size, 40); - - /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ - immUniformColor3ub(30, 30, 30); - imm_draw_circle_wire_2d(pos, x, y, brush->size + 1, 40); - - immUnbindProgram(); - - GPU_blend(false); - GPU_line_smooth(false); - } -} - -/* Turn brush cursor in on/off */ -static void gpencil_toggle_brush_cursor(bContext *C, bool enable) -{ - GP_BrushEdit_Settings *gset = gpsculpt_get_settings(CTX_data_scene(C)); - - if (gset->paintcursor && !enable) { - /* clear cursor */ - WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor); - gset->paintcursor = NULL; - } - else if (enable) { - /* enable cursor */ - gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C), - NULL, - gp_brush_drawcursor, NULL); - } -} - - /* ************************************************ */ /* Header Info for GPencil Sculpt */ @@ -1054,17 +1169,40 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso) static bool gpsculpt_brush_init(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Object *ob = CTX_data_active_object(C); + + const bool is_weight_mode = ob->mode == OB_MODE_GPENCIL_WEIGHT; + /* set the brush using the tool */ + GP_BrushEdit_Settings *gset = &ts->gp_sculpt; + eGP_EditBrush_Types mode = RNA_enum_get(op->ptr, "mode"); + const bool keep_brush = RNA_boolean_get(op->ptr, "keep_brush"); + + if (!keep_brush) { + if (is_weight_mode) { + gset->weighttype = mode; + } + else { + gset->brushtype = mode; + } + } tGP_BrushEditData *gso; /* setup operator data */ gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData"); op->customdata = gso; + gso->depsgraph = CTX_data_depsgraph(C); /* store state */ gso->settings = gpsculpt_get_settings(scene); - gso->brush = gpsculpt_get_brush(scene); + gso->brush = gpsculpt_get_brush(scene, is_weight_mode); - gso->brush_type = gso->settings->brushtype; + if (is_weight_mode) { + gso->brush_type = gso->settings->weighttype; + } + else { + gso->brush_type = gso->settings->brushtype; + } /* Random generator, only init once. */ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); @@ -1078,10 +1216,31 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */ gso->scene = scene; + gso->object = ob; + if (ob) { + gso->vrgroup = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, gso->vrgroup)) { + gso->vrgroup = -1; + } + } + else { + gso->vrgroup = - 1; + } gso->sa = CTX_wm_area(C); gso->ar = CTX_wm_region(C); + /* multiframe settings */ + gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd); + gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_FRAME_FALLOFF) != 0; + + /* init multiedit falloff curve data before doing anything, + * so we won't have to do it again later + */ + if (gso->is_multiframe) { + curvemapping_initialize(ts->gp_sculpt.cur_falloff); + } + /* initialise custom data for brushes */ switch (gso->brush_type) { case GP_EDITBRUSH_TYPE_CLONE: @@ -1133,9 +1292,10 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) gpsculpt_brush_header_set(C, gso); /* setup cursor drawing */ - WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR); - gpencil_toggle_brush_cursor(C, true); - + //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR); + if (gso->sa->spacetype != SPACE_VIEW3D) { + ED_gpencil_toggle_brush_cursor(C, true, NULL); + } return true; } @@ -1179,7 +1339,12 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) /* disable cursor and headerprints */ ED_workspace_status_text(C, NULL); WM_cursor_modal_restore(win); - gpencil_toggle_brush_cursor(C, false); + if (gso->sa->spacetype != SPACE_VIEW3D) { + ED_gpencil_toggle_brush_cursor(C, false, NULL); + } + + /* disable temp invert flag */ + gso->brush->flag &= ~GP_EDITBRUSH_FLAG_TMP_INVERT; /* free operator data */ MEM_freeN(gso); @@ -1197,13 +1362,13 @@ static bool gpsculpt_brush_poll(bContext *C) static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) { - Scene *scene = gso->scene; bGPdata *gpd = gso->gpd; + bGPDlayer *gpl; - int cfra = CFRA; + int cfra_eval = (int)DEG_get_ctime(gso->depsgraph); /* only try to add a new frame if this is the first stroke, or the frame has changed */ - if ((gpd == NULL) || (cfra == gso->cfra)) + if ((gpd == NULL) || (cfra_eval == gso->cfra)) return; /* go through each layer, and ensure that we've got a valid frame to use */ @@ -1217,21 +1382,21 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso) * spent too much time editing the wrong frame... */ // XXX: should this be allowed when framelock is enabled? - if (gpf->framenum != cfra) { - BKE_gpencil_frame_addcopy(gpl, cfra); + if (gpf->framenum != cfra_eval) { + BKE_gpencil_frame_addcopy(gpl, cfra_eval); } } } /* save off new current frame, so that next update works fine */ - gso->cfra = cfra; + gso->cfra = cfra_eval; } /* Apply ----------------------------------------------- */ /* Apply brush operation to points in this stroke */ static bool gpsculpt_brush_do_stroke( - tGP_BrushEditData *gso, bGPDstroke *gps, bool parented, + tGP_BrushEditData *gso, bGPDstroke *gps, float diff_mat[4][4], GP_BrushApplyCb apply) { GP_SpaceConversion *gsc = &gso->gsc; @@ -1246,14 +1411,9 @@ static bool gpsculpt_brush_do_stroke( bool changed = false; if (gps->totpoints == 1) { - if (!parented) { - gp_point_to_xy(gsc, gps, gps->points, &pc1[0], &pc1[1]); - } - else { - bGPDspoint pt_temp; - gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); - gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); - } + bGPDspoint pt_temp; + gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { @@ -1280,19 +1440,12 @@ static bool gpsculpt_brush_do_stroke( continue; } } - if (!parented) { - gp_point_to_xy(gsc, gps, pt1, &pc1[0], &pc1[1]); - gp_point_to_xy(gsc, gps, pt2, &pc2[0], &pc2[1]); - } - else { - bGPDspoint npt; - gp_point_to_parent_space(pt1, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); - - gp_point_to_parent_space(pt2, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); - } + bGPDspoint npt; + gp_point_to_parent_space(pt1, diff_mat, &npt); + gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]); + gp_point_to_parent_space(pt2, diff_mat, &npt); + gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the boundbox of the selection stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || @@ -1342,9 +1495,114 @@ static bool gpsculpt_brush_do_stroke( return changed; } +/* Apply sculpt brushes to strokes in the given frame */ +static bool gpsculpt_brush_do_frame( + bContext *C, tGP_BrushEditData *gso, + bGPDlayer *gpl, bGPDframe *gpf, + float diff_mat[4][4]) +{ + bool changed = false; + Object *ob = CTX_data_active_object(C); + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + continue; + } + + switch (gso->brush_type) { + case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply); + break; + } + + case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply); + break; + } + + case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply); + break; + } + + case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */ + { + if (gso->first) { + /* First time this brush stroke is being applied: + * 1) Prepare data buffers (init/clear) for this stroke + * 2) Use the points now under the cursor + */ + gp_brush_grab_stroke_init(gso, gps); + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points); + } + else { + /* Apply effect to the stored points */ + gp_brush_grab_apply_cached(gso, gps, diff_mat); + changed |= true; + } + break; + } + + case GP_EDITBRUSH_TYPE_PUSH: /* Push points */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply); + break; + } + + case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply); + break; + } + + case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply); + break; + } + + case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply); + break; + } + + case GP_EDITBRUSH_TYPE_WEIGHT: /* Adjust vertex group weight */ + { + changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply); + break; + } + + + default: + printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type); + break; + } + /* Triangulation must be calculated if changed */ + if (changed) { + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + } + } + + return changed; +} + /* Perform two-pass brushes which modify the existing strokes */ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) { + ToolSettings *ts = CTX_data_tool_settings(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ + Object *obact = gso->object; + bGPdata *gpd = gso->gpd; bool changed = false; /* Calculate brush-specific data which applies equally to all points */ @@ -1378,104 +1636,53 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) /* Find visible strokes, and perform operations on those if hit */ - float diff_mat[4][4]; - bool parented = false; - CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = gpl->actframe; - if (gpf == NULL) + /* If no active frame, don't do anything... */ + if (gpl->actframe == NULL) { continue; - - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - parented = true; } - else { - parented = false; - } - - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) - continue; - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { - continue; - } - switch (gso->brush_type) { - case GP_EDITBRUSH_TYPE_SMOOTH: /* Smooth strokes */ - { - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_smooth_apply); - break; - } + /* calculate difference matrix */ + float diff_mat[4][4]; + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); - case GP_EDITBRUSH_TYPE_THICKNESS: /* Adjust stroke thickness */ - { - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_thickness_apply); - break; - } + /* Active Frame or MultiFrame? */ + if (gso->is_multiframe) { + /* init multiframe falloff options */ + int f_init = 0; + int f_end = 0; - case GP_EDITBRUSH_TYPE_STRENGTH: /* Adjust stroke color strength */ - { - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_strength_apply); - break; - } + if (gso->use_multiframe_falloff) { + BKE_gpencil_get_range_selected(gpl, &f_init, &f_end); + } - case GP_EDITBRUSH_TYPE_GRAB: /* Grab points */ - { - if (gso->first) { - /* First time this brush stroke is being applied: - * 1) Prepare data buffers (init/clear) for this stroke - * 2) Use the points now under the cursor - */ - gp_brush_grab_stroke_init(gso, gps); - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_grab_store_points); + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* Always do active frame; Otherwise, only include selected frames */ + if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { + /* compute multiframe falloff factor */ + if (gso->use_multiframe_falloff) { + /* Faloff depends on distance to active frame (relative to the overall frame range) */ + gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc( + gpf, gpl->actframe->framenum, + f_init, f_end, + ts->gp_sculpt.cur_falloff); } else { - /* Apply effect to the stored points */ - gp_brush_grab_apply_cached(gso, gps, parented, diff_mat); - changed |= true; + /* No falloff */ + gso->mf_falloff = 1.0f; } - break; - } - - case GP_EDITBRUSH_TYPE_PUSH: /* Push points */ - { - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_push_apply); - break; - } - - case GP_EDITBRUSH_TYPE_PINCH: /* Pinch points */ - { - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_pinch_apply); - break; - } - case GP_EDITBRUSH_TYPE_TWIST: /* Twist points around midpoint */ - { - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_twist_apply); - break; + /* affect strokes in this frame */ + changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat); } - - case GP_EDITBRUSH_TYPE_RANDOMIZE: /* Apply jitter */ - { - changed |= gpsculpt_brush_do_stroke(gso, gps, parented, diff_mat, gp_brush_randomize_apply); - break; - } - - default: - printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type); - break; - } - /* Triangulation must be calculated if changed */ - if (changed) { - gps->flag |= GP_STROKE_RECALC_CACHES; - gps->tot_triangles = 0; } } + else { + /* Apply to active frame's strokes */ + gso->mf_falloff = 1.0f; + changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + } } CTX_DATA_END; @@ -1529,6 +1736,7 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt /* Updates */ if (changed) { + DEG_id_tag_update(&gso->gpd->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } @@ -1852,6 +2060,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even /* Redraw toolsettings (brush settings)? */ if (redraw_toolsettings) { + DEG_id_tag_update(&gso->gpd->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); } @@ -1860,6 +2069,19 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even /* Operator --------------------------------------------- */ +static const EnumPropertyItem prop_gpencil_sculpt_brush_items[] = { + {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points" }, + {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes" }, + {GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", 0, "Strength", "Adjust color strength of strokes" }, + {GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle" }, + {GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them" }, + {GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush" }, + {GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush" }, + {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Introduce jitter/randomness into strokes" }, + {GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard" }, + {GP_EDITBRUSH_TYPE_WEIGHT, "WEIGHT", 0, "Weight", "Weight Paint" }, + {0, NULL, 0, NULL, NULL } +}; void GPENCIL_OT_brush_paint(wmOperatorType *ot) { @@ -1879,13 +2101,20 @@ void GPENCIL_OT_brush_paint(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; /* properties */ + ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_sculpt_brush_items, 0, "Mode", "Brush mode"); + RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); + PropertyRNA *prop; prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, "keep_brush", false, "Keep Brush", + "Keep current brush activated"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /* ************************************************ */ diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 79bfc5149ba..f662e9b42be 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -56,7 +56,6 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_gpencil_types.h" -#include "DNA_workspace_types.h" #include "BKE_collection.h" #include "BKE_context.h" @@ -74,6 +73,7 @@ #include "BKE_tracking.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "UI_interface.h" @@ -149,28 +149,24 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C), Poi * - assumes that the active space is the 3D-View */ static void gp_strokepoint_convertcoords( - bContext *C, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt, + bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt, float p3d[3], const rctf *subrect) { Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ + Object *obact = CTX_data_active_object(C); bGPDspoint mypt, *pt; float diff_mat[4][4]; pt = &mypt; - /* calculate difference matrix if parent object */ - if (gpl->parent == NULL) { - copy_v3_v3(&pt->x, &source_pt->x); - } - else { - /* apply parent transform */ - float fpt[3]; - ED_gpencil_parent_location(gpl, diff_mat); - mul_v3_m4v3(fpt, diff_mat, &source_pt->x); - copy_v3_v3(&pt->x, fpt); - } + /* apply parent transform */ + float fpt[3]; + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + mul_v3_m4v3(fpt, diff_mat, &source_pt->x); + copy_v3_v3(&pt->x, fpt); if (gps->flag & GP_STROKE_3DSPACE) { @@ -591,7 +587,7 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const fl } } -static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, +static void gp_stroke_to_path(bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point, const bool add_end_point, tGpTimingData *gtd) { @@ -655,7 +651,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv bp = &nu->bp[old_nbp - 1]; /* First point */ - gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect); if (prev_bp) { interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC); if (do_gtd) { @@ -676,7 +672,7 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv /* Second point */ /* Note dt2 is always negative, which marks the gap. */ if (gps->totpoints > 1) { - gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect); interp_v3_v3v3(p2, p, next_p, -GAP_DFAC); if (do_gtd) { dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC); @@ -697,9 +693,9 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv float p[3], next_p[3]; float dt = 0.0f; - gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect); if (gps->totpoints > 1) { - gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect); interp_v3_v3v3(p, p, next_p, -GAP_DFAC); if (do_gtd) { dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC); @@ -728,10 +724,10 @@ static void gp_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curv i++, pt++, bp++) { float p[3]; - float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC; + float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC; /* get coordinates to add at */ - gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, p, subrect); gp_stroke_to_path_add_point(gtd, bp, p, (prev_bp) ? prev_bp->vec : p, do_gtd, gps->inittime, pt->time, width, rad_fac, minmax_weights); @@ -801,7 +797,7 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt, } } -static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, +static void gp_stroke_to_bezier(bContext *C, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point, const bool add_end_point, tGpTimingData *gtd) { @@ -843,12 +839,12 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu /* get initial coordinates */ pt = gps->points; if (tot) { - gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect); if (tot > 1) { - gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect); } if (stitch && tot > 2) { - gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect); } } @@ -967,7 +963,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu /* add points */ for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) { - float width = pt->pressure * (gps->thickness + gpl->thickness) * WIDTH_CORR_FAC; + float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC; if (i || old_nbezt) { interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC); @@ -991,7 +987,7 @@ static void gp_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Cu copy_v3_v3(p3d_cur, p3d_next); if (i + 2 < tot) { - gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect); + gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect); } prev_bezt = bezt; @@ -1130,10 +1126,12 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd) { struct Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Collection *collection = CTX_data_collection(C); - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); bGPDstroke *gps, *prev_gps = NULL; Object *ob; Curve *cu; @@ -1192,12 +1190,12 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG switch (mode) { case GP_STROKECONVERT_PATH: - gp_stroke_to_path(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, + gp_stroke_to_path(C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, add_start_point, add_end_point, gtd); break; case GP_STROKECONVERT_CURVE: case GP_STROKECONVERT_POLY: /* convert after */ - gp_stroke_to_bezier(C, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, + gp_stroke_to_bezier(C, gpd, gpl, gps, cu, subrect_ptr, &nu, minmax_weights, rad_fac, stitch, add_start_point, add_end_point, gtd); break; default: @@ -1238,7 +1236,9 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG */ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op) { - Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + bGPDframe *gpf = NULL; bGPDstroke *gps = NULL; bGPDspoint *pt; @@ -1246,7 +1246,7 @@ static bool gp_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOpe int i; bool valid = true; - if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) || !(gps = gpf->strokes.first)) + if (!gpl || !(gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0)) || !(gps = gpf->strokes.first)) return false; do { @@ -1294,10 +1294,12 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UN static bool gp_convert_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + bGPDlayer *gpl = NULL; bGPDframe *gpf = NULL; ScrArea *sa = CTX_wm_area(C); - Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!), @@ -1305,7 +1307,7 @@ static bool gp_convert_poll(bContext *C) */ return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_getactive(gpd)) && - (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0)) && + (gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0)) && (gpf->strokes.first) && (OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL)); } diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c28fea0fc41..dd1852ca8ce 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -46,18 +46,32 @@ #include "BLT_translation.h" +#include "DNA_anim_types.h" +#include "DNA_brush_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" -#include "DNA_gpencil_types.h" -#include "BKE_colortools.h" +#include "BKE_main.h" +#include "BKE_brush.h" +#include "BKE_animsys.h" #include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_fcurve.h" +#include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_object.h" +#include "BKE_material.h" +#include "BKE_paint.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -72,8 +86,13 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "ED_object.h" #include "ED_gpencil.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + #include "gpencil_intern.h" /* ************************************************ */ @@ -84,9 +103,9 @@ /* add new datablock - wrapper around API */ static int gp_data_add_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - ToolSettings *ts = CTX_data_tool_settings(C); + PointerRNA gpd_owner = {{NULL}}; + bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner); + bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner); if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); @@ -94,19 +113,36 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) } else { /* decrement user count and add new datablock */ - bGPdata *gpd = (*gpd_ptr); + /* TODO: if a datablock exists, we should make a copy of it instead of starting fresh (as in other areas) */ + Main *bmain = CTX_data_main(C); - id_us_min(&gpd->id); - *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil")); + /* decrement user count of old GP datablock */ + if (*gpd_ptr) { + bGPdata *gpd = (*gpd_ptr); + id_us_min(&gpd->id); + } - /* if not exist brushes, create a new set */ - if (ts) { - if (BLI_listbase_is_empty(&ts->gp_brushes)) { - /* create new brushes */ - BKE_gpencil_brush_init_presets(ts); - } + /* add new datablock, with a single layer ready to use (so users don't have to perform an extra step) */ + if (is_annotation) { + bGPdata *gpd = BKE_gpencil_data_addnew(bmain, DATA_("Annotations")); + *gpd_ptr = gpd; + + /* tag for annotations */ + gpd->flag |= GP_DATA_ANNOTATIONS; + + /* add new layer (i.e. a "note") */ + BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true); } + else { + /* GP Object Case - This shouldn't happen! */ + *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil")); + + /* add default sets of colors and brushes */ + ED_gpencil_add_defaults(C); + /* add new layer */ + BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); + } } /* notifiers */ @@ -185,28 +221,42 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) /* add new layer - wrapper around API */ static int gp_layer_add_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - ToolSettings *ts = CTX_data_tool_settings(C); + PointerRNA gpd_owner = {{NULL}}; + bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, &gpd_owner); + bool is_annotation = ED_gpencil_data_owner_is_annotation(&gpd_owner); /* if there's no existing Grease-Pencil data there, add some */ if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); return OPERATOR_CANCELLED; } - if (*gpd_ptr == NULL) - *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil")); - /* if not exist brushes, create a new set */ - if (ts) { - if (BLI_listbase_is_empty(&ts->gp_brushes)) { - /* create new brushes */ - BKE_gpencil_brush_init_presets(ts); + if (*gpd_ptr == NULL) { + Main *bmain = CTX_data_main(C); + if (is_annotation) { + /* Annotations */ + *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("Annotations")); + + /* mark as annotation */ + (*gpd_ptr)->flag |= GP_DATA_ANNOTATIONS; + } + else { + /* GP Object */ + /* NOTE: This shouldn't actually happen in practice */ + *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil")); + + /* add default sets of colors and brushes */ + ED_gpencil_add_defaults(C); } } /* add new layer now */ - BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); + if (is_annotation) { + BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("Note"), true); + } + else { + BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); + } /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); @@ -219,7 +269,7 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot) /* identifiers */ ot->name = "Add New Layer"; ot->idname = "GPENCIL_OT_layer_add"; - ot->description = "Add new Grease Pencil layer for the active Grease Pencil data-block"; + ot->description = "Add new layer or note for the active data-block"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -257,6 +307,7 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op) BKE_gpencil_layer_delete(gpd, gpl); /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -296,6 +347,7 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op) BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */ if (BLI_listbase_link_move(&gpd->layers, gpl, direction)) { + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } @@ -346,6 +398,7 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) BKE_gpencil_layer_setactive(gpd, new_layer); /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -366,6 +419,154 @@ void GPENCIL_OT_layer_duplicate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ********************* Duplicate Frame ************************** */ +enum { + GP_FRAME_DUP_ACTIVE = 0, + GP_FRAME_DUP_ALL = 1 +}; + +static int gp_frame_duplicate_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + + int mode = RNA_enum_get(op->ptr, "mode"); + + /* sanity checks */ + if (ELEM(NULL, gpd, gpl)) + return OPERATOR_CANCELLED; + + if (mode == 0) { + BKE_gpencil_frame_addcopy(gpl, cfra_eval); + } + else { + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if ((gpl->flag & GP_LAYER_LOCKED) == 0) { + BKE_gpencil_frame_addcopy(gpl, cfra_eval); + } + } + + } + /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_frame_duplicate(wmOperatorType *ot) +{ + static const EnumPropertyItem duplicate_mode[] = { + { GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only" }, + { GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers" }, + { 0, NULL, 0, NULL, NULL } + }; + + + /* identifiers */ + ot->name = "Duplicate Frame"; + ot->idname = "GPENCIL_OT_frame_duplicate"; + ot->description = "Make a copy of the active Grease Pencil Frame"; + + /* callbacks */ + ot->exec = gp_frame_duplicate_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", ""); +} + +/* ********************* Clean Fill Boundaries on Frame ************************** */ +enum { + GP_FRAME_CLEAN_FILL_ACTIVE = 0, + GP_FRAME_CLEAN_FILL_ALL = 1 +}; + +static int gp_frame_clean_fill_exec(bContext *C, wmOperator *op) +{ + bool changed = false; + bGPdata *gpd = ED_gpencil_data_get_active(C); + int mode = RNA_enum_get(op->ptr, "mode"); + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *init_gpf = gpl->actframe; + if (mode == GP_FRAME_CLEAN_FILL_ALL) { + init_gpf = gpl->frames.first; + } + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || (mode == GP_FRAME_CLEAN_FILL_ALL)) { + bGPDstroke *gps, *gpsn; + + if (gpf == NULL) + continue; + + /* simply delete strokes which are no fill */ + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + /* free stroke */ + if (gps->flag & GP_STROKE_NOFILL) { + /* free stroke memory arrays, then stroke itself */ + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + MEM_SAFE_FREE(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + + changed = true; + } + } + } + } + } + CTX_DATA_END; + + /* notifiers */ + if (changed) { + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + } + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_frame_clean_fill(wmOperatorType *ot) +{ + static const EnumPropertyItem duplicate_mode[] = { + { GP_FRAME_CLEAN_FILL_ACTIVE, "ACTIVE", 0, "Active Frame Only", "Clean active frame only" }, + { GP_FRAME_CLEAN_FILL_ALL, "ALL", 0, "All Frames", "Clean all frames in all layers" }, + { 0, NULL, 0, NULL, NULL } + }; + + /* identifiers */ + ot->name = "Clean Fill Boundaries"; + ot->idname = "GPENCIL_OT_frame_clean_fill"; + ot->description = "Remove 'no fill' boundary strokes"; + + /* callbacks */ + ot->exec = gp_frame_clean_fill_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", duplicate_mode, GP_FRAME_DUP_ACTIVE, "Mode", ""); +} + /* *********************** Hide Layers ******************************** */ static int gp_hide_exec(bContext *C, wmOperator *op) @@ -394,6 +595,7 @@ static int gp_hide_exec(bContext *C, wmOperator *op) } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -481,6 +683,7 @@ static int gp_reveal_exec(bContext *C, wmOperator *op) } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -521,6 +724,7 @@ static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -558,6 +762,7 @@ static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -630,6 +835,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op) } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -673,22 +879,28 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op) BLI_ghash_insert(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum), gpf); } - /* read all frames from next layer */ + /* read all frames from next layer and add any missing in current layer */ for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) { - /* try to find frame in active layer */ + /* try to find frame in current layer */ bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, SET_INT_IN_POINTER(gpf->framenum)); if (!frame) { - /* nothing found, create new */ + bGPDframe *actframe = BKE_gpencil_layer_getframe(gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV); frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum); + /* duplicate strokes of current active frame */ + if (actframe) { + BKE_gpencil_frame_copy_strokes(actframe, frame); + } } /* add to tail all strokes */ BLI_movelisttolist(&frame->strokes, &gpf->strokes); } + /* Now delete next layer */ BKE_gpencil_layer_delete(gpd, gpl_next); BLI_ghash_free(gh_frames_cur, NULL, NULL); /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -750,6 +962,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op) BKE_gpencil_layer_setactive(gpd, gpl); /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -788,6 +1001,7 @@ enum { static int gp_stroke_arrange_exec(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); bGPDstroke *gps; @@ -797,79 +1011,95 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - bGPDframe *gpf = gpl->actframe; - /* temp listbase to store selected strokes */ - ListBase selected = {NULL}; const int direction = RNA_enum_get(op->ptr, "direction"); - /* verify if any selected stroke is in the extreme of the stack and select to move */ - for (gps = gpf->strokes.first; gps; gps = gps->next) { - /* only if selected */ - if (gps->flag & GP_STROKE_SELECT) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { - continue; - } - /* some stroke is already at front*/ - if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) { - if (gps == gpf->strokes.last) { - return OPERATOR_CANCELLED; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* temp listbase to store selected strokes by layer */ + ListBase selected = { NULL }; + bGPDframe *gpf = gpl->actframe; + if (gpl->flag & GP_LAYER_LOCKED) { + continue; + } + + if (gpf == NULL) { + continue; + } + bool gpf_lock = false; + /* verify if any selected stroke is in the extreme of the stack and select to move */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* only if selected */ + if (gps->flag & GP_STROKE_SELECT) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; } - } - /* some stroke is already at botom */ - if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) { - if (gps == gpf->strokes.first) { - return OPERATOR_CANCELLED; + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + continue; + } + /* some stroke is already at front*/ + if ((direction == GP_STROKE_MOVE_TOP) || (direction == GP_STROKE_MOVE_UP)) { + if (gps == gpf->strokes.last) { + gpf_lock = true; + continue; + } + } + /* some stroke is already at botom */ + if ((direction == GP_STROKE_MOVE_BOTTOM) || (direction == GP_STROKE_MOVE_DOWN)) { + if (gps == gpf->strokes.first) { + gpf_lock = true; + continue; + } + } + /* add to list (if not locked) */ + if (!gpf_lock) { + BLI_addtail(&selected, BLI_genericNodeN(gps)); } } - /* add to list */ - BLI_addtail(&selected, BLI_genericNodeN(gps)); } - } - - /* Now do the movement of the stroke */ - switch (direction) { - /* Bring to Front */ - case GP_STROKE_MOVE_TOP: - for (LinkData *link = selected.first; link; link = link->next) { - gps = link->data; - BLI_remlink(&gpf->strokes, gps); - BLI_addtail(&gpf->strokes, gps); - } - break; - /* Bring Forward */ - case GP_STROKE_MOVE_UP: - for (LinkData *link = selected.last; link; link = link->prev) { - gps = link->data; - BLI_listbase_link_move(&gpf->strokes, gps, 1); - } - break; - /* Send Backward */ - case GP_STROKE_MOVE_DOWN: - for (LinkData *link = selected.first; link; link = link->next) { - gps = link->data; - BLI_listbase_link_move(&gpf->strokes, gps, -1); - } - break; - /* Send to Back */ - case GP_STROKE_MOVE_BOTTOM: - for (LinkData *link = selected.last; link; link = link->prev) { - gps = link->data; - BLI_remlink(&gpf->strokes, gps); - BLI_addhead(&gpf->strokes, gps); + /* Now do the movement of the stroke */ + if (!gpf_lock) { + switch (direction) { + /* Bring to Front */ + case GP_STROKE_MOVE_TOP: + for (LinkData *link = selected.first; link; link = link->next) { + gps = link->data; + BLI_remlink(&gpf->strokes, gps); + BLI_addtail(&gpf->strokes, gps); + } + break; + /* Bring Forward */ + case GP_STROKE_MOVE_UP: + for (LinkData *link = selected.last; link; link = link->prev) { + gps = link->data; + BLI_listbase_link_move(&gpf->strokes, gps, 1); + } + break; + /* Send Backward */ + case GP_STROKE_MOVE_DOWN: + for (LinkData *link = selected.first; link; link = link->next) { + gps = link->data; + BLI_listbase_link_move(&gpf->strokes, gps, -1); + } + break; + /* Send to Back */ + case GP_STROKE_MOVE_BOTTOM: + for (LinkData *link = selected.last; link; link = link->prev) { + gps = link->data; + BLI_remlink(&gpf->strokes, gps); + BLI_addhead(&gpf->strokes, gps); + } + break; + default: + BLI_assert(0); + break; } - break; - default: - BLI_assert(0); - break; + } + BLI_freelistN(&selected); } - BLI_freelistN(&selected); /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -890,58 +1120,70 @@ void GPENCIL_OT_stroke_arrange(wmOperatorType *ot) ot->idname = "GPENCIL_OT_stroke_arrange"; ot->description = "Arrange selected strokes up/down in the drawing order of the active layer"; - /* api callbacks */ + /* callbacks */ ot->exec = gp_stroke_arrange_exec; ot->poll = gp_active_layer_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* properties */ ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_STROKE_MOVE_UP, "Direction", ""); } + /* ******************* Move Stroke to new color ************************** */ static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette; - bGPDpalettecolor *color; + Object *ob = CTX_data_active_object(C); + Material *ma = give_current_material(ob, ob->actcol); + int idx = BKE_object_material_slot_find_index(ob, ma) - 1; /* sanity checks */ if (ELEM(NULL, gpd)) { return OPERATOR_CANCELLED; } - palette = BKE_gpencil_palette_getactive(gpd); - color = BKE_gpencil_palettecolor_getactive(palette); - if (ELEM(NULL, palette, color)) { + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + if (ELEM(NULL, ma)) { return OPERATOR_CANCELLED; } /* loop all strokes */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { - for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { - /* only if selected */ - if (gps->flag & GP_STROKE_SELECT) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) - continue; - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) - continue; + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + if (gpf == NULL) + continue; - /* asign new color (only if different) */ - if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) { - BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname)); - gps->palcolor = color; + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* only if selected */ + if (gps->flag & GP_STROKE_SELECT) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) + continue; + + /* asign new color */ + gps->mat_nr = idx; } } } } } + CTX_DATA_END; + /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -954,9 +1196,12 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot) ot->idname = "GPENCIL_OT_stroke_change_color"; ot->description = "Move selected strokes to active color"; - /* api callbacks */ + /* callbacks */ ot->exec = gp_stroke_change_color_exec; ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ******************* Lock color of non selected Strokes colors ************************** */ @@ -964,19 +1209,21 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot) static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette; + + Object *ob = CTX_data_active_object(C); + + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); /* sanity checks */ if (ELEM(NULL, gpd)) return OPERATOR_CANCELLED; - palette = BKE_gpencil_palette_getactive(gpd); - if (ELEM(NULL, palette)) - return OPERATOR_CANCELLED; - /* first lock all colors */ - for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag |= PC_COLOR_LOCKED; + for (short i = 0; i < *totcol; i++) { + Material *tmp_ma = (*matar)[i]; + tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED; + } /* loop all selected strokes and unlock any color */ @@ -991,14 +1238,14 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) continue; } /* unlock color */ - if (gps->palcolor != NULL) { - gps->palcolor->flag &= ~PC_COLOR_LOCKED; - } + Material *tmp_ma = (*matar)[gps->mat_nr]; + tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; } } } } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -1014,25 +1261,18 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot) /* api callbacks */ ot->exec = gp_stroke_lock_color_exec; ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************ */ /* Drawing Brushes Operators */ -/* ******************* Add New Brush ************************ */ - -/* add new brush - wrapper around API */ -static int gp_brush_add_exec(bContext *C, wmOperator *op) +/* ******************* Brush create presets ************************** */ +static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op)) { - ToolSettings *ts = CTX_data_tool_settings(C); - - /* if there's no existing container */ - if (ts == NULL) { - BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go"); - return OPERATOR_CANCELLED; - } - /* add new brush now */ - BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true); + BKE_brush_gpencil_presets(C); /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); @@ -1040,513 +1280,760 @@ static int gp_brush_add_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GPENCIL_OT_brush_add(wmOperatorType *ot) +void GPENCIL_OT_brush_presets_create(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Brush"; - ot->idname = "GPENCIL_OT_brush_add"; - ot->description = "Add new Grease Pencil drawing brush for the active Grease Pencil data-block"; + ot->name = "Create Preset Brushes"; + ot->idname = "GPENCIL_OT_brush_presets_create"; + ot->description = "Create a set of predefined Grease Pencil drawing brushes"; + /* api callbacks */ + ot->exec = gp_brush_presets_create_exec; + + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* callbacks */ - ot->exec = gp_brush_add_exec; - ot->poll = gp_add_poll; } -/* ******************* Remove Active Brush ************************* */ +/* ***************** Select Brush ************************ */ -static int gp_brush_remove_exec(bContext *C, wmOperator *op) +static int gp_brush_select_exec(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); - bGPDbrush *brush = BKE_gpencil_brush_getactive(ts); - - /* sanity checks */ - if (ELEM(NULL, ts, brush)) - return OPERATOR_CANCELLED; + Main *bmain = CTX_data_main(C); - if (BLI_listbase_count_at_most(&ts->gp_brushes, 2) < 2) { - BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a brush, unable to delete the last one"); + /* if there's no existing container */ + if (ts == NULL) { + BKE_report(op->reports, RPT_ERROR, "Nowhere to go"); return OPERATOR_CANCELLED; } + const int index = RNA_int_get(op->ptr, "index"); - /* make the brush before this the new active brush - * - use the one after if this is the first - * - if this is the only brush, this naturally becomes NULL - */ - if (brush->prev) - BKE_gpencil_brush_setactive(ts, brush->prev); - else - BKE_gpencil_brush_setactive(ts, brush->next); - - /* delete the brush now... */ - BKE_gpencil_brush_delete(ts, brush); + Paint *paint = BKE_brush_get_gpencil_paint(ts); + int i = 0; + for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) { + if (brush->ob_mode == OB_MODE_GPENCIL_PAINT) { + if (i == index) { + BKE_paint_brush_set(paint, brush); - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + i++; + } + } - return OPERATOR_FINISHED; + return OPERATOR_CANCELLED; } -void GPENCIL_OT_brush_remove(wmOperatorType *ot) +void GPENCIL_OT_brush_select(wmOperatorType *ot) { /* identifiers */ - ot->name = "Remove Brush"; - ot->idname = "GPENCIL_OT_brush_remove"; - ot->description = "Remove active Grease Pencil drawing brush"; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->name = "Select Brush"; + ot->idname = "GPENCIL_OT_brush_select"; + ot->description = "Select a Grease Pencil drawing brush"; /* callbacks */ - ot->exec = gp_brush_remove_exec; + ot->exec = gp_brush_select_exec; ot->poll = gp_active_brush_poll; -} - -/* ********************** Change Brush ***************************** */ - -static int gp_brush_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) -{ - uiPopupMenu *pup; - uiLayout *layout; - /* call the menu, which will call this operator again, hence the canceled */ - pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); - layout = UI_popup_menu_layout(pup); - uiItemsEnumO(layout, "GPENCIL_OT_brush_change", "brush"); - UI_popup_menu_end(C, pup); + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - return OPERATOR_INTERFACE; + /* properties */ + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX); } -static int gp_brush_change_exec(bContext *C, wmOperator *op) +/* ***************** Select Sculpt Brush ************************ */ + +static int gp_sculpt_select_exec(bContext *C, wmOperator *op) { ToolSettings *ts = CTX_data_tool_settings(C); - bGPDbrush *brush = NULL; - int brush_num = RNA_enum_get(op->ptr, "brush"); - /* Get brush or create new one */ - if (brush_num == -1) { - /* Create brush */ - brush = BKE_gpencil_brush_addnew(ts, DATA_("GP_Brush"), true); + /* if there's no existing container */ + if (ts == NULL) { + BKE_report(op->reports, RPT_ERROR, "Nowhere to go"); + return OPERATOR_CANCELLED; } - else { - /* Try to get brush */ - brush = BLI_findlink(&ts->gp_brushes, brush_num); - if (brush == NULL) { - BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent brush (index = %d)", brush_num); - return OPERATOR_CANCELLED; - } + const int index = RNA_int_get(op->ptr, "index"); + GP_BrushEdit_Settings *gp_sculpt = &ts->gp_sculpt; + /* sanity checks */ + if (ELEM(NULL, gp_sculpt)) { + return OPERATOR_CANCELLED; } - /* Set active brush */ - BKE_gpencil_brush_setactive(ts, brush); - - /* updates */ + if (index < TOT_GP_EDITBRUSH_TYPES - 1) { + gp_sculpt->brushtype = index; + } + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_brush_change(wmOperatorType *ot) +void GPENCIL_OT_sculpt_select(wmOperatorType *ot) { /* identifiers */ - ot->name = "Change Brush"; - ot->idname = "GPENCIL_OT_brush_change"; - ot->description = "Change active Grease Pencil drawing brush"; + ot->name = "Select Sculpt Brush"; + ot->idname = "GPENCIL_OT_sculpt_select"; + ot->description = "Select a Grease Pencil sculpt brush"; /* callbacks */ - ot->invoke = gp_brush_change_invoke; - ot->exec = gp_brush_change_exec; - ot->poll = gp_active_brush_poll; + ot->exec = gp_sculpt_select_exec; + ot->poll = gp_add_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* gp brush to use (dynamic enum) */ - ot->prop = RNA_def_enum(ot->srna, "brush", DummyRNA_DEFAULT_items, 0, "Grease Pencil Brush", ""); - RNA_def_enum_funcs(ot->prop, ED_gpencil_brushes_enum_itemf); + /* properties */ + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Sculpt Brush", 0, INT_MAX); } -/* ******************* Move Brush Up/Down ************************** */ +/*********************** Vertex Groups ***********************************/ -enum { - GP_BRUSH_MOVE_UP = -1, - GP_BRUSH_MOVE_DOWN = 1 -}; +static bool gpencil_vertex_group_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + + if ((ob) && (ob->type == OB_GPENCIL)) { + if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) { + if (ELEM(ob->mode, + OB_MODE_GPENCIL_EDIT, + OB_MODE_GPENCIL_SCULPT)) + { + return true; + } + } + } -static int gp_brush_move_exec(bContext *C, wmOperator *op) + return false; +} + +static bool gpencil_vertex_group_weight_poll(bContext *C) { - ToolSettings *ts = CTX_data_tool_settings(C); - bGPDbrush *brush = BKE_gpencil_brush_getactive(ts); + Object *ob = CTX_data_active_object(C); - int direction = RNA_enum_get(op->ptr, "type"); + if ((ob) && (ob->type == OB_GPENCIL)) { + if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) { + if (ob->mode == OB_MODE_GPENCIL_WEIGHT) + { + return true; + } + } + } + + return false; +} + +static int gpencil_vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + Object *ob = CTX_data_active_object(C); /* sanity checks */ - if (ELEM(NULL, ts, brush)) { + if (ELEM(NULL, ts, ob, ob->data)) return OPERATOR_CANCELLED; - } - /* up or down? */ - if (direction == GP_BRUSH_MOVE_UP) { - /* up */ - BLI_remlink(&ts->gp_brushes, brush); - BLI_insertlinkbefore(&ts->gp_brushes, brush->prev, brush); - } - else if (direction == GP_BRUSH_MOVE_DOWN) { - /* down */ - BLI_remlink(&ts->gp_brushes, brush); - BLI_insertlinkafter(&ts->gp_brushes, brush->next, brush); - } - else { - BLI_assert(0); - } + ED_gpencil_vgroup_assign(C, ob, ts->vgroup_weight); /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_brush_move(wmOperatorType *ot) +void GPENCIL_OT_vertex_group_assign(wmOperatorType *ot) { - static const EnumPropertyItem slot_move[] = { - {GP_BRUSH_MOVE_UP, "UP", 0, "Up", ""}, - {GP_BRUSH_MOVE_DOWN, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL } - }; - /* identifiers */ - ot->name = "Move Brush"; - ot->idname = "GPENCIL_OT_brush_move"; - ot->description = "Move the active Grease Pencil drawing brush up/down in the list"; + ot->name = "Assign to Vertex Group"; + ot->idname = "GPENCIL_OT_vertex_group_assign"; + ot->description = "Assign the selected vertices to the active vertex group"; /* api callbacks */ - ot->exec = gp_brush_move_exec; - ot->poll = gp_active_brush_poll; + ot->poll = gpencil_vertex_group_poll; + ot->exec = gpencil_vertex_group_assign_exec; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "type", slot_move, GP_BRUSH_MOVE_UP, "Type", ""); } -/* ******************* Brush create presets ************************** */ - -static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op)) +/* remove point from vertex group */ +static int gpencil_vertex_group_remove_from_exec(bContext *C, wmOperator *UNUSED(op)) { - ToolSettings *ts = CTX_data_tool_settings(C); - BKE_gpencil_brush_init_presets(ts); + Object *ob = CTX_data_active_object(C); + + /* sanity checks */ + if (ELEM(NULL, ob, ob->data)) + return OPERATOR_CANCELLED; + + ED_gpencil_vgroup_remove(C, ob); /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_brush_presets_create(wmOperatorType *ot) +void GPENCIL_OT_vertex_group_remove_from(wmOperatorType *ot) { /* identifiers */ - ot->name = "Create Preset Brushes"; - ot->idname = "GPENCIL_OT_brush_presets_create"; - ot->description = "Create a set of predefined Grease Pencil drawing brushes"; + ot->name = "Remove from Vertex Group"; + ot->idname = "GPENCIL_OT_vertex_group_remove_from"; + ot->description = "Remove the selected vertices from active or all vertex group(s)"; /* api callbacks */ - ot->exec = gp_brush_presets_create_exec; + ot->poll = gpencil_vertex_group_poll; + ot->exec = gpencil_vertex_group_remove_from_exec; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ***************** Copy Brush ************************ */ - -static int gp_brush_copy_exec(bContext *C, wmOperator *op) +static int gpencil_vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) { - ToolSettings *ts = CTX_data_tool_settings(C); - - /* if there's no existing container */ - if (ts == NULL) { - BKE_report(op->reports, RPT_ERROR, "Nowhere for brush data to go"); - return OPERATOR_CANCELLED; - } - - bGPDbrush *brush = BKE_gpencil_brush_getactive(ts); - bGPDbrush *newbrush; + Object *ob = CTX_data_active_object(C); /* sanity checks */ - if (ELEM(NULL, brush)) + if (ELEM(NULL, ob, ob->data)) return OPERATOR_CANCELLED; - /* create a brush and duplicate data */ - newbrush = BKE_gpencil_brush_addnew(ts, brush->info, true); - newbrush->thickness = brush->thickness; - newbrush->draw_smoothfac = brush->draw_smoothfac; - newbrush->draw_smoothlvl = brush->draw_smoothlvl; - newbrush->sublevel = brush->sublevel; - newbrush->flag = brush->flag; - newbrush->draw_sensitivity = brush->draw_sensitivity; - newbrush->draw_strength = brush->draw_strength; - newbrush->draw_jitter = brush->draw_jitter; - newbrush->draw_angle = brush->draw_angle; - newbrush->draw_angle_factor = brush->draw_angle_factor; - newbrush->draw_random_press = brush->draw_random_press; - newbrush->draw_random_sub = brush->draw_random_sub; - - /* free automatic curves created by default (replaced by copy) */ - curvemapping_free(newbrush->cur_sensitivity); - curvemapping_free(newbrush->cur_strength); - curvemapping_free(newbrush->cur_jitter); - - /* make a copy of curves */ - newbrush->cur_sensitivity = curvemapping_copy(brush->cur_sensitivity); - newbrush->cur_strength = curvemapping_copy(brush->cur_strength); - newbrush->cur_jitter = curvemapping_copy(brush->cur_jitter); - - BKE_gpencil_brush_setactive(ts, newbrush); + ED_gpencil_vgroup_select(C, ob); + /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_brush_copy(wmOperatorType *ot) +void GPENCIL_OT_vertex_group_select(wmOperatorType *ot) { /* identifiers */ - ot->name = "Copy Brush"; - ot->idname = "GPENCIL_OT_brush_copy"; - ot->description = "Copy current Grease Pencil drawing brush"; + ot->name = "Select Vertex Group"; + ot->idname = "GPENCIL_OT_vertex_group_select"; + ot->description = "Select all the vertices assigned to the active vertex group"; - /* callbacks */ - ot->exec = gp_brush_copy_exec; - ot->poll = gp_active_brush_poll; + /* api callbacks */ + ot->poll = gpencil_vertex_group_poll; + ot->exec = gpencil_vertex_group_select_exec; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ***************** Select Brush ************************ */ - -static int gp_brush_select_exec(bContext *C, wmOperator *op) +static int gpencil_vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) { - ToolSettings *ts = CTX_data_tool_settings(C); - - /* if there's no existing container */ - if (ts == NULL) { - BKE_report(op->reports, RPT_ERROR, "Nowhere to go"); - return OPERATOR_CANCELLED; - } + Object *ob = CTX_data_active_object(C); - const int index = RNA_int_get(op->ptr, "index"); - bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, index); /* sanity checks */ - if (ELEM(NULL, brush)) { + if (ELEM(NULL, ob, ob->data)) return OPERATOR_CANCELLED; - } - BKE_gpencil_brush_setactive(ts, brush); + ED_gpencil_vgroup_deselect(C, ob); /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_brush_select(wmOperatorType *ot) +void GPENCIL_OT_vertex_group_deselect(wmOperatorType *ot) { /* identifiers */ - ot->name = "Select Brush"; - ot->idname = "GPENCIL_OT_brush_select"; - ot->description = "Select a Grease Pencil drawing brush"; + ot->name = "Deselect Vertex Group"; + ot->idname = "GPENCIL_OT_vertex_group_deselect"; + ot->description = "Deselect all selected vertices assigned to the active vertex group"; - /* callbacks */ - ot->exec = gp_brush_select_exec; - ot->poll = gp_active_brush_poll; + /* api callbacks */ + ot->poll = gpencil_vertex_group_poll; + ot->exec = gpencil_vertex_group_deselect_exec; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of Drawing Brush", 0, INT_MAX); } -/* ************************************************ */ -/* Palette Operators */ - -/* ******************* Add New Palette ************************ */ - -/* add new palette - wrapper around API */ -static int gp_palette_add_exec(bContext *C, wmOperator *op) +/* invert */ +static int gpencil_vertex_group_invert_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); + ToolSettings *ts = CTX_data_tool_settings(C); + Object *ob = CTX_data_active_object(C); - /* if there's no existing Grease-Pencil data there, add some */ - if (gpd_ptr == NULL) { - BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); + /* sanity checks */ + if (ELEM(NULL, ts, ob, ob->data)) return OPERATOR_CANCELLED; - } - if (*gpd_ptr == NULL) - *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil")); - /* add new palette now */ - BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true); + MDeformVert *dvert; + const int def_nr = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, def_nr)) + return OPERATOR_CANCELLED; + + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + for (int i = 0; i < gps->totpoints; i++) { + dvert = &gps->dvert[i]; + if (dvert->dw == NULL) { + BKE_gpencil_vgroup_add_point_weight(dvert, def_nr, 1.0f); + } + else if (dvert->dw->weight == 1.0f) { + BKE_gpencil_vgroup_remove_point_weight(dvert, def_nr); + } + else { + dvert->dw->weight = 1.0f - dvert->dw->weight; + } + } + } + CTX_DATA_END; /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_palette_add(wmOperatorType *ot) +void GPENCIL_OT_vertex_group_invert(wmOperatorType *ot) { /* identifiers */ - ot->name = "Add Palette"; - ot->idname = "GPENCIL_OT_palette_add"; - ot->description = "Add new Grease Pencil palette for the active Grease Pencil data-block"; + ot->name = "Invert Vertex Group"; + ot->idname = "GPENCIL_OT_vertex_group_invert"; + ot->description = "Invert weights to the active vertex group"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* api callbacks */ + ot->poll = gpencil_vertex_group_weight_poll; + ot->exec = gpencil_vertex_group_invert_exec; - /* callbacks */ - ot->exec = gp_palette_add_exec; - ot->poll = gp_add_poll; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Remove Active Palette ************************* */ - -static int gp_palette_remove_exec(bContext *C, wmOperator *op) +/* smooth */ +static int gpencil_vertex_group_smooth_exec(bContext *C, wmOperator *op) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); + const float fac = RNA_float_get(op->ptr, "factor"); + const int repeat = RNA_int_get(op->ptr, "repeat"); + + ToolSettings *ts = CTX_data_tool_settings(C); + Object *ob = CTX_data_active_object(C); /* sanity checks */ - if (ELEM(NULL, gpd, palette)) + if (ELEM(NULL, ts, ob, ob->data)) return OPERATOR_CANCELLED; - if (BLI_listbase_count_at_most(&gpd->palettes, 2) < 2) { - BKE_report(op->reports, RPT_ERROR, "Grease Pencil needs a palette, unable to delete the last one"); - return OPERATOR_CANCELLED; - } + bGPDspoint *pta, *ptb, *ptc; + MDeformVert *dverta, *dvertb; + const int def_nr = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, def_nr)) + return OPERATOR_CANCELLED; - /* make the palette before this the new active palette - * - use the one after if this is the first - * - if this is the only palette, this naturally becomes NULL - */ - if (palette->prev) - BKE_gpencil_palette_setactive(gpd, palette->prev); - else - BKE_gpencil_palette_setactive(gpd, palette->next); + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + for (int s = 0; s < repeat; s++) { + for (int i = 0; i < gps->totpoints; i++) { + /* previous point */ + if (i > 0) { + pta = &gps->points[i - 1]; + dverta = &gps->dvert[i - 1]; + } + else { + pta = &gps->points[i]; + dverta = &gps->dvert[i]; + } + /* current */ + ptb = &gps->points[i]; + dvertb = &gps->dvert[i]; + /* next point */ + if (i + 1 < gps->totpoints) { + ptc = &gps->points[i + 1]; + } + else { + ptc = &gps->points[i]; + } - /* delete the palette now... */ - BKE_gpencil_palette_delete(gpd, palette); + float wa = BKE_gpencil_vgroup_use_index(dverta, def_nr); + float wb = BKE_gpencil_vgroup_use_index(dvertb, def_nr); + CLAMP_MIN(wa, 0.0f); + CLAMP_MIN(wb, 0.0f); + + /* the optimal value is the corresponding to the interpolation of the weight + * at the distance of point b + */ + const float opfac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); + const float optimal = interpf(wa, wb, opfac); + /* Based on influence factor, blend between original and optimal */ + wb = interpf(wb, optimal, fac); + BKE_gpencil_vgroup_add_point_weight(dvertb, def_nr, wb); + } + } + } + CTX_DATA_END; /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED | ND_SPACE_PROPERTIES, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_palette_remove(wmOperatorType *ot) +void GPENCIL_OT_vertex_group_smooth(wmOperatorType *ot) { /* identifiers */ - ot->name = "Remove palette"; - ot->idname = "GPENCIL_OT_palette_remove"; - ot->description = "Remove active Grease Pencil palette"; + ot->name = "Smooth Vertex Group"; + ot->idname = "GPENCIL_OT_vertex_group_smooth"; + ot->description = "Smooth weights to the active vertex group"; + + /* api callbacks */ + ot->poll = gpencil_vertex_group_weight_poll; + ot->exec = gpencil_vertex_group_smooth_exec; + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* callbacks */ - ot->exec = gp_palette_remove_exec; - ot->poll = gp_active_palette_poll; + RNA_def_float(ot->srna, "factor", 0.5f, 0.0f, 1.0, "Factor", "", 0.0f, 1.0f); + RNA_def_int(ot->srna, "repeat", 1, 1, 10000, "Iterations", "", 1, 200); } -/* ********************** Change Palette ***************************** */ +/****************************** Join ***********************************/ -static int gp_palette_change_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) +/* userdata for joined_gpencil_fix_animdata_cb() */ +typedef struct tJoinGPencil_AdtFixData { + bGPdata *src_gpd; + bGPdata *tar_gpd; + + GHash *names_map; +} tJoinGPencil_AdtFixData; + +/* Callback to pass to BKE_fcurves_main_cb() for RNA Paths attached to each F-Curve used in the AnimData */ +static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data) { - uiPopupMenu *pup; - uiLayout *layout; + tJoinGPencil_AdtFixData *afd = (tJoinGPencil_AdtFixData *)user_data; + ID *src_id = &afd->src_gpd->id; + ID *dst_id = &afd->tar_gpd->id; - /* call the menu, which will call this operator again, hence the canceled */ - pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); - layout = UI_popup_menu_layout(pup); - uiItemsEnumO(layout, "GPENCIL_OT_palette_change", "palette"); - UI_popup_menu_end(C, pup); + GHashIterator gh_iter; - return OPERATOR_INTERFACE; + /* Fix paths - If this is the target datablock, it will have some "dirty" paths */ + if ((id == src_id) && fcu->rna_path && strstr(fcu->rna_path, "layers[")) { + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + + /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */ + if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) { + fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "layers", + old_name, new_name, 0, 0, false); + + /* we don't want to apply a second remapping on this F-Curve now, + * so stop trying to fix names names + */ + break; + } + } + } + + /* Fix driver targets */ + if (fcu->driver) { + /* Fix driver references to invalid ID's */ + for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) { + /* only change the used targets, since the others will need fixing manually anyway */ + DRIVER_TARGETS_USED_LOOPER(dvar) + { + /* change the ID's used... */ + if (dtar->id == src_id) { + dtar->id = dst_id; + + /* also check on the subtarget... + * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own + * little twists so that we know that it isn't going to clobber the wrong data + */ + if (dtar->rna_path && strstr(dtar->rna_path, "layers[")) { + GHASH_ITER(gh_iter, afd->names_map) { + const char *old_name = BLI_ghashIterator_getKey(&gh_iter); + const char *new_name = BLI_ghashIterator_getValue(&gh_iter); + + /* only remap if changed */ + if (!STREQ(old_name, new_name)) { + if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) { + /* Fix up path */ + dtar->rna_path = BKE_animsys_fix_rna_path_rename(id, dtar->rna_path, "layers", + old_name, new_name, 0, 0, false); + break; /* no need to try any more names for layer path */ + } + } + } + } + } + } + DRIVER_TARGETS_LOOPER_END + } + } } -static int gp_palette_change_exec(bContext *C, wmOperator *op) +/* join objects called from OBJECT_OT_join */ +int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) { - bGPdata *gpd = CTX_data_gpencil_data(C); - bGPDpalette *palette = NULL; - int palette_num = RNA_enum_get(op->ptr, "palette"); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *obact = CTX_data_active_object(C); + bGPdata *gpd_dst = NULL; + bool ok = false; + + /* Ensure we're in right mode and that the active object is correct */ + if (!obact || obact->type != OB_GPENCIL) + return OPERATOR_CANCELLED; - /* Get palette or create new one */ - if (palette_num == -1) { - /* Create palette */ - palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true); + bGPdata *gpd = (bGPdata *)obact->data; + if ((!gpd) || GPENCIL_ANY_MODE(gpd)) { + return OPERATOR_CANCELLED; } - else { - /* Try to get palette */ - palette = BLI_findlink(&gpd->palettes, palette_num); - if (palette == NULL) { - BKE_reportf(op->reports, RPT_ERROR, "Cannot change to non-existent palette (index = %d)", palette_num); - return OPERATOR_CANCELLED; + /* Ensure all rotations are applied before */ + // XXX: Why don't we apply them here instead of warning? + CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) + { + if (base->object->type == OB_GPENCIL) { + if ((base->object->rot[0] != 0) || + (base->object->rot[1] != 0) || + (base->object->rot[2] != 0)) + { + BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects"); + return OPERATOR_CANCELLED; + } } } + CTX_DATA_END; - /* Set active palette */ - BKE_gpencil_palette_setactive(gpd, palette); + CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) + { + if (base->object == obact) { + ok = true; + break; + } + } + CTX_DATA_END; - /* updates */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + /* that way the active object is always selected */ + if (ok == false) { + BKE_report(op->reports, RPT_WARNING, "Active object is not a selected grease pencil"); + return OPERATOR_CANCELLED; + } - return OPERATOR_FINISHED; -} + gpd_dst = obact->data; + Object *ob_dst = obact; + + /* loop and join all data */ + CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) + { + if ((base->object->type == OB_GPENCIL) && (base->object != obact)) { + /* we assume that each datablock is not already used in active object */ + if (obact->data != base->object->data) { + Object *ob_src = base->object; + bGPdata *gpd_src = base->object->data; + + /* Apply all GP modifiers before */ + for (GpencilModifierData *md = base->object->greasepencil_modifiers.first; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + if (mti->bakeModifier) { + mti->bakeModifier(bmain, depsgraph, md, base->object); + } + } -void GPENCIL_OT_palette_change(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Change Palette"; - ot->idname = "GPENCIL_OT_palette_change"; - ot->description = "Change active Grease Pencil palette"; + /* copy vertex groups to the base one's */ + int old_idx = 0; + for (bDeformGroup *dg = base->object->defbase.first; dg; dg = dg->next) { + bDeformGroup *vgroup = MEM_dupallocN(dg); + int idx = BLI_listbase_count(&obact->defbase); + defgroup_unique_name(vgroup, obact); + BLI_addtail(&obact->defbase, vgroup); + /* update vertex groups in strokes in original data */ + for (bGPDlayer *gpl_src = gpd->layers.first; gpl_src; gpl_src = gpl_src->next) { + for (bGPDframe *gpf = gpl_src->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + MDeformVert *dvert; + int i; + for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) { + if ((dvert->dw) && (dvert->dw->def_nr == old_idx)) { + dvert->dw->def_nr = idx; + } + } + } + } + } + old_idx++; + } + if (obact->defbase.first && obact->actdef == 0) + obact->actdef = 1; + + /* add missing materials reading source materials and checking in destination object */ + Material ***matar = give_matarar(ob_src); + short *totcol = give_totcolp(ob_src); + + for (short i = 0; i < *totcol; i++) { + Material *tmp_ma = (*matar)[i]; + if (BKE_object_material_slot_find_index(ob_dst, tmp_ma) == 0) { + BKE_object_material_slot_add(bmain, ob_dst); + assign_material(bmain, ob_dst, tmp_ma, ob_dst->totcol, BKE_MAT_ASSIGN_EXISTING); + } + } - /* callbacks */ - ot->invoke = gp_palette_change_invoke; - ot->exec = gp_palette_change_exec; - ot->poll = gp_active_palette_poll; + /* duplicate bGPDlayers */ + tJoinGPencil_AdtFixData afd = {0}; + afd.src_gpd = gpd_src; + afd.tar_gpd = gpd_dst; + afd.names_map = BLI_ghash_str_new("joined_gp_layers_map"); + + float imat[3][3], bmat[3][3]; + float offset_global[3]; + float offset_local[3]; + + sub_v3_v3v3(offset_global, obact->loc, base->object->obmat[3]); + copy_m3_m4(bmat, obact->obmat); + invert_m3_m3(imat, bmat); + mul_m3_v3(imat, offset_global); + mul_v3_m3v3(offset_local, imat, offset_global); + + + for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { + bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src); + float diff_mat[4][4]; + float inverse_diff_mat[4][4]; + + /* recalculate all stroke points */ + ED_gpencil_parent_location(depsgraph, base->object, gpd_src, gpl_src, diff_mat); + invert_m4_m4(inverse_diff_mat, diff_mat); + + Material *ma_src = NULL; + int idx; + for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + + /* reasign material. Look old material and try to find in dst */ + ma_src = give_current_material(ob_src, gps->mat_nr + 1); + if (ma_src != NULL) { + idx = BKE_object_material_slot_find_index(ob_dst, ma_src); + if (idx > 0) { + gps->mat_nr = idx - 1; + } + else { + gps->mat_nr = 0; + } + } + else { + gps->mat_nr = 0; + } + + bGPDspoint *pt; + int i; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + float mpt[3]; + mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x); + sub_v3_v3(mpt, offset_local); + mul_v3_m4v3(&pt->x, diff_mat, mpt); + } + } + } - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* be sure name is unique in new object */ + BLI_uniquename(&gpd_dst->layers, gpl_new, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_new->info)); + BLI_ghash_insert(afd.names_map, BLI_strdup(gpl_src->info), gpl_new->info); + + /* add to destination datablock */ + BLI_addtail(&gpd_dst->layers, gpl_new); + } + + /* Fix all the animation data */ + BKE_fcurves_main_cb(bmain, joined_gpencil_fix_animdata_cb, &afd); + BLI_ghash_free(afd.names_map, MEM_freeN, NULL); + + /* Only copy over animdata now, after all the remapping has been done, + * so that we don't have to worry about ambiguities re which datablock + * a layer came from! + */ + if (base->object->adt) { + if (obact->adt == NULL) { + /* no animdata, so just use a copy of the whole thing */ + obact->adt = BKE_animdata_copy(bmain, base->object->adt, false, true); + } + else { + /* merge in data - we'll fix the drivers manually */ + BKE_animdata_merge_copy(bmain, &obact->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false); + } + } + + if (gpd_src->adt) { + if (gpd_dst->adt == NULL) { + /* no animdata, so just use a copy of the whole thing */ + gpd_dst->adt = BKE_animdata_copy(bmain, gpd_src->adt, false, true); + } + else { + /* merge in data - we'll fix the drivers manually */ + BKE_animdata_merge_copy(bmain, &gpd_dst->id, &gpd_src->id, ADT_MERGECOPY_KEEP_DST, false); + } + } + } + + /* Free the old object */ + ED_object_base_free_and_unlink(bmain, scene, base->object); + } + } + CTX_DATA_END; + + DEG_relations_tag_update(bmain); /* because we removed object(s) */ - /* gp palette to use (dynamic enum) */ - ot->prop = RNA_def_enum(ot->srna, "palette", DummyRNA_DEFAULT_items, 0, "Grease Pencil Palette", ""); - RNA_def_enum_funcs(ot->prop, ED_gpencil_palettes_enum_itemf); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + + return OPERATOR_FINISHED; } -/* ******************* Lock and hide any color non used in current layer ************************** */ +/* Color Handle operator */ +static bool gpencil_active_color_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + if (ob && ob->data && (ob->type == OB_GPENCIL)) { + short *totcolp = give_totcolp(ob); + return *totcolp > 0; + } + return false; +} -static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) + +/* ******************* Lock and hide any color non used in current layer ************************** */ +static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette; + Object *ob = CTX_data_active_object(C); + MaterialGPencilStyle *gp_style = NULL; /* sanity checks */ if (ELEM(NULL, gpd)) return OPERATOR_CANCELLED; - palette = BKE_gpencil_palette_getactive(gpd); - if (ELEM(NULL, palette)) + /* first lock and hide all colors */ + Material *ma = NULL; + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); + if ((totcol == 0) || (matar == NULL)) return OPERATOR_CANCELLED; - /* first lock and hide all colors */ - for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag |= PC_COLOR_LOCKED; - palcolor->flag |= PC_COLOR_HIDE; + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + gp_style = ma->gp_style; + gp_style->flag |= GP_STYLE_COLOR_LOCKED; + gp_style->flag |= GP_STYLE_COLOR_HIDE; } /* loop all selected strokes and unlock any color used in active layer */ @@ -1558,140 +2045,49 @@ static int gp_palette_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) if (ED_gpencil_stroke_can_use(C, gps) == false) continue; + gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); /* unlock/unhide color if not unlocked before */ - if (gps->palcolor != NULL) { - gps->palcolor->flag &= ~PC_COLOR_LOCKED; - gps->palcolor->flag &= ~PC_COLOR_HIDE; + if (gp_style != NULL) { + gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; + gp_style->flag &= ~GP_STYLE_COLOR_HIDE; } } } } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_palette_lock_layer(wmOperatorType *ot) +void GPENCIL_OT_lock_layer(wmOperatorType *ot) { /* identifiers */ ot->name = "Disable Unused Layer Colors"; - ot->idname = "GPENCIL_OT_palette_lock_layer"; + ot->idname = "GPENCIL_OT_lock_layer"; ot->description = "Lock and hide any color not used in any layer"; /* api callbacks */ - ot->exec = gp_palette_lock_layer_exec; + ot->exec = gpencil_lock_layer_exec; ot->poll = gp_active_layer_poll; } -/* ************************************************ */ -/* Palette Colors Operators */ - -/* ******************* Add New Palette ************************ */ - -/* add new palette - wrapper around API */ -static int gp_palettecolor_add_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - - /* if there's no existing Grease-Pencil data there, add some */ - if (gpd_ptr == NULL) { - BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); - return OPERATOR_CANCELLED; - } - if (*gpd_ptr == NULL) - *gpd_ptr = BKE_gpencil_data_addnew(bmain, DATA_("GPencil")); - - /* verify palette */ - bGPDpalette *palette = BKE_gpencil_palette_getactive(*gpd_ptr); - if (palette == NULL) - palette = BKE_gpencil_palette_addnew(*gpd_ptr, DATA_("GP_Palette"), true); - - /* add new palette color now */ - BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true); - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_palettecolor_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Palette Color"; - ot->idname = "GPENCIL_OT_palettecolor_add"; - ot->description = "Add new Grease Pencil palette color for the active Grease Pencil data-block"; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* callbacks */ - ot->exec = gp_palettecolor_add_exec; - ot->poll = gp_add_poll; -} - -/* ******************* Remove Active Palette color ************************* */ - -static int gp_palettecolor_remove_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *color = BKE_gpencil_palettecolor_getactive(palette); - - /* sanity checks */ - if (ELEM(NULL, gpd, palette, color)) - return OPERATOR_CANCELLED; - - /* make the palette color before this the new active color - * - use the one after if this is the first - * - if this is the only color, this naturally becomes NULL - */ - if (color->prev) - BKE_gpencil_palettecolor_setactive(palette, color->prev); - else - BKE_gpencil_palettecolor_setactive(palette, color->next); - - /* delete the strokes */ - BKE_gpencil_palettecolor_delete_strokes(gpd, color->info); - - /* delete the palette color now... */ - BKE_gpencil_palettecolor_delete(palette, color); - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_palettecolor_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove palette color"; - ot->idname = "GPENCIL_OT_palettecolor_remove"; - ot->description = "Remove active Grease Pencil palette color"; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* callbacks */ - ot->exec = gp_palettecolor_remove_exec; - ot->poll = gp_active_palettecolor_poll; -} - -/* ********************** Isolate palette color **************************** */ +/* ********************** Isolate gpencil_ color **************************** */ -static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op) +static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *active_color = BKE_gpencil_palettecolor_getactive(palette); - bGPDpalettecolor *palcolor; + Object *ob = CTX_data_active_object(C); + Material *active_ma = give_current_material(ob, ob->actcol); + MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol); + MaterialGPencilStyle *gp_style; - int flags = PC_COLOR_LOCKED; + int flags = GP_STYLE_COLOR_LOCKED; bool isolate = false; if (RNA_boolean_get(op->ptr, "affect_visibility")) - flags |= PC_COLOR_HIDE; + flags |= GP_STYLE_COLOR_HIDE; if (ELEM(NULL, gpd, active_color)) { BKE_report(op->reports, RPT_ERROR, "No active color to isolate"); @@ -1699,15 +2095,20 @@ static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op) } /* Test whether to isolate or clear all flags */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { + Material *ma = NULL; + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; /* Skip if this is the active one */ - if (palcolor == active_color) + if (ma == active_ma) continue; /* If the flags aren't set, that means that the color is - * not alone, so we have some colors to isolate still - */ - if ((palcolor->flag & flags) == 0) { + * not alone, so we have some colors to isolate still + */ + gp_style = ma->gp_style; + if ((gp_style->flag & flags) == 0) { isolate = true; break; } @@ -1716,72 +2117,79 @@ static int gp_isolate_palettecolor_exec(bContext *C, wmOperator *op) /* Set/Clear flags as appropriate */ if (isolate) { /* Set flags on all "other" colors */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - if (palcolor == active_color) + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + gp_style = ma->gp_style; + if (gp_style == active_color) continue; else - palcolor->flag |= flags; + gp_style->flag |= flags; } } else { /* Clear flags - Restore everything else */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag &= ~flags; + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + gp_style = ma->gp_style; + gp_style->flag &= ~flags; } } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } -void GPENCIL_OT_palettecolor_isolate(wmOperatorType *ot) +void GPENCIL_OT_color_isolate(wmOperatorType *ot) { /* identifiers */ - ot->name = "Isolate Palette Color"; - ot->idname = "GPENCIL_OT_palettecolor_isolate"; + ot->name = "Isolate Color"; + ot->idname = "GPENCIL_OT_color_isolate"; ot->description = "Toggle whether the active color is the only one that is editable and/or visible"; /* callbacks */ - ot->exec = gp_isolate_palettecolor_exec; - ot->poll = gp_active_palettecolor_poll; + ot->exec = gpencil_color_isolate_exec; + ot->poll = gpencil_active_color_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ RNA_def_boolean(ot->srna, "affect_visibility", false, "Affect Visibility", "In addition to toggling " - "the editability, also affect the visibility"); + "the editability, also affect the visibility"); } -/* *********************** Hide Palette colors ******************************** */ +/* *********************** Hide colors ******************************** */ -static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op) +static int gpencil_color_hide_exec(bContext *C, wmOperator *op) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); + Object *ob = CTX_data_active_object(C); + MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol); bool unselected = RNA_boolean_get(op->ptr, "unselected"); - /* sanity checks */ - if (ELEM(NULL, gpd, palette, palcolor)) + Material *ma = NULL; + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); + if ((totcol == 0) || (matar == NULL)) return OPERATOR_CANCELLED; if (unselected) { - bGPDpalettecolor *color; - /* hide unselected */ - for (color = palette->colors.first; color; color = color->next) { - if (color != palcolor) { - color->flag |= PC_COLOR_HIDE; + MaterialGPencilStyle *color = NULL; + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + color = ma->gp_style; + if (active_color != color) { + color->flag |= GP_STYLE_COLOR_HIDE; } } } else { /* hide selected/active */ - palcolor->flag |= PC_COLOR_HIDE; + active_color->flag |= GP_STYLE_COLOR_HIDE; } /* notifiers */ @@ -1790,18 +2198,18 @@ static int gp_palettecolor_hide_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot) +void GPENCIL_OT_color_hide(wmOperatorType *ot) { /* identifiers */ ot->name = "Hide Color(s)"; - ot->idname = "GPENCIL_OT_palettecolor_hide"; + ot->idname = "GPENCIL_OT_color_hide"; ot->description = "Hide selected/unselected Grease Pencil colors"; /* callbacks */ - ot->exec = gp_palettecolor_hide_exec; - ot->poll = gp_active_palettecolor_poll; /* NOTE: we need an active color to play with */ + ot->exec = gpencil_color_hide_exec; + ot->poll = gpencil_active_color_poll; /* NOTE: we need an active color to play with */ - /* flags */ + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* props */ @@ -1810,25 +2218,23 @@ void GPENCIL_OT_palettecolor_hide(wmOperatorType *ot) /* ********************** Show All Colors ***************************** */ -/* poll callback for showing colors */ -static bool gp_palettecolor_reveal_poll(bContext *C) -{ - return ED_gpencil_data_get_active(C) != NULL; -} - -static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op)) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor; + Object *ob = CTX_data_active_object(C); + Material *ma = NULL; + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); - /* sanity checks */ - if (ELEM(NULL, gpd, palette)) + if ((totcol == 0) || (matar == NULL)) return OPERATOR_CANCELLED; /* make all colors visible */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag &= ~PC_COLOR_HIDE; + MaterialGPencilStyle *gp_style = NULL; + + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + gp_style = ma->gp_style; + gp_style->flag &= ~GP_STYLE_COLOR_HIDE; } /* notifiers */ @@ -1837,36 +2243,41 @@ static int gp_palettecolor_reveal_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void GPENCIL_OT_palettecolor_reveal(wmOperatorType *ot) +void GPENCIL_OT_color_reveal(wmOperatorType *ot) { /* identifiers */ ot->name = "Show All Colors"; - ot->idname = "GPENCIL_OT_palettecolor_reveal"; - ot->description = "Unhide all hidden Grease Pencil palette colors"; + ot->idname = "GPENCIL_OT_color_reveal"; + ot->description = "Unhide all hidden Grease Pencil gpencil_ colors"; /* callbacks */ - ot->exec = gp_palettecolor_reveal_exec; - ot->poll = gp_palettecolor_reveal_poll; + ot->exec = gpencil_color_reveal_exec; + ot->poll = gpencil_active_color_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ***************** Lock/Unlock All Palette colors ************************ */ +/* ***************** Lock/Unlock All colors ************************ */ -static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor; - /* sanity checks */ - if (ELEM(NULL, gpd, palette)) + Object *ob = CTX_data_active_object(C); + Material *ma = NULL; + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); + + if ((totcol == 0) || (matar == NULL)) return OPERATOR_CANCELLED; /* make all layers non-editable */ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag |= PC_COLOR_LOCKED; + MaterialGPencilStyle *gp_style = NULL; + + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + gp_style = ma->gp_style; + gp_style->flag |= GP_STYLE_COLOR_LOCKED; } /* notifiers */ @@ -1875,16 +2286,16 @@ static int gp_palettecolor_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot) +void GPENCIL_OT_color_lock_all(wmOperatorType *ot) { /* identifiers */ ot->name = "Lock All Colors"; - ot->idname = "GPENCIL_OT_palettecolor_lock_all"; + ot->idname = "GPENCIL_OT_color_lock_all"; ot->description = "Lock all Grease Pencil colors to prevent them from being accidentally modified"; /* callbacks */ - ot->exec = gp_palettecolor_lock_all_exec; - ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ + ot->exec = gpencil_color_lock_all_exec; + ot->poll = gpencil_active_color_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1892,19 +2303,23 @@ void GPENCIL_OT_palettecolor_lock_all(wmOperatorType *ot) /* -------------------------- */ -static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor; + Object *ob = CTX_data_active_object(C); + Material *ma = NULL; + Material ***matar = give_matarar(ob); + short *totcol = give_totcolp(ob); - /* sanity checks */ - if (ELEM(NULL, gpd, palette)) + if ((totcol == 0) || (matar == NULL)) return OPERATOR_CANCELLED; /* make all layers editable again*/ - for (palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - palcolor->flag &= ~PC_COLOR_LOCKED; + MaterialGPencilStyle *gp_style = NULL; + + for (short i = 0; i < *totcol; i++) { + ma = (*matar)[i]; + gp_style = ma->gp_style; + gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; } /* notifiers */ @@ -1913,94 +2328,32 @@ static int gp_palettecolor_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void GPENCIL_OT_palettecolor_unlock_all(wmOperatorType *ot) +void GPENCIL_OT_color_unlock_all(wmOperatorType *ot) { /* identifiers */ ot->name = "Unlock All Colors"; - ot->idname = "GPENCIL_OT_palettecolor_unlock_all"; + ot->idname = "GPENCIL_OT_color_unlock_all"; ot->description = "Unlock all Grease Pencil colors so that they can be edited"; /* callbacks */ - ot->exec = gp_palettecolor_unlock_all_exec; - ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ + ot->exec = gpencil_color_unlock_all_exec; + ot->poll = gpencil_active_color_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Move Color Up/Down ************************** */ - -enum { - GP_COLOR_MOVE_UP = -1, - GP_COLOR_MOVE_DOWN = 1 -}; - -static int gp_palettecolor_move_exec(bContext *C, wmOperator *op) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - - int direction = RNA_enum_get(op->ptr, "direction"); - - /* sanity checks */ - if (ELEM(NULL, gpd, palette, palcolor)) - return OPERATOR_CANCELLED; - - /* up or down? */ - if (direction == GP_COLOR_MOVE_UP) { - /* up */ - BLI_remlink(&palette->colors, palcolor); - BLI_insertlinkbefore(&palette->colors, palcolor->prev, palcolor); - } - else if (direction == GP_COLOR_MOVE_DOWN) { - /* down */ - BLI_remlink(&palette->colors, palcolor); - BLI_insertlinkafter(&palette->colors, palcolor->next, palcolor); - } - else { - BLI_assert(0); - } - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_palettecolor_move(wmOperatorType *ot) -{ - static const EnumPropertyItem slot_move[] = { - {GP_COLOR_MOVE_UP, "UP", 0, "Up", ""}, - {GP_COLOR_MOVE_DOWN, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL} - }; - /* identifiers */ - ot->name = "Move Palette color"; - ot->idname = "GPENCIL_OT_palettecolor_move"; - ot->description = "Move the active Grease Pencil palette color up/down in the list"; +/* ***************** Select all strokes using color ************************ */ - /* api callbacks */ - ot->exec = gp_palettecolor_move_exec; - ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - ot->prop = RNA_def_enum(ot->srna, "direction", slot_move, GP_COLOR_MOVE_UP, "Direction", ""); -} - -/* ***************** Select all strokes using Palette color ************************ */ - -static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_color_select_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); + Object *ob = CTX_data_active_object(C); + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, ob->actcol); /* sanity checks */ - if (ELEM(NULL, gpd, palette, palcolor)) + if (ELEM(NULL, gpd, gp_style)) return OPERATOR_CANCELLED; /* read all strokes and select*/ @@ -2013,11 +2366,11 @@ static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op)) if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) continue; /* select */ - if (strcmp(palcolor->info, gps->colorname) == 0) { + if (ob->actcol == gps->mat_nr) { bGPDspoint *pt; int i; @@ -2035,56 +2388,16 @@ static int gp_palettecolor_select_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -void GPENCIL_OT_palettecolor_select(wmOperatorType *ot) +void GPENCIL_OT_color_select(wmOperatorType *ot) { /* identifiers */ ot->name = "Select Color"; - ot->idname = "GPENCIL_OT_palettecolor_select"; + ot->idname = "GPENCIL_OT_color_select"; ot->description = "Select all Grease Pencil strokes using current color"; /* callbacks */ - ot->exec = gp_palettecolor_select_exec; - ot->poll = gp_palettecolor_reveal_poll; /* XXX: could use dedicated poll later */ - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/* ***************** Copy Palette color ************************ */ - -static int gp_palettecolor_copy_exec(bContext *C, wmOperator *UNUSED(op)) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - bGPDpalettecolor *newcolor; - - /* sanity checks */ - if (ELEM(NULL, gpd, palette, palcolor)) - return OPERATOR_CANCELLED; - - /* create a new color and duplicate data */ - newcolor = BKE_gpencil_palettecolor_addnew(palette, palcolor->info, true); - copy_v4_v4(newcolor->color, palcolor->color); - copy_v4_v4(newcolor->fill, palcolor->fill); - newcolor->flag = palcolor->flag; - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_palettecolor_copy(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Copy Color"; - ot->idname = "GPENCIL_OT_palettecolor_copy"; - ot->description = "Copy current Grease Pencil palette color"; - - /* callbacks */ - ot->exec = gp_palettecolor_copy_exec; - ot->poll = gp_active_palettecolor_poll; + ot->exec = gpencil_color_select_exec; + ot->poll = gpencil_active_color_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index ec67b2da161..4264645b52e 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -47,6 +47,7 @@ #include "BLT_translation.h" +#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -54,12 +55,19 @@ #include "DNA_view3d_types.h" #include "DNA_gpencil_types.h" +#include "BKE_main.h" #include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_brush.h" #include "BKE_gpencil.h" +#include "BKE_paint.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_object.h" #include "BKE_report.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "UI_interface.h" #include "UI_resources.h" @@ -80,31 +88,70 @@ #include "ED_space_api.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "gpencil_intern.h" /* ************************************************ */ /* Stroke Edit Mode Management */ - static bool gpencil_editmode_toggle_poll(bContext *C) { + /* if using gpencil object, use this gpd */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + return ob->data != NULL; + } return ED_gpencil_data_get_active(C) != NULL; } -static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) +static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op) { + const int back = RNA_boolean_get(op->ptr, "back"); + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ bGPdata *gpd = ED_gpencil_data_get_active(C); + bool is_object = false; + short mode; + /* if using a gpencil object, use this datablock */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + gpd = ob->data; + is_object = true; + } - if (gpd == NULL) + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active GP data"); return OPERATOR_CANCELLED; + } /* Just toggle editmode flag... */ gpd->flag ^= GP_DATA_STROKE_EDITMODE; /* recalculate parent matrix */ if (gpd->flag & GP_DATA_STROKE_EDITMODE) { - ED_gpencil_reset_layers_parent(gpd); + ED_gpencil_reset_layers_parent(depsgraph, ob, gpd); + } + /* set mode */ + if (gpd->flag & GP_DATA_STROKE_EDITMODE) { + mode = OB_MODE_GPENCIL_EDIT; + } + else { + mode = OB_MODE_OBJECT; } + if (is_object) { + /* try to back previous mode */ + if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_EDITMODE) == 0) && (back == 1)) { + mode = ob->restore_mode; + } + ob->restore_mode = ob->mode; + ob->mode = mode; + } + + /* setup other modes */ + ED_gpencil_setup_modes(C, gpd, mode); + /* set cache as dirty */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); WM_event_add_notifier(C, NC_GPENCIL | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); @@ -114,6 +161,8 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) void GPENCIL_OT_editmode_toggle(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Strokes Edit Mode Toggle"; ot->idname = "GPENCIL_OT_editmode_toggle"; @@ -125,6 +174,259 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + +/* Stroke Paint Mode Management */ + +static bool gpencil_paintmode_toggle_poll(bContext *C) +{ + /* if using gpencil object, use this gpd */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + return ob->data != NULL; + } + return ED_gpencil_data_get_active(C) != NULL; +} + +static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) +{ + const bool back = RNA_boolean_get(op->ptr, "back"); + + bGPdata *gpd = ED_gpencil_data_get_active(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + bool is_object = false; + short mode; + /* if using a gpencil object, use this datablock */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + gpd = ob->data; + is_object = true; + } + + if (gpd == NULL) + return OPERATOR_CANCELLED; + + /* Just toggle paintmode flag... */ + gpd->flag ^= GP_DATA_STROKE_PAINTMODE; + /* set mode */ + if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { + mode = OB_MODE_GPENCIL_PAINT; + } + else { + mode = OB_MODE_OBJECT; + } + + if (is_object) { + /* try to back previous mode */ + if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0) && (back == 1)) { + mode = ob->restore_mode; + } + ob->restore_mode = ob->mode; + ob->mode = mode; + } + + /* be sure we have brushes */ + Paint *paint = BKE_brush_get_gpencil_paint(ts); + /* if not exist, create a new one */ + if (paint->brush == NULL) { + BKE_brush_gpencil_presets(C); + } + + /* setup other modes */ + ED_gpencil_setup_modes(C, gpd, mode); + /* set cache as dirty */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_paintmode_toggle(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Strokes Paint Mode Toggle"; + ot->idname = "GPENCIL_OT_paintmode_toggle"; + ot->description = "Enter/Exit paint mode for Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gpencil_paintmode_toggle_exec; + ot->poll = gpencil_paintmode_toggle_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + +/* Stroke Sculpt Mode Management */ + +static bool gpencil_sculptmode_toggle_poll(bContext *C) +{ + /* if using gpencil object, use this gpd */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + return ob->data != NULL; + } + return ED_gpencil_data_get_active(C) != NULL; +} + +static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) +{ + const bool back = RNA_boolean_get(op->ptr, "back"); + + bGPdata *gpd = ED_gpencil_data_get_active(C); + bool is_object = false; + short mode; + /* if using a gpencil object, use this datablock */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + gpd = ob->data; + is_object = true; + } + + if (gpd == NULL) + return OPERATOR_CANCELLED; + + /* Just toggle sculptmode flag... */ + gpd->flag ^= GP_DATA_STROKE_SCULPTMODE; + /* set mode */ + if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) { + mode = OB_MODE_GPENCIL_SCULPT; + } + else { + mode = OB_MODE_OBJECT; + } + + if (is_object) { + /* try to back previous mode */ + if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) == 0) && (back == 1)) { + mode = ob->restore_mode; + } + ob->restore_mode = ob->mode; + ob->mode = mode; + } + + /* setup other modes */ + ED_gpencil_setup_modes(C, gpd, mode); + /* set cache as dirty */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_sculptmode_toggle(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Strokes Sculpt Mode Toggle"; + ot->idname = "GPENCIL_OT_sculptmode_toggle"; + ot->description = "Enter/Exit sculpt mode for Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gpencil_sculptmode_toggle_exec; + ot->poll = gpencil_sculptmode_toggle_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); +} + +/* Stroke Weight Paint Mode Management */ + +static bool gpencil_weightmode_toggle_poll(bContext *C) +{ + /* if using gpencil object, use this gpd */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + return ob->data != NULL; + } + return ED_gpencil_data_get_active(C) != NULL; +} + +static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op) +{ + const bool back = RNA_boolean_get(op->ptr, "back"); + + bGPdata *gpd = ED_gpencil_data_get_active(C); + bool is_object = false; + short mode; + /* if using a gpencil object, use this datablock */ + Object *ob = CTX_data_active_object(C); + if ((ob) && (ob->type == OB_GPENCIL)) { + gpd = ob->data; + is_object = true; + } + + if (gpd == NULL) + return OPERATOR_CANCELLED; + + /* Just toggle weightmode flag... */ + gpd->flag ^= GP_DATA_STROKE_WEIGHTMODE; + /* set mode */ + if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) { + mode = OB_MODE_GPENCIL_WEIGHT; + } + else { + mode = OB_MODE_OBJECT; + } + + if (is_object) { + /* try to back previous mode */ + if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && (back == 1)) { + mode = ob->restore_mode; + } + ob->restore_mode = ob->mode; + ob->mode = mode; + } + + /* setup other modes */ + ED_gpencil_setup_modes(C, gpd, mode); + /* set cache as dirty */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Strokes Weight Mode Toggle"; + ot->idname = "GPENCIL_OT_weightmode_toggle"; + ot->description = "Enter/Exit weight paint mode for Grease Pencil strokes"; + + /* callbacks */ + ot->exec = gpencil_weightmode_toggle_exec; + ot->poll = gpencil_weightmode_toggle_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + prop = RNA_def_boolean(ot->srna, "back", 0, "Return to Previous Mode", "Return to previous mode"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } /* ************************************************ */ @@ -137,21 +439,30 @@ static bool gp_stroke_edit_poll(bContext *C) return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0; } +/* poll callback to verify edit mode in 3D view only */ +static bool gp_strokes_edit3d_poll(bContext *C) +{ + /* 2 Requirements: + * - 1) Editable GP data + * - 2) 3D View only + */ + return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C)); +} + /* ************ Stroke Hide selection Toggle ************** */ static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { - ToolSettings *ts = CTX_data_tool_settings(C); - - if (ts == NULL) + View3D *v3d = CTX_wm_view3d(C); + if (v3d == NULL) return OPERATOR_CANCELLED; /* Just toggle alpha... */ - if (ts->gp_sculpt.alpha > 0.0f) { - ts->gp_sculpt.alpha = 0.0f; + if (v3d->vertex_opacity > 0.0f) { + v3d->vertex_opacity = 0.0f; } else { - ts->gp_sculpt.alpha = 1.0f; + v3d->vertex_opacity = 1.0f; } WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); @@ -176,6 +487,44 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot) ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; } +/* toggle multi edit strokes support */ +static int gpencil_multiedit_toggle_exec(bContext *C, wmOperator *op) +{ + View3D *v3d = CTX_wm_view3d(C); + const bool lines = RNA_boolean_get(op->ptr, "lines"); + + /* Just toggle value */ + if (lines == 0) { + v3d->flag3 ^= V3D_GP_SHOW_EDIT_LINES; + } + else { + v3d->flag3 ^= V3D_GP_SHOW_MULTIEDIT_LINES; + } + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_multiedit_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Edit Lines Toggle"; + ot->idname = "GPENCIL_OT_multiedit_toggle"; + ot->description = "Enable/disable edit lines support"; + + /* callbacks */ + ot->exec = gpencil_multiedit_toggle_exec; + ot->poll = gp_stroke_edit_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* properties */ + RNA_def_boolean(ot->srna, "toggle_visibility", 0, "Toggle Visibility Only", "Toggle visibility of edit lines only"); +} + /* ************** Duplicate Selected Strokes **************** */ /* Make copies of selected point segments in a selected stroke */ @@ -220,7 +569,7 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co /* make a stupid copy first of the entire stroke (to get the flags too) */ gpsd = MEM_dupallocN(gps); - BLI_strncpy(gpsd->tmp_layerinfo, layername, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */ + BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo)); /* saves original layer name */ /* initialize triangle memory - will be calculated on next redraw */ gpsd->triangles = NULL; @@ -232,6 +581,20 @@ static void gp_duplicate_points(const bGPDstroke *gps, ListBase *new_strokes, co memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len); gpsd->totpoints = len; + if (gps->dvert != NULL) { + gpsd->dvert = MEM_callocN(sizeof(MDeformVert) * len, "gps stroke weights copy"); + memcpy(gpsd->dvert, gps->dvert + start_idx, sizeof(MDeformVert) * len); + + /* Copy weights */ + int e = start_idx; + for (int j = 0; j < gpsd->totpoints; j++) { + MDeformVert *dvert_dst = &gps->dvert[e]; + MDeformVert *dvert_src = &gps->dvert[j]; + dvert_dst->dw = MEM_dupallocN(dvert_src->dw); + e++; + } + } + /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; BLI_addtail(new_strokes, gpsd); @@ -252,6 +615,11 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) { + BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition"); + return OPERATOR_CANCELLED; + } + /* for each visible (and editable) layer's selected strokes, * copy the strokes into a temporary buffer, then append * once all done @@ -279,8 +647,12 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) /* make direct copies of the stroke and its points */ gpsd = MEM_dupallocN(gps); - BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); + BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo)); gpsd->points = MEM_dupallocN(gps->points); + if (gps->dvert != NULL) { + gpsd->dvert = MEM_dupallocN(gps->dvert); + BKE_gpencil_stroke_weights_duplicate(gps, gpsd); + } /* triangle information - will be calculated on next redraw */ gpsd->flag |= GP_STROKE_RECALC_CACHES; @@ -309,6 +681,7 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -342,7 +715,7 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot) /* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */ ListBase gp_strokes_copypastebuf = {NULL, NULL}; -/* Hash for hanging on to all the palette colors used by strokes in the buffer +/* Hash for hanging on to all the colors used by strokes in the buffer * * This is needed to prevent dangling and unsafe pointers when pasting across datablocks, * or after a color used by a stroke in the buffer gets deleted (via user action or undo). @@ -354,11 +727,11 @@ void ED_gpencil_strokes_copybuf_free(void) { bGPDstroke *gps, *gpsn; - /* Free the palettes buffer - * NOTE: This is done before the strokes so that the name ptrs (keys) are still safe + /* Free the colors buffer + * NOTE: This is done before the strokes so that the ptrs are still safe */ if (gp_strokes_copypastebuf_colors) { - BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, MEM_freeN); + BLI_ghash_free(gp_strokes_copypastebuf_colors, NULL, NULL); gp_strokes_copypastebuf_colors = NULL; } @@ -366,8 +739,15 @@ void ED_gpencil_strokes_copybuf_free(void) for (gps = gp_strokes_copypastebuf.first; gps; gps = gpsn) { gpsn = gps->next; - if (gps->points) MEM_freeN(gps->points); - if (gps->triangles) MEM_freeN(gps->triangles); + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + + MEM_SAFE_FREE(gps->triangles); BLI_freelinkN(&gp_strokes_copypastebuf, gps); } @@ -378,38 +758,26 @@ void ED_gpencil_strokes_copybuf_free(void) /* Ensure that destination datablock has all the colours the pasted strokes need * Helper function for copy-pasting strokes */ -GHash *gp_copybuf_validate_colormap(bGPdata *gpd) +GHash *gp_copybuf_validate_colormap(bContext *C) { + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); GHash *new_colors = BLI_ghash_str_new("GPencil Paste Dst Colors"); GHashIterator gh_iter; - /* If there's no active palette yet (i.e. new datablock), add one */ - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - if (palette == NULL) { - palette = BKE_gpencil_palette_addnew(gpd, "Pasted Palette", true); - } - - /* For each color, figure out what to map to... */ + /* For each color, check if exist and add if not */ GHASH_ITER(gh_iter, gp_strokes_copypastebuf_colors) { - bGPDpalettecolor *palcolor; - char *name = BLI_ghashIterator_getKey(&gh_iter); - /* Look for existing color to map to */ - /* XXX: What to do if same name but different color? Behaviour here should depend on a property? */ - palcolor = BKE_gpencil_palettecolor_getbyname(palette, name); - if (palcolor == NULL) { - /* Doesn't Exist - Create new matching color for this palette */ - /* XXX: This still doesn't fix the pasting across file boundaries problem... */ - bGPDpalettecolor *src_color = BLI_ghashIterator_getValue(&gh_iter); + int *key = BLI_ghashIterator_getKey(&gh_iter); + Material *ma = BLI_ghashIterator_getValue(&gh_iter); - palcolor = MEM_dupallocN(src_color); - BLI_addtail(&palette->colors, palcolor); - - BLI_uniquename(&palette->colors, palcolor, DATA_("GP Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info)); + if (BKE_object_material_slot_find_index(ob, ma) == 0) { + BKE_object_material_slot_add(bmain, ob); + assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING); } /* Store this mapping (for use later when pasting) */ - BLI_ghash_insert(new_colors, name, palcolor); + BLI_ghash_insert(new_colors, key, ma); } return new_colors; @@ -420,6 +788,7 @@ GHash *gp_copybuf_validate_colormap(bGPdata *gpd) static int gp_strokes_copy_exec(bContext *C, wmOperator *op) { + Object *ob = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); if (gpd == NULL) { @@ -427,6 +796,11 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) { + BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition"); + return OPERATOR_CANCELLED; + } + /* clear the buffer first */ ED_gpencil_strokes_copybuf_free(); @@ -455,8 +829,12 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) /* make direct copies of the stroke and its points */ gpsd = MEM_dupallocN(gps); - BLI_strncpy(gpsd->tmp_layerinfo, gpl->info, sizeof(gpsd->tmp_layerinfo)); /* saves original layer name */ + BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo)); /* saves original layer name */ gpsd->points = MEM_dupallocN(gps->points); + if (gps->dvert != NULL) { + gpsd->dvert = MEM_dupallocN(gps->dvert); + BKE_gpencil_stroke_weights_duplicate(gps, gpsd); + } /* triangles cache - will be recalculated on next redraw */ gpsd->flag |= GP_STROKE_RECALC_CACHES; @@ -476,17 +854,16 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - /* Build up hash of colors used in these strokes, making copies of these to protect against dangling pointers */ + /* Build up hash of material colors used in these strokes */ if (gp_strokes_copypastebuf.first) { gp_strokes_copypastebuf_colors = BLI_ghash_str_new("GPencil CopyBuf Colors"); - + Material *ma = NULL; for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { - if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, gps->colorname) == false) { - bGPDpalettecolor *color = MEM_dupallocN(gps->palcolor); - - BLI_ghash_insert(gp_strokes_copypastebuf_colors, gps->colorname, color); - gps->palcolor = color; + ma = give_current_material(ob, gps->mat_nr + 1); + if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, &gps->mat_nr) == false) + { + BLI_ghash_insert(gp_strokes_copypastebuf_colors, &gps->mat_nr, ma); } } } @@ -534,9 +911,11 @@ typedef enum eGP_PasteMode { static int gp_strokes_paste_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); bGPDframe *gpf; eGP_PasteMode type = RNA_enum_get(op->ptr, "type"); @@ -547,6 +926,10 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); return OPERATOR_CANCELLED; } + else if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) { + BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition"); + return OPERATOR_CANCELLED; + } else if (BLI_listbase_is_empty(&gp_strokes_copypastebuf)) { BKE_report(op->reports, RPT_ERROR, "No strokes to paste, select and copy some points before trying again"); return OPERATOR_CANCELLED; @@ -599,14 +982,14 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* Ensure that all the necessary colors exist */ - new_colors = gp_copybuf_validate_colormap(gpd); + new_colors = gp_copybuf_validate_colormap(C); /* Copy over the strokes from the buffer (and adjust the colors) */ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { /* Need to verify if layer exists */ if (type != GP_COPY_MERGE) { - gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info)); + gpl = BLI_findstring(&gpd->layers, gps->runtime.tmp_layerinfo, offsetof(bGPDlayer, info)); if (gpl == NULL) { /* no layer - use active (only if layer deleted before paste) */ gpl = CTX_data_active_gpencil_layer(C); @@ -618,28 +1001,33 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) * we are obliged to add a new frame if one * doesn't exist already */ - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); + gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, true); if (gpf) { /* Create new stroke */ bGPDstroke *new_stroke = MEM_dupallocN(gps); - new_stroke->tmp_layerinfo[0] = '\0'; + new_stroke->runtime.tmp_layerinfo[0] = '\0'; new_stroke->points = MEM_dupallocN(gps->points); - + if (gps->dvert != NULL) { + new_stroke->dvert = MEM_dupallocN(gps->dvert); + BKE_gpencil_stroke_weights_duplicate(gps, new_stroke); + } new_stroke->flag |= GP_STROKE_RECALC_CACHES; new_stroke->triangles = NULL; new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); - /* Fix color references */ - BLI_assert(new_stroke->colorname[0] != '\0'); - new_stroke->palcolor = BLI_ghash_lookup(new_colors, new_stroke->colorname); - - BLI_assert(new_stroke->palcolor != NULL); - BLI_strncpy(new_stroke->colorname, new_stroke->palcolor->info, sizeof(new_stroke->colorname)); + /* Remap material */ + Material *ma = BLI_ghash_lookup(new_colors, &new_stroke->mat_nr); + if ((ma) && (BKE_object_material_slot_find_index(ob, ma) > 0)) { + gps->mat_nr = BKE_object_material_slot_find_index(ob, ma) - 1; + CLAMP_MIN(gps->mat_nr, 0); + } + else { + gps->mat_nr = 0; /* only if the color is not found */ + } - /*new_stroke->flag |= GP_STROKE_RECALC_COLOR; */ } } } @@ -648,6 +1036,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) BLI_ghash_free(new_colors, NULL, NULL); /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -697,10 +1086,17 @@ static int gp_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *U static int gp_move_to_layer_exec(bContext *C, wmOperator *op) { bGPdata *gpd = CTX_data_gpencil_data(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); bGPDlayer *target_layer = NULL; ListBase strokes = {NULL, NULL}; int layer_num = RNA_enum_get(op->ptr, "layer"); + if (GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)) { + BKE_report(op->reports, RPT_ERROR, "Operator not supported in multiframe edition"); + return OPERATOR_CANCELLED; + } + /* Get layer or create new one */ if (layer_num == -1) { /* Create layer */ @@ -748,14 +1144,14 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op) /* Paste them all in one go */ if (strokes.first) { - Scene *scene = CTX_data_scene(C); - bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, true); + bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, cfra_eval, true); BLI_movelisttolist(&gpf->strokes, &strokes); BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL)); } /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -804,8 +1200,10 @@ static bool UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C) static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); bGPdata *gpd = ED_gpencil_data_get_active(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd); const bool all_layers = RNA_boolean_get(op->ptr, "all_layers"); @@ -826,7 +1224,7 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) } /* 1) Check for an existing frame on the current frame */ - bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, CFRA); + bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, cfra_eval); if (gpf) { /* Shunt all frames after (and including) the existing one later by 1-frame */ for (; gpf; gpf = gpf->next) { @@ -835,11 +1233,12 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) } /* 2) Now add a new frame, with nothing in it */ - gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); + gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW); } CTX_DATA_END; /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -876,10 +1275,13 @@ static bool gp_actframe_delete_poll(bContext *C) /* delete active frame - wrapper around API calls */ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); + + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); /* if there's no existing Grease-Pencil data there, add some */ if (gpd == NULL) { @@ -895,6 +1297,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) BKE_gpencil_layer_delframe(gpl, gpf); /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -928,13 +1331,16 @@ static bool gp_actframe_delete_all_poll(bContext *C) static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + bool success = false; CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { /* try to get the "active" frame - but only if it actually occurs on this frame */ - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); if (gpf == NULL) continue; @@ -949,6 +1355,7 @@ static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) /* updates */ if (success) { + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -983,43 +1390,69 @@ typedef enum eGP_DeleteMode { GP_DELETEOP_FRAME = 2, } eGP_DeleteMode; +typedef enum eGP_DissolveMode { + /* dissolve all selected points */ + GP_DISSOLVE_POINTS = 0, + /* dissolve between selected points */ + GP_DISSOLVE_BETWEEN = 1, + /* dissolve unselected points */ + GP_DISSOLVE_UNSELECT = 2, +} eGP_DissolveMode; + /* ----------------------------------- */ /* Delete selected strokes */ static int gp_delete_selected_strokes(bContext *C) { bool changed = false; + bGPdata *gpd = ED_gpencil_data_get_active(C); + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = gpl->actframe; - bGPDstroke *gps, *gpsn; + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } - if (gpf == NULL) - continue; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + bGPDstroke *gps, *gpsn; - /* simply delete strokes which are selected */ - for (gps = gpf->strokes.first; gps; gps = gpsn) { - gpsn = gps->next; + if (gpf == NULL) + continue; - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) - continue; + /* simply delete strokes which are selected */ + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; - /* free stroke if selected */ - if (gps->flag & GP_STROKE_SELECT) { - /* free stroke memory arrays, then stroke itself */ - if (gps->points) MEM_freeN(gps->points); - if (gps->triangles) MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + /* free stroke if selected */ + if (gps->flag & GP_STROKE_SELECT) { + /* free stroke memory arrays, then stroke itself */ + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + MEM_SAFE_FREE(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); - changed = true; + changed = true; + } + } } } } CTX_DATA_END; if (changed) { + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1031,88 +1464,238 @@ static int gp_delete_selected_strokes(bContext *C) /* ----------------------------------- */ /* Delete selected points but keep the stroke */ -static int gp_dissolve_selected_points(bContext *C) +static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode) { + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); bool changed = false; + int first = 0; + int last = 0; CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = gpl->actframe; - bGPDstroke *gps, *gpsn; + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } - if (gpf == NULL) - continue; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { - /* simply delete points from selected strokes - * NOTE: we may still have to remove the stroke if it ends up having no points! - */ - for (gps = gpf->strokes.first; gps; gps = gpsn) { - gpsn = gps->next; + bGPDstroke *gps, *gpsn; - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) - continue; - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) - continue; + if (gpf == NULL) + continue; - if (gps->flag & GP_STROKE_SELECT) { - bGPDspoint *pt; - int i; + /* simply delete points from selected strokes + * NOTE: we may still have to remove the stroke if it ends up having no points! + */ + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) + continue; + + /* the stroke must have at least one point selected for any operator */ + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + MDeformVert *dvert = NULL; + int i; + + int tot = gps->totpoints; /* number of points in new buffer */ + + /* first pass: count points to remove */ + switch (mode) { + case GP_DISSOLVE_POINTS: + /* Count how many points are selected (i.e. how many to remove) */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + /* selected point - one of the points to remove */ + tot--; + } + } + break; + case GP_DISSOLVE_BETWEEN: + /* need to find first and last point selected */ + first = -1; + last = 0; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + if (first < 0) { + first = i; + } + last = i; + } + } + /* count unselected points in the range */ + for (i = first, pt = gps->points + first; i < last; i++, pt++) { + if ((pt->flag & GP_SPOINT_SELECT) == 0) { + tot--; + } + } + break; + case GP_DISSOLVE_UNSELECT: + /* count number of unselected points */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if ((pt->flag & GP_SPOINT_SELECT) == 0) { + tot--; + } + } + break; + default: + return false; + break; + } - int tot = gps->totpoints; /* number of points in new buffer */ + /* if no points are left, we simply delete the entire stroke */ + if (tot <= 0) { + /* remove the entire stroke */ + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + if (gps->triangles) { + MEM_freeN(gps->triangles); + } + BLI_freelinkN(&gpf->strokes, gps); + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + } + else { + /* just copy all points to keep into a smaller buffer */ + bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy"); + bGPDspoint *npt = new_points; - /* First Pass: Count how many points are selected (i.e. how many to remove) */ - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->flag & GP_SPOINT_SELECT) { - /* selected point - one of the points to remove */ - tot--; - } - } + MDeformVert *new_dvert = NULL; + MDeformVert *ndvert = NULL; - /* if no points are left, we simply delete the entire stroke */ - if (tot <= 0) { - /* remove the entire stroke */ - MEM_freeN(gps->points); - if (gps->triangles) { - MEM_freeN(gps->triangles); - } - BLI_freelinkN(&gpf->strokes, gps); - } - else { - /* just copy all unselected into a smaller buffer */ - bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy"); - bGPDspoint *npt = new_points; + if (gps->dvert != NULL) { + new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy"); + ndvert = new_dvert; + } - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) == 0) { - *npt = *pt; - npt++; - } - } + switch (mode) { + case GP_DISSOLVE_POINTS: + (gps->dvert != NULL) ? dvert = gps->dvert : NULL; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if ((pt->flag & GP_SPOINT_SELECT) == 0) { + *npt = *pt; + npt++; + + if (gps->dvert != NULL) { + *ndvert = *dvert; + ndvert->dw = MEM_dupallocN(dvert->dw); + ndvert++; + dvert++; + } + } + } + break; + case GP_DISSOLVE_BETWEEN: + /* copy first segment */ + (gps->dvert != NULL) ? dvert = gps->dvert : NULL; + for (i = 0, pt = gps->points; i < first; i++, pt++) { + *npt = *pt; + npt++; + + if (gps->dvert != NULL) { + *ndvert = *dvert; + ndvert->dw = MEM_dupallocN(dvert->dw); + ndvert++; + dvert++; + } + } + /* copy segment (selected points) */ + (gps->dvert != NULL) ? dvert = gps->dvert + first : NULL; + for (i = first, pt = gps->points + first; i < last; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + *npt = *pt; + npt++; + + if (gps->dvert != NULL) { + *ndvert = *dvert; + ndvert->dw = MEM_dupallocN(dvert->dw); + ndvert++; + dvert++; + } + } + } + /* copy last segment */ + (gps->dvert != NULL) ? dvert = gps->dvert + last : NULL; + for (i = last, pt = gps->points + last; i < gps->totpoints; i++, pt++) { + *npt = *pt; + npt++; + + if (gps->dvert != NULL) { + *ndvert = *dvert; + ndvert->dw = MEM_dupallocN(dvert->dw); + ndvert++; + dvert++; + } + } + + break; + case GP_DISSOLVE_UNSELECT: + /* copy any selected point */ + (gps->dvert != NULL) ? dvert = gps->dvert : NULL; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) { + *npt = *pt; + npt++; + + if (gps->dvert != NULL) { + *ndvert = *dvert; + ndvert->dw = MEM_dupallocN(dvert->dw); + ndvert++; + dvert++; + } + } + } + break; + } - /* free the old buffer */ - MEM_freeN(gps->points); + /* free the old buffer */ + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } - /* save the new buffer */ - gps->points = new_points; - gps->totpoints = tot; + /* save the new buffer */ + gps->points = new_points; + gps->dvert = new_dvert; + gps->totpoints = tot; - /* triangles cache needs to be recalculated */ - gps->flag |= GP_STROKE_RECALC_CACHES; - gps->tot_triangles = 0; + /* triangles cache needs to be recalculated */ + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; - /* deselect the stroke, since none of its selected points will still be selected */ - gps->flag &= ~GP_STROKE_SELECT; - } + /* deselect the stroke, since none of its selected points will still be selected */ + gps->flag &= ~GP_STROKE_SELECT; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + pt->flag &= ~GP_SPOINT_SELECT; + } + } - changed = true; + changed = true; + } + } } } } CTX_DATA_END; if (changed) { + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1146,17 +1729,17 @@ typedef struct tGPDeleteIsland { * becomes much less * 2) Each island gets converted to a new stroke */ -void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags) +void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, + int tag_flags, bool select) { tGPDeleteIsland *islands = MEM_callocN(sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); bool in_island = false; int num_islands = 0; - bGPDspoint *pt; - int i; /* First Pass: Identify start/end of islands */ - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + bGPDspoint *pt = gps->points; + for (int i = 0; i < gps->totpoints; i++, pt++) { if (pt->flag & tag_flags) { /* selected - stop accumulating to island */ in_island = false; @@ -1198,11 +1781,26 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */ new_stroke->totpoints = island->end_idx - island->start_idx + 1; - new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment"); - /* Copy over the relevant points */ + /* Copy over the relevant point data */ + new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment"); memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints); - + + /* Copy over vertex weight data (if available) */ + if (new_stroke->dvert != NULL) { + /* Copy over the relevant vertex-weight points */ + new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, "gp delete stroke fragment weight"); + memcpy(new_stroke->dvert, gps->dvert + island->start_idx, sizeof(MDeformVert) * new_stroke->totpoints); + + /* Copy weights */ + int e = island->start_idx; + for (int i = 0; i < new_stroke->totpoints; i++) { + MDeformVert *dvert_dst = &gps->dvert[e]; + MDeformVert *dvert_src = &new_stroke->dvert[i]; + dvert_dst->dw = MEM_dupallocN(dvert_src->dw); + e++; + } + } /* Each island corresponds to a new stroke. We must adjust the * timings of these new strokes: @@ -1222,6 +1820,11 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke pts = new_stroke->points; for (j = 0; j < new_stroke->totpoints; j++, pts++) { pts->time -= delta; + /* set flag for select again later */ + if (select == true) { + pts->flag &= ~GP_SPOINT_SELECT; + pts->flag |= GP_SPOINT_TAG; + } } } @@ -1239,53 +1842,70 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke MEM_freeN(islands); /* Delete the old stroke */ - MEM_freeN(gps->points); + if (gps->points) { + MEM_freeN(gps->points); + } + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } if (gps->triangles) { MEM_freeN(gps->triangles); } BLI_freelinkN(&gpf->strokes, gps); } - /* Split selected strokes into segments, splitting on selected points */ static int gp_delete_selected_points(bContext *C) { + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); bool changed = false; CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = gpl->actframe; - bGPDstroke *gps, *gpsn; + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } - if (gpf == NULL) - continue; + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + bGPDstroke *gps, *gpsn; - /* simply delete strokes which are selected */ - for (gps = gpf->strokes.first; gps; gps = gpsn) { - gpsn = gps->next; + if (gpf == NULL) + continue; - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) - continue; - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) - continue; + /* simply delete strokes which are selected */ + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) + continue; - if (gps->flag & GP_STROKE_SELECT) { - /* deselect old stroke, since it will be used as template for the new strokes */ - gps->flag &= ~GP_STROKE_SELECT; - /* delete unwanted points by splitting stroke into several smaller ones */ - gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT); + if (gps->flag & GP_STROKE_SELECT) { + /* deselect old stroke, since it will be used as template for the new strokes */ + gps->flag &= ~GP_STROKE_SELECT; + + /* delete unwanted points by splitting stroke into several smaller ones */ + gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false); - changed = true; + changed = true; + } + } } } } CTX_DATA_END; if (changed) { + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1294,6 +1914,12 @@ static int gp_delete_selected_points(bContext *C) } } +/* simple wrapper to external call */ +int gp_delete_selected_point_wrap(bContext *C) +{ + return gp_delete_selected_points(C); +} + /* ----------------------------------- */ static int gp_delete_exec(bContext *C, wmOperator *op) @@ -1344,24 +1970,37 @@ void GPENCIL_OT_delete(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_delete_types, 0, "Type", "Method used for deleting Grease Pencil data"); } -static int gp_dissolve_exec(bContext *C, wmOperator *UNUSED(op)) +static int gp_dissolve_exec(bContext *C, wmOperator *op) { - return gp_dissolve_selected_points(C); + eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type"); + + return gp_dissolve_selected_points(C, mode); } void GPENCIL_OT_dissolve(wmOperatorType *ot) { + static EnumPropertyItem prop_gpencil_dissolve_types[] = { + { GP_DISSOLVE_POINTS, "POINTS", 0, "Dissolve", "Dissolve selected points" }, + { GP_DISSOLVE_BETWEEN, "BETWEEN", 0, "Dissolve Between", "Dissolve points between selected points" }, + { GP_DISSOLVE_UNSELECT, "UNSELECT", 0, "Dissolve Unselect", "Dissolve all unselected points" }, + { 0, NULL, 0, NULL, NULL } + }; + /* identifiers */ ot->name = "Dissolve"; ot->idname = "GPENCIL_OT_dissolve"; ot->description = "Delete selected points without splitting strokes"; /* callbacks */ + ot->invoke = WM_menu_invoke; ot->exec = gp_dissolve_exec; ot->poll = gp_stroke_edit_poll; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; + + /* props */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_gpencil_dissolve_types, 0, "Type", "Method used for disolving Stroke points"); } /* ****************** Snapping - Strokes <-> Cursor ************************ */ @@ -1384,6 +2023,8 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); RegionView3D *rv3d = CTX_wm_region_data(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ + Object *obact = CTX_data_active_object(C); const float gridf = rv3d->gridview; for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { @@ -1392,10 +2033,8 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - } + /* calculate difference matrix object */ + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt; @@ -1405,37 +2044,32 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) + if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) continue; // TODO: if entire stroke is selected, offset entire stroke by same amount? for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { /* only if point is selected */ if (pt->flag & GP_SPOINT_SELECT) { - if (gpl->parent == NULL) { - pt->x = gridf * floorf(0.5f + pt->x / gridf); - pt->y = gridf * floorf(0.5f + pt->y / gridf); - pt->z = gridf * floorf(0.5f + pt->z / gridf); - } - else { - /* apply parent transformations */ - float fpt[3]; - mul_v3_m4v3(fpt, diff_mat, &pt->x); + /* apply parent transformations */ + float fpt[3]; + mul_v3_m4v3(fpt, diff_mat, &pt->x); - fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf); - fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf); - fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf); + fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf); + fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf); + fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf); - /* return data */ - copy_v3_v3(&pt->x, fpt); - gp_apply_parent_point(gpl, pt); - } + /* return data */ + copy_v3_v3(&pt->x, fpt); + gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt); } } } } } + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1463,6 +2097,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ + Object *obact = CTX_data_active_object(C); \ const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d)->location; @@ -1473,10 +2109,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - } + /* calculate difference matrix */ + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt; @@ -1486,7 +2120,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) + if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) continue; /* only continue if this stroke is selected (editable doesn't guarantee this)... */ if ((gps->flag & GP_STROKE_SELECT) == 0) @@ -1509,9 +2143,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { copy_v3_v3(&pt->x, cursor_global); - if (gpl->parent != NULL) { - gp_apply_parent_point(gpl, pt); - } + gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt); } } } @@ -1520,6 +2152,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) } } + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -1551,6 +2185,8 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ + Object *obact = CTX_data_active_object(C); \ float *cursor = ED_view3d_cursor3d_get(scene, v3d)->location; float centroid[3] = {0.0f}; @@ -1566,10 +2202,8 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - } + /* calculate difference matrix */ + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { bGPDspoint *pt; @@ -1579,7 +2213,7 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) if (ED_gpencil_stroke_can_use(C, gps) == false) continue; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) + if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) continue; /* only continue if this stroke is selected (editable doesn't guarantee this)... */ if ((gps->flag & GP_STROKE_SELECT) == 0) @@ -1587,18 +2221,13 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { - if (gpl->parent == NULL) { - add_v3_v3(centroid, &pt->x); - minmax_v3v3_v3(min, max, &pt->x); - } - else { - /* apply parent transformations */ - float fpt[3]; - mul_v3_m4v3(fpt, diff_mat, &pt->x); + /* apply parent transformations */ + float fpt[3]; + mul_v3_m4v3(fpt, diff_mat, &pt->x); add_v3_v3(centroid, fpt); - minmax_v3v3_v3(min, max, fpt); - } + minmax_v3v3_v3(min, max, fpt); + count++; } } @@ -1616,7 +2245,9 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) } - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d); + return OPERATOR_FINISHED; } @@ -1650,13 +2281,20 @@ static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { /* Apply thickness */ - gps->thickness = gps->thickness + gpl->thickness; + if ((gps->thickness == 0) && (gpl->line_change == 0)) { + gps->thickness = gpl->thickness; + } + else { + gps->thickness = gps->thickness + gpl->line_change; + } } } /* clear value */ gpl->thickness = 0.0f; + gpl->line_change = 0; /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -1685,6 +2323,8 @@ enum { static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); + Object *ob = CTX_data_active_object(C); + const int type = RNA_enum_get(op->ptr, "type"); /* sanity checks */ @@ -1698,13 +2338,13 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) continue; for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { - bGPDpalettecolor *palcolor = gps->palcolor; + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); /* skip strokes that are not selected or invalid for current view */ if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) continue; /* skip hidden or locked colors */ - if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED)) + if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || (gp_style->flag & GP_STYLE_COLOR_LOCKED)) continue; switch (type) { @@ -1729,6 +2369,7 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -1809,15 +2450,24 @@ static void gpencil_flip_stroke(bGPDstroke *gps) } /* Helper: copy point between strokes */ -static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3], +static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, int idx, float delta[3], float pressure, float strength, float deltatime) { bGPDspoint *newpoint; + MDeformVert *dvert, *newdvert; gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); + if (gps->dvert != NULL) { + gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1)); + } gps->totpoints++; - newpoint = &gps->points[gps->totpoints - 1]; + + if (gps->dvert != NULL) { + dvert = &gps->dvert[idx]; + newdvert = &gps->dvert[gps->totpoints - 1]; + } + newpoint->x = point->x * delta[0]; newpoint->y = point->y * delta[1]; newpoint->z = point->z * delta[2]; @@ -1825,6 +2475,9 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float newpoint->pressure = pressure; newpoint->strength = strength; newpoint->time = point->time + deltatime; + + newdvert->totweight = dvert->totweight; + newdvert->dw = MEM_dupallocN(dvert->dw); } /* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */ @@ -1870,18 +2523,18 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, co /* 1st: add one tail point to start invisible area */ point = gps_a->points[gps_a->totpoints - 1]; deltatime = point.time; - gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f); + gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f); /* 2nd: add one head point to finish invisible area */ point = gps_b->points[0]; - gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime); + gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime); } /* 3rd: add all points */ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { /* check if still room in buffer */ if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) { - gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime); + gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime); } } } @@ -1891,8 +2544,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd); bGPDstroke *gps, *gpsn; - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); + Object *ob = CTX_data_active_object(C); bGPDframe *gpf_a = NULL; bGPDstroke *stroke_a = NULL; @@ -1928,7 +2580,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { continue; } @@ -1948,15 +2600,17 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) if (new_stroke == NULL) { new_stroke = MEM_dupallocN(stroke_a); new_stroke->points = MEM_dupallocN(stroke_a->points); + if (stroke_a->dvert != NULL) { + new_stroke->dvert = MEM_dupallocN(stroke_a->dvert); + BKE_gpencil_stroke_weights_duplicate(stroke_a, new_stroke); + } new_stroke->triangles = NULL; new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; /* if new, set current color */ if (type == GP_STROKE_JOINCOPY) { - new_stroke->palcolor = palcolor; - BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname)); - new_stroke->flag |= GP_STROKE_RECALC_COLOR; + new_stroke->mat_nr = stroke_a->mat_nr; } } @@ -1995,6 +2649,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -2030,6 +2685,7 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot) static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); + Object *ob = CTX_data_active_object(C); /* sanity checks */ if (ELEM(NULL, gpd)) @@ -2049,7 +2705,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { continue; } @@ -2061,6 +2717,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) CTX_DATA_END; /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -2084,33 +2741,42 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) /* ***************** Reproject Strokes ********************** */ typedef enum eGP_ReprojectModes { + /* Axis (equal to lock axis) */ + GP_REPROJECT_AXIS = 0, /* On same plane, parallel to viewplane */ - GP_REPROJECT_PLANAR = 0, + GP_REPROJECT_PLANAR, /* Reprojected on to the scene geometry */ GP_REPROJECT_SURFACE, } eGP_ReprojectModes; -static bool gp_strokes_reproject_poll(bContext *C) -{ - /* 2 Requirements: - * - 1) Editable GP data - * - 2) 3D View only (2D editors don't have projection issues) - */ - return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C)); -} - static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) { + bGPdata *gpd = ED_gpencil_data_get_active(C); Scene *scene = CTX_data_scene(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob = CTX_data_active_object(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + RegionView3D *rv3d = ar->regiondata; + View3D *v3d = sa->spacedata.first; + GP_SpaceConversion gsc = {NULL}; - eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type"); + eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type"); + + int lock_axis = ts->gp_sculpt.lock_axis; + float origin[3]; + + if ((mode == GP_REPROJECT_AXIS) && (lock_axis == GP_LOCKAXIS_NONE)) { + BKE_report(op->reports, RPT_ERROR, "To reproject by axis, a lock axis must be set before"); + return OPERATOR_CANCELLED; + } /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); /* init autodist for geometry projection */ if (mode == GP_REPROJECT_SURFACE) { - struct Depsgraph *depsgraph = CTX_data_depsgraph(C); view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar); ED_view3d_autodist_init(depsgraph, gsc.ar, CTX_wm_view3d(C), 0); } @@ -2127,9 +2793,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) /* Compute inverse matrix for unapplying parenting once instead of doing per-point */ /* TODO: add this bit to the iteration macro? */ - if (gpl->parent) { - invert_m4_m4(inverse_diff_mat, diff_mat); - } + invert_m4_m4(inverse_diff_mat, diff_mat); /* Adjust each point */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { @@ -2140,19 +2804,28 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) * coordinates, resulting in lost precision, which in turn causes stairstepping * artifacts in the final points. */ - if (gpl->parent == NULL) { - gp_point_to_xy_fl(&gsc, gps, pt, &xy[0], &xy[1]); - } - else { - bGPDspoint pt2; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); + bGPDspoint pt2; + gp_point_to_parent_space(pt, diff_mat, &pt2); + gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); + + /* Project stroke in the axis locked */ + if (mode == GP_REPROJECT_AXIS) { + if (lock_axis > GP_LOCKAXIS_NONE) { + ED_gp_get_drawing_reference(v3d, scene, ob, gpl, + ts->gpencil_v3d_align, origin); + ED_gp_project_point_to_plane(ob, rv3d, origin, + lock_axis - 1, &pt2); + + copy_v3_v3(&pt->x, &pt2.x); + + /* apply parent again */ + gp_apply_parent_point(depsgraph, ob, gpd, gpl, pt); + } } - /* Project screenspace back to 3D space (from current perspective) * so that all points have been treated the same way */ - if (mode == GP_REPROJECT_PLANAR) { + else if (mode == GP_REPROJECT_PLANAR) { /* Planar - All on same plane parallel to the viewplane */ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x); } @@ -2175,7 +2848,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) } /* Unapply parent corrections */ - if (gpl->parent) { + if (mode != GP_REPROJECT_AXIS) { mul_m4_v3(inverse_diff_mat, &pt->x); } } @@ -2183,6 +2856,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) } GP_EDITABLE_STROKES_END; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -2190,6 +2864,9 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) void GPENCIL_OT_reproject(wmOperatorType *ot) { static const EnumPropertyItem reproject_type[] = { + { GP_REPROJECT_AXIS, "AXIS", 0, "Axis", + "Reproject the strokes using the current lock axis configuration. This is the same projection using while" + "drawing new strokes" }, {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar", "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint " "using 'Cursor' Stroke Placement"}, @@ -2208,7 +2885,7 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) /* callbacks */ ot->invoke = WM_menu_invoke; ot->exec = gp_strokes_reproject_exec; - ot->poll = gp_strokes_reproject_poll; + ot->poll = gp_strokes_edit3d_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -2229,7 +2906,7 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps) if (pt->flag & GP_SPOINT_SELECT) { if (i + 1 < gps->totpoints) { if (gps->points[i + 1].flag & GP_SPOINT_SELECT) { - ++totnewpoints; + totnewpoints++; } } } @@ -2237,6 +2914,7 @@ static int gp_count_subdivision_cuts(bGPDstroke *gps) return totnewpoints; } + static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -2267,6 +2945,9 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) /* resize the points arrys */ gps->totpoints += totnewpoints; gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + if (gps->dvert != NULL) { + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + } gps->flag |= GP_STROKE_RECALC_CACHES; /* loop and interpolate */ @@ -2275,19 +2956,27 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) bGPDspoint *pt = &temp_points[i]; bGPDspoint *pt_final = &gps->points[i2]; + MDeformVert *dvert_final = &gps->dvert[i2]; + /* copy current point */ copy_v3_v3(&pt_final->x, &pt->x); pt_final->pressure = pt->pressure; pt_final->strength = pt->strength; pt_final->time = pt->time; pt_final->flag = pt->flag; - ++i2; + + dvert_final->totweight = 0; + dvert_final->dw = NULL; + i2++; /* if next point is selected add a half way point */ if (pt->flag & GP_SPOINT_SELECT) { if (i + 1 < oldtotpoints) { if (temp_points[i + 1].flag & GP_SPOINT_SELECT) { pt_final = &gps->points[i2]; + if (gps->dvert != NULL) { + dvert_final = &gps->dvert[i2]; + } /* Interpolate all values */ bGPDspoint *next = &temp_points[i + 1]; interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); @@ -2296,7 +2985,11 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt_final->time = interpf(pt->time, next->time, 0.5f); pt_final->flag |= GP_SPOINT_SELECT; - ++i2; + + dvert_final->totweight = 0; + dvert_final->dw = NULL; + + i2++; } } } @@ -2309,6 +3002,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_END; /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -2328,7 +3022,7 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot) ot->poll = gp_active_layer_poll; /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, 5); @@ -2336,3 +3030,414 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } + +/* ** simplify stroke *** */ +static int gp_stroke_simplify_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + float factor = RNA_float_get(op->ptr, "factor"); + + /* sanity checks */ + if (ELEM(NULL, gpd)) + return OPERATOR_CANCELLED; + + /* Go through each editable + selected stroke */ + GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) + { + if (gps->flag & GP_STROKE_SELECT) { + /* simplify stroke using Ramer-Douglas-Peucker algorithm */ + BKE_gpencil_simplify_stroke(gps, factor); + } + } + GP_EDITABLE_STROKES_END; + + /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_simplify(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Simplify Stroke"; + ot->idname = "GPENCIL_OT_stroke_simplify"; + ot->description = "Simplify selected stroked reducing number of points"; + + /* api callbacks */ + ot->exec = gp_stroke_simplify_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_float(ot->srna, "factor", 0.0f, 0.0f, 100.0f, "Factor", "", 0.0f, 100.0f); + /* avoid re-using last var */ + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/* ** simplify stroke using fixed algorith *** */ +static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + int steps = RNA_int_get(op->ptr, "step"); + + /* sanity checks */ + if (ELEM(NULL, gpd)) + return OPERATOR_CANCELLED; + + /* Go through each editable + selected stroke */ + GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) + { + if (gps->flag & GP_STROKE_SELECT) { + for (int i = 0; i < steps; i++) { + BKE_gpencil_simplify_fixed(gps); + } + } + } + GP_EDITABLE_STROKES_END; + + /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_simplify_fixed(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Simplify Fixed Stroke"; + ot->idname = "GPENCIL_OT_stroke_simplify_fixed"; + ot->description = "Simplify selected stroked reducing number of points using fixed algorithm"; + + /* api callbacks */ + ot->exec = gp_stroke_simplify_fixed_exec; + ot->poll = gp_active_layer_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_int(ot->srna, "step", 1, 1, 100, "Steps", "Number of simplify steps", 1, 10); + + /* avoid re-using last var */ + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + +} + +/* ***************** Separate Strokes ********************** */ +typedef enum eGP_SeparateModes { + /* Points */ + GP_SEPARATE_POINT = 0, + /* Selected Strokes */ + GP_SEPARATE_STROKE, + /* Current Layer */ + GP_SEPARATE_LAYER, +} eGP_SeparateModes; + +static int gp_stroke_separate_exec(bContext *C, wmOperator *op) +{ + Base *base_new; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *base_old = CTX_data_active_base(C); + bGPdata *gpd_src = ED_gpencil_data_get_active(C); + Object *ob = CTX_data_active_object(C); + + Object *ob_dst = NULL; + bGPdata *gpd_dst = NULL; + bGPDlayer *gpl_dst = NULL; + bGPDframe *gpf_dst = NULL; + bGPDspoint *pt; + Material *ma = NULL; + int i, idx; + + eGP_SeparateModes mode = RNA_enum_get(op->ptr, "mode"); + + /* sanity checks */ + if (ELEM(NULL, gpd_src)) { + return OPERATOR_CANCELLED; + } + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_src); + + /* create a new object */ + base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, 0); + ob_dst = base_new->object; + + /* create new grease pencil datablock */ + // XXX: check usercounts + gpd_dst = BKE_gpencil_data_addnew(bmain, "GPencil"); + ob_dst->data = (bGPdata *)gpd_dst; + + int totslots = ob_dst->totcol; + int totadd = 0; + + /* loop old datablock and separate parts */ + if ((mode == GP_SEPARATE_POINT) || (mode == GP_SEPARATE_STROKE)) { + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + gpl_dst = NULL; + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + bGPDstroke *gps, *gpsn; + + if (gpf == NULL) { + continue; + } + + gpf_dst = NULL; + + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + continue; + } + /* separate selected strokes */ + if (gps->flag & GP_STROKE_SELECT) { + /* add layer if not created before */ + if (gpl_dst == NULL) { + gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl->info, false); + } + + /* add frame if not created before */ + if (gpf_dst == NULL) { + gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW); + } + + /* add duplicate materials */ + ma = give_current_material(ob, gps->mat_nr + 1); + idx = BKE_object_material_slot_find_index(ob_dst, ma); + if (idx == 0) { + + totadd++; + ob_dst->actcol = totadd; + ob_dst->totcol = totadd; + + if (totadd > totslots) { + BKE_object_material_slot_add(bmain, ob_dst); + } + + assign_material(bmain, ob_dst, ma, ob_dst->totcol, BKE_MAT_ASSIGN_EXISTING); + idx = totadd; + } + + /* selected points mode */ + if (mode == GP_SEPARATE_POINT) { + /* make copy of source stroke */ + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps); + + /* reasign material */ + gps_dst->mat_nr = idx - 1; + + /* link to destination frame */ + BLI_addtail(&gpf_dst->strokes, gps_dst); + + /* Invert selection status of all points in destination stroke */ + for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) { + pt->flag ^= GP_SPOINT_SELECT; + } + + /* delete selected points from destination stroke */ + gp_stroke_delete_tagged_points(gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false); + + /* delete selected points from origin stroke */ + gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false); + } + /* selected strokes mode */ + else if (mode == GP_SEPARATE_STROKE) { + /* deselect old stroke */ + gps->flag &= ~GP_STROKE_SELECT; + /* unlink from source frame */ + BLI_remlink(&gpf->strokes, gps); + gps->prev = gps->next = NULL; + /* relink to destination frame */ + BLI_addtail(&gpf_dst->strokes, gps); + /* reasign material */ + gps->mat_nr = idx - 1; + } + } + } + } + + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } + } + } + CTX_DATA_END; + } + else if (mode == GP_SEPARATE_LAYER) { + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + if (gpl) { + /* try to set a new active layer in source datablock */ + if (gpl->prev) { + BKE_gpencil_layer_setactive(gpd_src, gpl->prev); + } + else if (gpl->next) { + BKE_gpencil_layer_setactive(gpd_src, gpl->next); + } + /* unlink from source datablock */ + BLI_remlink(&gpd_src->layers, gpl); + gpl->prev = gpl->next = NULL; + /* relink to destination datablock */ + BLI_addtail(&gpd_dst->layers, gpl); + } + } + DEG_id_tag_update(&gpd_src->id, OB_RECALC_OB | OB_RECALC_DATA); + DEG_id_tag_update(&gpd_dst->id, OB_RECALC_OB | OB_RECALC_DATA); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_separate(wmOperatorType *ot) +{ + static const EnumPropertyItem separate_type[] = { + {GP_SEPARATE_POINT, "POINT", 0, "Selected Points", "Separate the selected points" }, + {GP_SEPARATE_STROKE, "STROKE", 0, "Selected Strokes", "Separate the selected strokes"}, + {GP_SEPARATE_LAYER, "LAYER", 0, "Active Layer", "Separate the strokes of the current layer" }, + { 0, NULL, 0, NULL, NULL } + }; + + /* identifiers */ + ot->name = "Separate Strokes"; + ot->idname = "GPENCIL_OT_stroke_separate"; + ot->description = "Separate the selected strokes or layer in a new grease pencil object"; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = gp_stroke_separate_exec; + ot->poll = gp_strokes_edit3d_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", ""); +} + +/* ***************** Split Strokes ********************** */ +static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDspoint *pt; + int i; + + /* sanity checks */ + if (ELEM(NULL, gpd)) { + return OPERATOR_CANCELLED; + } + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + + /* loop strokes and split parts */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + bGPDstroke *gps, *gpsn; + + if (gpf == NULL) { + continue; + } + + for (gps = gpf->strokes.first; gps; gps = gpsn) { + gpsn = gps->next; + + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + continue; + } + /* split selected strokes */ + if (gps->flag & GP_STROKE_SELECT) { + /* make copy of source stroke */ + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps); + + /* link to same frame */ + BLI_addtail(&gpf->strokes, gps_dst); + + /* invert selection status of all points in destination stroke */ + for (i = 0, pt = gps_dst->points; i < gps_dst->totpoints; i++, pt++) { + pt->flag ^= GP_SPOINT_SELECT; + } + + /* delete selected points from destination stroke */ + gp_stroke_delete_tagged_points(gpf, gps_dst, NULL, GP_SPOINT_SELECT, true); + + /* delete selected points from origin stroke */ + gp_stroke_delete_tagged_points(gpf, gps, gpsn, GP_SPOINT_SELECT, false); + } + } + /* select again tagged points */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + bGPDspoint *ptn = gps->points; + for (int i2 = 0; i2 < gps->totpoints; i2++, ptn++) { + if (ptn->flag & GP_SPOINT_TAG) { + ptn->flag |= GP_SPOINT_SELECT; + ptn->flag &= ~GP_SPOINT_TAG; + } + } + } + } + + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } + } + } + CTX_DATA_END; + + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split Strokes"; + ot->idname = "GPENCIL_OT_stroke_split"; + ot->description = "Split selected points as new stroke on same frame"; + + /* callbacks */ + ot->exec = gp_stroke_split_exec; + ot->poll = gp_strokes_edit3d_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c new file mode 100644 index 00000000000..b768ac2c44f --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -0,0 +1,1246 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation, Joshua Leung + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/gpencil/gpencil_fill.c + * \ingroup edgpencil + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_stack.h" + +#include "BLT_translation.h" + +#include "DNA_brush_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_image_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_windowmanager_types.h" + +#include "BKE_main.h" +#include "BKE_brush.h" +#include "BKE_image.h" +#include "BKE_gpencil.h" +#include "BKE_material.h" +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_paint.h" + +#include "ED_gpencil.h" +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_view3d.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "GPU_immediate.h" +#include "GPU_draw.h" +#include "GPU_matrix.h" +#include "GPU_framebuffer.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "gpencil_intern.h" + +#define LEAK_HORZ 0 +#define LEAK_VERT 1 + + +/* Temporary fill operation data (op->customdata) */ +typedef struct tGPDfill { + struct Main *bmain; + struct Depsgraph *depsgraph; + struct wmWindow *win; /* window where painting originated */ + struct Scene *scene; /* current scene from context */ + struct Object *ob; /* current active gp object */ + struct ScrArea *sa; /* area where painting originated */ + struct RegionView3D *rv3d; /* region where painting originated */ + struct View3D *v3d; /* view3 where painting originated */ + struct ARegion *ar; /* region where painting originated */ + struct bGPdata *gpd; /* current GP datablock */ + struct Material *mat; /* current material */ + struct bGPDlayer *gpl; /* layer */ + struct bGPDframe *gpf; /* frame */ + + short flag; /* flags */ + short oldkey; /* avoid too fast events */ + bool on_back; /* send to back stroke */ + + int center[2]; /* mouse fill center position */ + int sizex; /* windows width */ + int sizey; /* window height */ + int lock_axis; /* lock to viewport axis */ + + short fill_leak; /* number of pixel to consider the leak is too small (x 2) */ + float fill_threshold; /* factor for transparency */ + int fill_simplylvl; /* number of simplify steps */ + int fill_draw_mode; /* boundary limits drawing mode */ + + short sbuffer_size; /* number of elements currently in cache */ + void *sbuffer; /* temporary points */ + float *depth_arr; /* depth array for reproject */ + + Image *ima; /* temp image */ + BLI_Stack *stack; /* temp points data */ + void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */ +} tGPDfill; + + + /* draw a given stroke using same thickness and color for all points */ +static void gp_draw_basic_stroke(tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4], + bool cyclic, float ink[4], int flag, float thershold) +{ + bGPDspoint *points = gps->points; + + Material *ma = tgpf->mat; + MaterialGPencilStyle *gp_style = ma->gp_style; + + int totpoints = gps->totpoints; + float fpt[3]; + float col[4]; + + copy_v4_v4(col, ink); + + /* if cyclic needs more vertex */ + int cyclic_add = (cyclic) ? 1 : 0; + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); + + /* draw stroke curve */ + glLineWidth(1.0f); + immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add); + const bGPDspoint *pt = points; + + for (int i = 0; i < totpoints; i++, pt++) { + + if (flag & GP_BRUSH_FILL_HIDE) { + float alpha = gp_style->stroke_rgba[3] * pt->strength; + CLAMP(alpha, 0.0f, 1.0f); + col[3] = alpha <= thershold ? 0.0f : 1.0f; + } + else { + col[3] = 1.0f; + } + /* set point */ + immAttrib4fv(color, col); + mul_v3_m4v3(fpt, diff_mat, &pt->x); + immVertex3fv(pos, fpt); + } + + if (cyclic && totpoints > 2) { + /* draw line to first point to complete the cycle */ + immAttrib4fv(color, col); + mul_v3_m4v3(fpt, diff_mat, &points->x); + immVertex3fv(pos, fpt); + } + + immEnd(); + immUnbindProgram(); +} + +/* loop all layers */ +static void gp_draw_datablock(tGPDfill *tgpf, float ink[4]) +{ + /* duplicated: etempFlags */ + enum { + GP_DRAWFILLS_NOSTATUS = (1 << 0), /* don't draw status info */ + GP_DRAWFILLS_ONLY3D = (1 << 1), /* only draw 3d-strokes */ + }; + + Object *ob = tgpf->ob; + bGPdata *gpd = tgpf->gpd; + int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph); + + tGPDdraw tgpw; + tgpw.rv3d = tgpf->rv3d; + tgpw.depsgraph = tgpf->depsgraph; + tgpw.ob = ob; + tgpw.gpd = gpd; + tgpw.offsx = 0; + tgpw.offsy = 0; + tgpw.winx = tgpf->ar->winx; + tgpw.winy = tgpf->ar->winy; + tgpw.dflag = 0; + tgpw.disable_fill = 1; + tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS); + + glEnable(GL_BLEND); + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* calculate parent position */ + ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat); + + /* do not draw layer if hidden */ + if (gpl->flag & GP_LAYER_HIDE) + continue; + + /* get frame to draw */ + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); + if (gpf == NULL) + continue; + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* check if stroke can be drawn */ + if ((gps->points == NULL) || (gps->totpoints < 2)) { + continue; + } + /* check if the color is visible */ + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) + { + continue; + } + + tgpw.gps = gps; + tgpw.gpl = gpl; + tgpw.gpf = gpf; + tgpw.t_gpf = gpf; + + /* reduce thickness to avoid gaps */ + tgpw.lthick = gpl->line_change - 4; + tgpw.opacity = 1.0; + copy_v4_v4(tgpw.tintcolor, ink); + tgpw.onion = true; + tgpw.custonion = true; + + /* normal strokes */ + if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) || + (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) + { + ED_gp_draw_fill(&tgpw); + + } + + /* 3D Lines with basic shapes and invisible lines */ + if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) || + (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) + { + gp_draw_basic_stroke(tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink, + tgpf->flag, tgpf->fill_threshold); + } + } + } + + glDisable(GL_BLEND); +} + + /* draw strokes in offscreen buffer */ +static void gp_render_offscreen(tGPDfill *tgpf) +{ + bool is_ortho = false; + float winmat[4][4]; + + if (!tgpf->gpd) { + return; + } + + char err_out[256] = "unknown"; + GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out); + GPU_offscreen_bind(offscreen, true); + uint flag = IB_rect | IB_rectfloat; + ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag); + + rctf viewplane; + float clipsta, clipend; + + is_ortho = ED_view3d_viewplane_get(tgpf->depsgraph, tgpf->v3d, tgpf->rv3d, tgpf->sizex, tgpf->sizey, &viewplane, &clipsta, &clipend, NULL); + if (is_ortho) { + orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend); + } + else { + perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend); + } + + /* set temporary new size */ + int bwinx = tgpf->ar->winx; + int bwiny = tgpf->ar->winy; + rcti brect = tgpf->ar->winrct; + + tgpf->ar->winx = (short) tgpf->sizex; + tgpf->ar->winy = (short) tgpf->sizey; + tgpf->ar->winrct.xmin = 0; + tgpf->ar->winrct.ymin = 0; + tgpf->ar->winrct.xmax = tgpf->sizex; + tgpf->ar->winrct.ymax = tgpf->sizey; + + GPU_matrix_push_projection(); + GPU_matrix_identity_set(); + GPU_matrix_push(); + GPU_matrix_identity_set(); + + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ED_view3d_update_viewmat(tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, + NULL, winmat, NULL); + /* set for opengl */ + GPU_matrix_projection_set(tgpf->rv3d->winmat); + GPU_matrix_set(tgpf->rv3d->viewmat); + + /* draw strokes */ + float ink[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; + gp_draw_datablock(tgpf, ink); + + /* restore size */ + tgpf->ar->winx = (short)bwinx; + tgpf->ar->winy = (short)bwiny; + tgpf->ar->winrct = brect; + + GPU_matrix_pop_projection(); + GPU_matrix_pop(); + + /* create a image to see result of template */ + if (ibuf->rect_float) { + GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float); + } + else if (ibuf->rect) { + GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect); + } + if (ibuf->rect_float && ibuf->rect) { + IMB_rect_from_float(ibuf); + } + + tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill"); + tgpf->ima->id.tag |= LIB_TAG_DOIT; + + BKE_image_release_ibuf(tgpf->ima, ibuf, NULL); + + /* switch back to window-system-provided framebuffer */ + GPU_offscreen_unbind(offscreen, true); + GPU_offscreen_free(offscreen); +} + +/* return pixel data (rgba) at index */ +static void get_pixel(ImBuf *ibuf, int idx, float r_col[4]) +{ + if (ibuf->rect_float) { + float *frgba = &ibuf->rect_float[idx * 4]; + copy_v4_v4(r_col, frgba); + } + else { + /* XXX: This case probably doesn't happen, as we only write to the float buffer, + * but we get compiler warnings about uninitialised vars otherwise + */ + BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!"); + zero_v4(r_col); + } +} + +/* set pixel data (rgba) at index */ +static void set_pixel(ImBuf *ibuf, int idx, const float col[4]) +{ + if (ibuf->rect) { + uint *rrect = &ibuf->rect[idx]; + uchar ccol[4]; + + rgba_float_to_uchar(ccol, col); + *rrect = *((uint *)ccol); + } + + if (ibuf->rect_float) { + float *rrectf = &ibuf->rect_float[idx * 4]; + copy_v4_v4(rrectf, col); + } +} + +/* check if the size of the leak is narrow to determine if the stroke is closed + * this is used for strokes with small gaps between them to get a full fill + * and do not get a full screen fill. + * + * \param ibuf Image pixel data + * \param maxpixel Maximum index + * \param limit Limit of pixels to analize + * \param index Index of current pixel + * \param type 0-Horizontal 1-Vertical + */ +static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type) +{ + float rgba[4]; + int i; + int pt; + bool t_a = false; + bool t_b = false; + + /* Horizontal leak (check vertical pixels) + * X + * X + * xB7 + * X + * X + */ + if (type == LEAK_HORZ) { + /* pixels on top */ + for (i = 1; i <= limit; i++) { + pt = index + (ibuf->x * i); + if (pt <= maxpixel) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { + t_a = true; + break; + } + } + else { + t_a = true; /* edge of image*/ + break; + } + } + /* pixels on bottom */ + for (i = 1; i <= limit; i++) { + pt = index - (ibuf->x * i); + if (pt >= 0) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { + t_b = true; + break; + } + } + else { + t_b = true; /* edge of image*/ + break; + } + } + } + + /* Vertical leak (check horizontal pixels) + * + * XXXxB7XX + * + */ + if (type == LEAK_VERT) { + /* get pixel range of the row */ + int row = index / ibuf->x; + int lowpix = row * ibuf->x; + int higpix = lowpix + ibuf->x - 1; + + /* pixels to right */ + for (i = 0; i < limit; i++) { + pt = index - (limit - i); + if (pt >= lowpix) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { + t_a = true; + break; + } + } + else { + t_a = true; /* edge of image*/ + break; + } + } + /* pixels to left */ + for (i = 0; i < limit; i++) { + pt = index + (limit - i); + if (pt <= higpix) { + get_pixel(ibuf, pt, rgba); + if (rgba[0] == 1.0f) { + t_b = true; + break; + } + } + else { + t_b = true; /* edge of image */ + break; + } + } + } + return (bool)(t_a && t_b); +} + +/* Boundary fill inside strokes + * Fills the space created by a set of strokes using the stroke color as the boundary + * of the shape to fill. + * + * \param tgpf Temporary fill data + */ +static void gpencil_boundaryfill_area(tGPDfill *tgpf) +{ + ImBuf *ibuf; + float rgba[4]; + void *lock; + const float fill_col[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; + ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); + const int maxpixel = (ibuf->x * ibuf->y) - 1; + + BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__); + + /* calculate index of the seed point using the position of the mouse */ + int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0]; + if ((index >= 0) && (index < maxpixel)) { + BLI_stack_push(stack, &index); + } + + /* the fill use a stack to save the pixel list instead of the common recursive + * 4-contact point method. + * The problem with recursive calls is that for big fill areas, we can get max limit + * of recursive calls and STACK_OVERFLOW error. + * + * The 4-contact point analyze the pixels to the left, right, bottom and top + * ----------- + * | X | + * | XoX | + * | X | + * ----------- + */ + while (!BLI_stack_is_empty(stack)) { + int v; + BLI_stack_pop(stack, &v); + + get_pixel(ibuf, v, rgba); + + if (true) { /* Was: 'rgba' */ + /* check if no border(red) or already filled color(green) */ + if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) + { + /* fill current pixel */ + set_pixel(ibuf, v, fill_col); + + /* add contact pixels */ + /* pixel left */ + if (v - 1 >= 0) { + index = v - 1; + if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) { + BLI_stack_push(stack, &index); + } + } + /* pixel right */ + if (v + 1 < maxpixel) { + index = v + 1; + if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) { + BLI_stack_push(stack, &index); + } + } + /* pixel top */ + if (v + tgpf->sizex < maxpixel) { + index = v + tgpf->sizex; + if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) { + BLI_stack_push(stack, &index); + } + } + /* pixel bottom */ + if (v - tgpf->sizex >= 0) { + index = v - tgpf->sizex; + if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) { + BLI_stack_push(stack, &index); + } + } + } + } + } + + /* release ibuf */ + if (ibuf) { + BKE_image_release_ibuf(tgpf->ima, ibuf, lock); + } + + tgpf->ima->id.tag |= LIB_TAG_DOIT; + /* free temp stack data */ + BLI_stack_free(stack); +} + +/* clean external border of image to avoid infinite loops */ +static void gpencil_clean_borders(tGPDfill *tgpf) +{ + ImBuf *ibuf; + void *lock; + const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); + int idx; + + /* horizontal lines */ + for (idx = 0; idx < ibuf->x; idx++) { + /* bottom line */ + set_pixel(ibuf, idx, fill_col); + /* top line */ + set_pixel(ibuf, idx + (ibuf->x * (ibuf->y - 1)), fill_col); + } + /* vertical lines */ + for (idx = 0; idx < ibuf->y; idx++) { + /* left line */ + set_pixel(ibuf, ibuf->x * idx, fill_col); + /* right line */ + set_pixel(ibuf, ibuf->x * idx + (ibuf->x - 1), fill_col); + } + + /* release ibuf */ + if (ibuf) { + BKE_image_release_ibuf(tgpf->ima, ibuf, lock); + } + + tgpf->ima->id.tag |= LIB_TAG_DOIT; +} + +/* Get the outline points of a shape using Moore Neighborhood algorithm + * + * This is a Blender customized version of the general algorithm described + * in https://en.wikipedia.org/wiki/Moore_neighborhood + */ +static void gpencil_get_outline_points(tGPDfill *tgpf) +{ + ImBuf *ibuf; + float rgba[4]; + void *lock; + int v[2]; + int boundary_co[2]; + int start_co[2]; + int backtracked_co[2]; + int current_check_co[2]; + int prev_check_co[2]; + int backtracked_offset[1][2] = { { 0,0 } }; + // bool boundary_found = false; + bool start_found = false; + const int NEIGHBOR_COUNT = 8; + + int offset[8][2] = { + { -1, -1 }, + { 0, -1 }, + { 1, -1 }, + { 1, 0 }, + { 1, 1 }, + { 0, 1 }, + { -1, 1 }, + { -1, 0 } + }; + + tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__); + + ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); + int imagesize = ibuf->x * ibuf->y; + + /* find the initial point to start outline analysis */ + for (int idx = imagesize; idx >= 0; idx--) { + get_pixel(ibuf, idx, rgba); + if (rgba[1] == 1.0f) { + boundary_co[0] = idx % ibuf->x; + boundary_co[1] = idx / ibuf->x; + copy_v2_v2_int(start_co, boundary_co); + backtracked_co[0] = (idx - 1) % ibuf->x; + backtracked_co[1] = (idx - 1) / ibuf->x; + backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0]; + backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1]; + copy_v2_v2_int(prev_check_co, start_co); + + BLI_stack_push(tgpf->stack, &boundary_co); + start_found = true; + break; + } + } + + while (true && start_found) + { + int cur_back_offset = -1; + for (int i = 0; i < NEIGHBOR_COUNT; i++) { + if (backtracked_offset[0][0] == offset[i][0] && + backtracked_offset[0][1] == offset[i][1]) + { + /* Finding the bracktracked pixel offset index */ + cur_back_offset = i; + break; + } + } + + int loop = 0; + while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) { + int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT; + current_check_co[0] = boundary_co[0] + offset[offset_idx][0]; + current_check_co[1] = boundary_co[1] + offset[offset_idx][1]; + + int image_idx = ibuf->x * current_check_co[1] + current_check_co[0]; + get_pixel(ibuf, image_idx, rgba); + + /* find next boundary pixel */ + if (rgba[1] == 1.0f) { + copy_v2_v2_int(boundary_co, current_check_co); + copy_v2_v2_int(backtracked_co, prev_check_co); + backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0]; + backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1]; + + BLI_stack_push(tgpf->stack, &boundary_co); + + break; + } + copy_v2_v2_int(prev_check_co, current_check_co); + cur_back_offset++; + loop++; + } + /* current pixel is equal to starting pixel */ + if (boundary_co[0] == start_co[0] && + boundary_co[1] == start_co[1]) + { + BLI_stack_pop(tgpf->stack, &v); + // boundary_found = true; + break; + } + } + + /* release ibuf */ + if (ibuf) { + BKE_image_release_ibuf(tgpf->ima, ibuf, lock); + } +} + +/* get z-depth array to reproject on surface */ +static void gpencil_get_depth_array(tGPDfill *tgpf) +{ + tGPspoint *ptc; + ToolSettings *ts = tgpf->scene->toolsettings; + int totpoints = tgpf->sbuffer_size; + int i = 0; + + if (totpoints == 0) { + return; + } + + /* for surface sketching, need to set the right OpenGL context stuff so that + * the conversions will project the values correctly... + */ + if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) { + /* need to restore the original projection settings before packing up */ + view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar); + ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0); + + /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ + int depth_margin = 0; + + /* get an array of depths, far depths are blended */ + int mval[2], mval_prev[2] = { 0 }; + int interp_depth = 0; + int found_depth = 0; + + tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points"); + + for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) { + copy_v2_v2_int(mval, &ptc->x); + + if ((ED_view3d_autodist_depth(tgpf->ar, mval, depth_margin, tgpf->depth_arr + i) == 0) && + (i && (ED_view3d_autodist_depth_seg(tgpf->ar, mval, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) + { + interp_depth = true; + } + else { + found_depth = true; + } + + copy_v2_v2_int(mval_prev, mval); + } + + if (found_depth == false) { + /* eeh... not much we can do.. :/, ignore depth in this case */ + for (i = totpoints - 1; i >= 0; i--) + tgpf->depth_arr[i] = 0.9999f; + } + else { + if (interp_depth) { + interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX); + } + } + } +} + +/* create array of points using stack as source */ +static void gpencil_points_from_stack(tGPDfill *tgpf) +{ + tGPspoint *point2D; + int totpoints = BLI_stack_count(tgpf->stack); + if (totpoints == 0) { + return; + } + + tgpf->sbuffer_size = (short)totpoints; + tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__); + + point2D = tgpf->sbuffer; + while (!BLI_stack_is_empty(tgpf->stack)) { + int v[2]; + BLI_stack_pop(tgpf->stack, &v); + point2D->x = v[0]; + point2D->y = v[1]; + + point2D->pressure = 1.0f; + point2D->strength = 1.0f;; + point2D->time = 0.0f; + point2D++; + } +} + +/* create a grease pencil stroke using points in buffer */ +static void gpencil_stroke_from_buffer(tGPDfill *tgpf) +{ + ToolSettings *ts = tgpf->scene->toolsettings; + int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph); + + Brush *brush; + brush = BKE_brush_getactive_gpencil(ts); + if (brush == NULL) { + return; + } + + bGPDspoint *pt; + MDeformVert *dvert; + tGPspoint *point2D; + + if (tgpf->sbuffer_size == 0) { + return; + } + + /* get frame or create a new one */ + tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW); + + /* create new stroke */ + bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); + gps->thickness = brush->size; + gps->inittime = 0.0f; + + /* the polygon must be closed, so enabled cyclic */ + gps->flag |= GP_STROKE_CYCLIC; + gps->flag |= GP_STROKE_3DSPACE; + + gps->mat_nr = BKE_object_material_slot_find_index(tgpf->ob, tgpf->mat) - 1; + + /* allocate memory for storage points */ + gps->totpoints = tgpf->sbuffer_size; + gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert) * tgpf->sbuffer_size, "gp_stroke_weights"); + + /* initialize triangle memory to dummy data */ + gps->tot_triangles = 0; + gps->triangles = NULL; + gps->flag |= GP_STROKE_RECALC_CACHES; + + /* add stroke to frame */ + if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)){ + BLI_addhead(&tgpf->gpf->strokes, gps); + } + else { + BLI_addtail(&tgpf->gpf->strokes, gps); + } + + /* add points */ + pt = gps->points; + dvert = gps->dvert; + point2D = (tGPspoint *)tgpf->sbuffer; + for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++, dvert++) { + /* convert screen-coordinates to 3D coordinates */ + gp_stroke_convertcoords_tpoint(tgpf->scene, tgpf->ar, tgpf->v3d, tgpf->ob, + tgpf->gpl, point2D, + tgpf->depth_arr ? tgpf->depth_arr + i : NULL, + &pt->x); + + pt->pressure = 1.0f; + pt->strength = 1.0f;; + pt->time = 0.0f; + + dvert->totweight = 0; + dvert->dw = NULL; + } + + /* smooth stroke */ + float reduce = 0.0f; + float smoothfac = 1.0f; + for (int r = 0; r < 1; r++) { + for (int i = 0; i < gps->totpoints; i++) { + BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce); + } + reduce += 0.25f; // reduce the factor + } + + /* if axis locked, reproject to plane locked */ + if ((tgpf->lock_axis > GP_LOCKAXIS_NONE) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) { + float origin[3]; + ED_gp_get_drawing_reference(tgpf->v3d, tgpf->scene, tgpf->ob, tgpf->gpl, + ts->gpencil_v3d_align, origin); + ED_gp_project_stroke_to_plane(tgpf->ob, tgpf->rv3d, gps, origin, + tgpf->lock_axis - 1); + } + + /* if parented change position relative to parent object */ + for (int a = 0; a < tgpf->sbuffer_size; a++) { + pt = &gps->points[a]; + gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt); + } + + /* simplify stroke */ + for (int b = 0; b < tgpf->fill_simplylvl; b++) { + BKE_gpencil_simplify_fixed(gps); + } +} + +/* ----------------------- */ +/* Drawing */ +/* Helper: Draw status message while the user is running the operator */ +static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf)) +{ + char status_str[UI_MAX_DRAW_STR]; + + BLI_snprintf(status_str, sizeof(status_str), IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back")); + ED_workspace_status_text(C, status_str); +} + +/* draw boundary lines to see fill limits */ +static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgpf) +{ + if (!tgpf->gpd) { + return; + } + float ink[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; + gp_draw_datablock(tgpf, ink); +} + +/* Drawing callback for modal operator in 3d mode */ +static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg) +{ + tGPDfill *tgpf = (tGPDfill *)arg; + /* draw only in the region that originated operator. This is required for multiwindow */ + ARegion *ar = CTX_wm_region(C); + if (ar != tgpf->ar) { + return; + } + + gpencil_draw_boundary_lines(C, tgpf); +} + +/* check if context is suitable for filling */ +static bool gpencil_fill_poll(bContext *C) +{ + if (ED_operator_regionactive(C)) { + ScrArea *sa = CTX_wm_area(C); + if (sa->spacetype == SPACE_VIEW3D) { + return 1; + } + else { + CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator"); + return 0; + } + } + else { + CTX_wm_operator_poll_msg_set(C, "Active region not set"); + return 0; + } +} + +/* Allocate memory and initialize values */ +static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op)) +{ + tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data"); + + /* define initial values */ + ToolSettings *ts = CTX_data_tool_settings(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + Main *bmain = CTX_data_main(C); + + /* set current scene and window info */ + tgpf->bmain = CTX_data_main(C); + tgpf->scene = CTX_data_scene(C); + tgpf->ob = CTX_data_active_object(C); + tgpf->sa = CTX_wm_area(C); + tgpf->ar = CTX_wm_region(C); + tgpf->rv3d = tgpf->ar->regiondata; + tgpf->v3d = tgpf->sa->spacedata.first; + tgpf->depsgraph = CTX_data_depsgraph(C); + tgpf->win = CTX_wm_window(C); + + /* set GP datablock */ + tgpf->gpd = gpd; + tgpf->gpl = BKE_gpencil_layer_getactive(gpd); + + tgpf->lock_axis = ts->gp_sculpt.lock_axis; + + tgpf->oldkey = -1; + tgpf->sbuffer_size = 0; + tgpf->sbuffer = NULL; + tgpf->depth_arr = NULL; + + /* save filling parameters */ + Brush *brush = BKE_brush_getactive_gpencil(ts); + tgpf->flag = brush->gpencil_settings->flag; + tgpf->fill_leak = brush->gpencil_settings->fill_leak; + tgpf->fill_threshold = brush->gpencil_settings->fill_threshold; + tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl; + tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode; + + /* get color info */ + Material *ma = BKE_gpencil_get_material_from_brush(brush); + /* if no brush defaults, get material and color info */ + if ((ma == NULL) || (ma->gp_style == NULL)) { + ma = BKE_gpencil_material_ensure(bmain, tgpf->ob); + /* assign always the first material to the brush */ + brush->gpencil_settings->material = give_current_material(tgpf->ob, 1); + } + + tgpf->mat = ma; + + /* init undo */ + gpencil_undo_init(tgpf->gpd); + + /* return context data for running operator */ + return tgpf; +} + +/* end operator */ +static void gpencil_fill_exit(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + + /* clear undo stack */ + gpencil_undo_finish(); + + /* restore cursor to indicate end of fill */ + WM_cursor_modal_restore(CTX_wm_window(C)); + + tGPDfill *tgpf = op->customdata; + + /* don't assume that operator data exists at all */ + if (tgpf) { + /* clear status message area */ + ED_workspace_status_text(C, NULL); + + MEM_SAFE_FREE(tgpf->sbuffer); + MEM_SAFE_FREE(tgpf->depth_arr); + + /* remove drawing handler */ + if (tgpf->draw_handle_3d) { + ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d); + } + + /* delete temp image */ + if (tgpf->ima) { + for (Image *ima = bmain->image.first; ima; ima = ima->id.next) { + if (ima == tgpf->ima) { + BLI_remlink(&bmain->image, ima); + BKE_image_free(tgpf->ima); + MEM_SAFE_FREE(tgpf->ima); + break; + } + } + } + + /* finally, free memory used by temp data */ + MEM_freeN(tgpf); + } + + /* clear pointer */ + op->customdata = NULL; + + /* drawing batch cache is dirty now */ + if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) { + bGPdata *gpd2 = ob->data; + DEG_id_tag_update(&gpd2->id, OB_RECALC_OB | OB_RECALC_DATA); + gpd2->flag |= GP_DATA_CACHE_IS_DIRTY; + } + + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); +} + +static void gpencil_fill_cancel(bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + gpencil_fill_exit(C, op); +} + +/* Init: Allocate memory and set init values */ +static int gpencil_fill_init(bContext *C, wmOperator *op) +{ + tGPDfill *tgpf; + + /* check context */ + tgpf = op->customdata = gp_session_init_fill(C, op); + if (tgpf == NULL) { + /* something wasn't set correctly in context */ + gpencil_fill_exit(C, op); + return 0; + } + + /* everything is now setup ok */ + return 1; +} + +/* start of interactive part of operator */ +static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + tGPDfill *tgpf = NULL; + + /* try to initialize context data needed */ + if (!gpencil_fill_init(C, op)) { + gpencil_fill_exit(C, op); + if (op->customdata) + MEM_freeN(op->customdata); + return OPERATOR_CANCELLED; + } + else { + tgpf = op->customdata; + } + + /* Enable custom drawing handlers to show help lines */ + if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) { + tgpf->draw_handle_3d = ED_region_draw_cb_activate(tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW); + } + + WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR); + + gpencil_fill_status_indicators(C, tgpf); + + DEG_id_tag_update(&tgpf->gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + + /* add a modal handler for this operator*/ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +/* events handling during interactive part of operator */ +static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + tGPDfill *tgpf = op->customdata; + + int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */ + + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + estate = OPERATOR_CANCELLED; + break; + case LEFTMOUSE: + tgpf->on_back = RNA_boolean_get(op->ptr, "on_back"); + /* first time the event is not enabled to show help lines */ + if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) { + ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y); + if (ar) { + bool in_bounds = false; + + /* Perform bounds check */ + in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y); + + if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) { + /* TODO GPXX: Verify the mouse click is right for any window size */ + tgpf->center[0] = event->mval[0]; + tgpf->center[1] = event->mval[1]; + + /* save size */ + tgpf->sizex = ar->winx; + tgpf->sizey = ar->winy; + + /* render screen to temp image */ + gp_render_offscreen(tgpf); + + /* apply boundary fill */ + gpencil_boundaryfill_area(tgpf); + + /* clean borders to avoid infinite loops */ + gpencil_clean_borders(tgpf); + + /* analyze outline */ + gpencil_get_outline_points(tgpf); + + /* create array of points from stack */ + gpencil_points_from_stack(tgpf); + + /* create z-depth array for reproject */ + gpencil_get_depth_array(tgpf); + + /* create stroke and reproject */ + gpencil_stroke_from_buffer(tgpf); + + /* free temp stack data */ + if (tgpf->stack) { + BLI_stack_free(tgpf->stack); + } + + /* push undo data */ + gpencil_undo_push(tgpf->gpd); + + estate = OPERATOR_FINISHED; + } + else { + estate = OPERATOR_CANCELLED; + } + } + else { + estate = OPERATOR_CANCELLED; + } + } + tgpf->oldkey = event->type; + break; + } + /* process last operations before exiting */ + switch (estate) { + case OPERATOR_FINISHED: + gpencil_fill_exit(C, op); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + break; + + case OPERATOR_CANCELLED: + gpencil_fill_exit(C, op); + break; + + case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH: + break; + } + + /* return status code */ + return estate; +} + +void GPENCIL_OT_fill(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Grease Pencil Fill"; + ot->idname = "GPENCIL_OT_fill"; + ot->description = "Fill with color the shape formed by strokes"; + + /* api callbacks */ + ot->invoke = gpencil_fill_invoke; + ot->modal = gpencil_fill_modal; + ot->poll = gpencil_fill_poll; + ot->cancel = gpencil_fill_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; + + prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 90ff1e0bb25..0218530be4e 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -34,24 +34,144 @@ #include "DNA_vec_types.h" +#include "ED_numinput.h" + /* internal exports only */ struct bGPdata; struct bGPDstroke; struct bGPDspoint; +struct tGPspoint; +struct Material; struct GHash; struct RNG; +struct Brush; +struct Scene; struct ARegion; +struct View3D; struct View2D; struct wmOperatorType; +struct Depsgraph; + struct PointerRNA; struct PropertyRNA; struct EnumPropertyItem; +/* ***************************************************** */ +/* Modal Operator Geometry Preview + * + * Several modal operators (Fill, Interpolate, Primitive) + * need to run some drawing code to display previews, or + * to perform screen-space/image-based analysis routines. + * The following structs + function prototypes are used + * by these operators so that the operator code + * (in gpencil_.c) can communicate with the drawing + * code (in drawgpencil.c). + * + * NOTE: All this is within the gpencil module, so nothing needs + * to be exported to other modules. + */ + +/* Internal Operator-State Data ------------------------ */ + +/* Temporary draw data (no draw manager mode) */ +typedef struct tGPDdraw { + struct RegionView3D *rv3d; /* region to draw */ + struct Depsgraph *depsgraph; /* depsgraph */ + struct Object *ob; /* GP object */ + struct bGPdata *gpd; /* current GP datablock */ + struct bGPDlayer *gpl; /* layer */ + struct bGPDframe *gpf; /* frame */ + struct bGPDframe *t_gpf; /* temporal frame */ + struct bGPDstroke *gps; /* stroke */ + int disable_fill; /* disable fill */ + int offsx; /* windows offset x */ + int offsy; /* windows offset y */ + int winx; /* windows width */ + int winy; /* windows height */ + int dflag; /* flags datablock */ + short lthick; /* layer thickness */ + float opacity; /* opacity */ + float tintcolor[4]; /* tint color */ + bool onion; /* onion flag */ + bool custonion; /* use custom onion colors */ + float diff_mat[4][4]; /* matrix */ +} tGPDdraw; + + +/* Temporary interpolate operation data */ +typedef struct tGPDinterpolate_layer { + struct tGPDinterpolate_layer *next, *prev; + + struct bGPDlayer *gpl; /* layer */ + struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */ + struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */ + struct bGPDframe *interFrame; /* interpolated frame */ + float factor; /* interpolate factor */ + +} tGPDinterpolate_layer; + +typedef struct tGPDinterpolate { + struct Scene *scene; /* current scene from context */ + struct ScrArea *sa; /* area where painting originated */ + struct ARegion *ar; /* region where painting originated */ + struct bGPdata *gpd; /* current GP datablock */ + struct Material *mat; /* current material */ + + int cframe; /* current frame number */ + ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */ + float shift; /* value for determining the displacement influence */ + float init_factor; /* initial interpolation factor for active layer */ + float low_limit; /* shift low limit (-100%) */ + float high_limit; /* shift upper limit (200%) */ + int flag; /* flag from toolsettings */ + + NumInput num; /* numeric input */ + void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */ + void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */ +} tGPDinterpolate; + + +/* Temporary primitive operation data */ +typedef struct tGPDprimitive { + struct Depsgraph *depsgraph; + struct wmWindow *win; /* window where painting originated */ + struct Scene *scene; /* current scene from context */ + struct Object *ob; /* current active gp object */ + struct ScrArea *sa; /* area where painting originated */ + struct RegionView3D *rv3d; /* region where painting originated */ + struct View3D *v3d; /* view3d where painting originated */ + struct ARegion *ar; /* region where painting originated */ + struct bGPdata *gpd; /* current GP datablock */ + struct Material *mat; /* current material */ + struct Brush *brush; /* current brush */ + + int cframe; /* current frame number */ + struct bGPDlayer *gpl; /* layer */ + struct bGPDframe *gpf; /* frame */ + int type; /* type of primitive */ + int tot_edges; /* number of polygon edges */ + int top[2]; /* first box corner */ + int bottom[2]; /* last box corner */ + int flag; /* flag to determine operations in progress */ + + int lock_axis; /* lock to viewport axis */ + + NumInput num; /* numeric input */ + void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */ +} tGPDprimitive; + + +/* Modal Operator Drawing Callbacks ------------------------ */ + +void ED_gp_draw_interpolation(const struct bContext *C, struct tGPDinterpolate *tgpi, const int type); +void ED_gp_draw_primitives(const struct bContext *C, struct tGPDprimitive *tgpi, const int type); +void ED_gp_draw_fill(struct tGPDdraw *tgpw); + /* ***************************************************** */ /* Internal API */ @@ -84,21 +204,29 @@ void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt, float *r_x, float *r_y); void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint *r_pt); - -void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps); - -void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt); +/** + * Change points position relative to parent object + */ +void gp_apply_parent(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps); +/** + * Change point position relative to parent object + */ +void gp_apply_parent_point(struct Depsgraph *depsgraph, struct Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt); bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]); +/* helper to convert 2d to 3d */ +void gp_stroke_convertcoords_tpoint(struct Scene *scene, struct ARegion *ar, + struct View3D *v3d, struct Object *ob, + bGPDlayer *gpl, const struct tGPspoint *point2D, + float *depth, float out[3]); + /* Poll Callbacks ------------------------------------ */ /* gpencil_utils.c */ bool gp_add_poll(struct bContext *C); bool gp_active_layer_poll(struct bContext *C); bool gp_active_brush_poll(struct bContext *C); -bool gp_active_palette_poll(struct bContext *C); -bool gp_active_palettecolor_poll(struct bContext *C); bool gp_brush_crt_presets_poll(bContext *C); /* Copy/Paste Buffer --------------------------------- */ @@ -107,18 +235,19 @@ bool gp_brush_crt_presets_poll(bContext *C); extern ListBase gp_strokes_copypastebuf; /* Build a map for converting between old colornames and destination-color-refs */ -struct GHash *gp_copybuf_validate_colormap(bGPdata *gpd); +struct GHash *gp_copybuf_validate_colormap(struct bContext *C); /* Stroke Editing ------------------------------------ */ -void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags); - +void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, + int tag_flags, bool select); +int gp_delete_selected_point_wrap(bContext *C); bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure); bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf); bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf); -void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints); -void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, struct RNG *rng); +void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide); +void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, struct RNG *rng); /* Layers Enums -------------------------------------- */ @@ -129,22 +258,18 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf( struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free); -/* Enums of GP Brushes */ -const EnumPropertyItem *ED_gpencil_brushes_enum_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), - bool *r_free); - -/* Enums of GP palettes */ -const EnumPropertyItem *ED_gpencil_palettes_enum_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), - bool *r_free); - /* ***************************************************** */ /* Operator Defines */ +/* annotations ------ */ + +void GPENCIL_OT_annotate(struct wmOperatorType *ot); + + /* drawing ---------- */ void GPENCIL_OT_draw(struct wmOperatorType *ot); +void GPENCIL_OT_fill(struct wmOperatorType *ot); /* Paint Modes for operator */ typedef enum eGPencil_PaintModes { @@ -160,7 +285,11 @@ typedef enum eGPencil_PaintModes { /* stroke editing ----- */ void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot); +void GPENCIL_OT_paintmode_toggle(struct wmOperatorType *ot); +void GPENCIL_OT_sculptmode_toggle(struct wmOperatorType *ot); +void GPENCIL_OT_weightmode_toggle(struct wmOperatorType *ot); void GPENCIL_OT_selection_opacity_toggle(struct wmOperatorType *ot); +void GPENCIL_OT_multiedit_toggle(struct wmOperatorType *ot); void GPENCIL_OT_select(struct wmOperatorType *ot); void GPENCIL_OT_select_all(struct wmOperatorType *ot); @@ -174,6 +303,7 @@ void GPENCIL_OT_select_more(struct wmOperatorType *ot); void GPENCIL_OT_select_less(struct wmOperatorType *ot); void GPENCIL_OT_select_first(struct wmOperatorType *ot); void GPENCIL_OT_select_last(struct wmOperatorType *ot); +void GPENCIL_OT_select_alternate(struct wmOperatorType *ot); void GPENCIL_OT_duplicate(struct wmOperatorType *ot); void GPENCIL_OT_delete(struct wmOperatorType *ot); @@ -218,6 +348,8 @@ void GPENCIL_OT_blank_frame_add(struct wmOperatorType *ot); void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot); +void GPENCIL_OT_frame_duplicate(struct wmOperatorType *ot); +void GPENCIL_OT_frame_clean_fill(struct wmOperatorType *ot); void GPENCIL_OT_convert(struct wmOperatorType *ot); @@ -226,6 +358,13 @@ enum { GP_STROKE_JOINCOPY = 1 }; +enum { + GP_STROKE_BOX = -1, + GP_STROKE_LINE = 1, + GP_STROKE_CIRCLE = 2 +}; + + void GPENCIL_OT_stroke_arrange(struct wmOperatorType *ot); void GPENCIL_OT_stroke_change_color(struct wmOperatorType *ot); void GPENCIL_OT_stroke_lock_color(struct wmOperatorType *ot); @@ -234,30 +373,15 @@ void GPENCIL_OT_stroke_cyclical_set(struct wmOperatorType *ot); void GPENCIL_OT_stroke_join(struct wmOperatorType *ot); void GPENCIL_OT_stroke_flip(struct wmOperatorType *ot); void GPENCIL_OT_stroke_subdivide(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_simplify(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_simplify_fixed(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_separate(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_split(struct wmOperatorType *ot); -void GPENCIL_OT_brush_add(struct wmOperatorType *ot); -void GPENCIL_OT_brush_remove(struct wmOperatorType *ot); -void GPENCIL_OT_brush_change(struct wmOperatorType *ot); -void GPENCIL_OT_brush_move(struct wmOperatorType *ot); void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot); -void GPENCIL_OT_brush_copy(struct wmOperatorType *ot); void GPENCIL_OT_brush_select(struct wmOperatorType *ot); -void GPENCIL_OT_palette_add(struct wmOperatorType *ot); -void GPENCIL_OT_palette_remove(struct wmOperatorType *ot); -void GPENCIL_OT_palette_change(struct wmOperatorType *ot); -void GPENCIL_OT_palette_lock_layer(struct wmOperatorType *ot); - -void GPENCIL_OT_palettecolor_add(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_remove(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_isolate(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_hide(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_reveal(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_lock_all(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_unlock_all(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_move(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_select(struct wmOperatorType *ot); -void GPENCIL_OT_palettecolor_copy(struct wmOperatorType *ot); +void GPENCIL_OT_sculpt_select(struct wmOperatorType *ot); /* undo stack ---------- */ @@ -271,6 +395,30 @@ void GPENCIL_OT_interpolate(struct wmOperatorType *ot); void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot); void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot); +/* primitives ---------- */ + +void GPENCIL_OT_primitive(struct wmOperatorType *ot); + +/* vertex groups ------------ */ +void GPENCIL_OT_vertex_group_assign(struct wmOperatorType *ot); +void GPENCIL_OT_vertex_group_remove_from(struct wmOperatorType *ot); +void GPENCIL_OT_vertex_group_select(struct wmOperatorType *ot); +void GPENCIL_OT_vertex_group_deselect(struct wmOperatorType *ot); +void GPENCIL_OT_vertex_group_invert(struct wmOperatorType *ot); +void GPENCIL_OT_vertex_group_smooth(struct wmOperatorType *ot); + +/* color handle */ +void GPENCIL_OT_lock_layer(struct wmOperatorType *ot); +void GPENCIL_OT_color_isolate(struct wmOperatorType *ot); +void GPENCIL_OT_color_hide(struct wmOperatorType *ot); +void GPENCIL_OT_color_reveal(struct wmOperatorType *ot); +void GPENCIL_OT_color_lock_all(struct wmOperatorType *ot); +void GPENCIL_OT_color_unlock_all(struct wmOperatorType *ot); +void GPENCIL_OT_color_select(struct wmOperatorType *ot); + +/* convert old 2.7 files to 2.8 */ +void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot); + /* ****************************************************** */ /* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */ @@ -331,24 +479,37 @@ typedef enum ACTCONT_TYPES { */ #define GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) \ { \ + Depsgraph *depsgraph_ = CTX_data_depsgraph(C); \ + Object *obact_ = CTX_data_active_object(C); \ + bGPdata *gpd_ = CTX_data_gpencil_data(C); \ + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \ CTX_DATA_BEGIN(C, bGPDlayer*, gpl, editable_gpencil_layers) \ { \ - if (gpl->actframe == NULL) \ - continue; \ - /* calculate difference matrix if parent object */ \ - float diff_mat[4][4]; \ - ED_gpencil_parent_location(gpl, diff_mat); \ - /* loop over strokes */ \ - for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { \ - /* skip strokes that are invalid for current view */ \ - if (ED_gpencil_stroke_can_use(C, gps) == false) \ - continue; \ - /* check if the color is editable */ \ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) \ - continue; \ - /* ... Do Stuff With Strokes ... */ + bGPDframe *init_gpf = gpl->actframe; \ + if (is_multiedit) { \ + init_gpf = gpl->frames.first; \ + } \ + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { \ + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { \ + /* calculate difference matrix */ \ + float diff_mat[4][4]; \ + ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, diff_mat); \ + /* loop over strokes */ \ + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { \ + /* skip strokes that are invalid for current view */ \ + if (ED_gpencil_stroke_can_use(C, gps) == false) \ + continue; \ + /* check if the color is editable */ \ + if (ED_gpencil_stroke_color_use(obact_, gpl, gps) == false) \ + continue; \ + /* ... Do Stuff With Strokes ... */ #define GP_EDITABLE_STROKES_END \ + } \ + } \ + if (!is_multiedit) { \ + break; \ + } \ } \ } \ CTX_DATA_END; \ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index cc30d7ec266..6541e9f012a 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -47,6 +47,7 @@ #include "DNA_color_types.h" #include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -60,6 +61,7 @@ #include "BKE_library.h" #include "BKE_report.h" #include "BKE_screen.h" +#include "BKE_deform.h" #include "UI_interface.h" #include "UI_resources.h" @@ -79,6 +81,9 @@ #include "ED_view3d.h" #include "ED_space_api.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "gpencil_intern.h" /* ************************************************ */ @@ -108,11 +113,13 @@ static bool gpencil_view3d_poll(bContext *C) static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) { bGPDspoint *prev, *pt, *next; + MDeformVert *dvert; /* update points */ for (int i = 0; i < new_stroke->totpoints; i++) { prev = &gps_from->points[i]; pt = &new_stroke->points[i]; + dvert = &new_stroke->dvert[i]; next = &gps_to->points[i]; /* Interpolate all values */ @@ -120,6 +127,9 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor); pt->strength = interpf(prev->strength, next->strength, 1.0f - factor); CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + + dvert->totweight = 0; + dvert->dw = NULL; } } @@ -128,6 +138,7 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t /* Helper: Update all strokes interpolated */ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) { + bGPdata *gpd = tgpi->gpd; tGPDinterpolate_layer *tgpil; const float shift = tgpi->shift; @@ -156,12 +167,14 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) } } + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } /* Helper: Verify valid strokes for interpolation */ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) { + Object *ob = CTX_data_active_object(C); ToolSettings *ts = CTX_data_tool_settings(C); eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag; @@ -190,7 +203,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { + if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) { continue; } @@ -213,6 +226,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) bGPdata *gpd = tgpi->gpd; bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDframe *actframe = active_gpl->actframe; + Object *ob = CTX_data_active_object(C); /* save initial factor for active layer to define shift limits */ tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1); @@ -255,7 +269,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) bGPDstroke *gps_to; int fFrame; - bGPDstroke *new_stroke; + bGPDstroke *new_stroke = NULL; bool valid = true; @@ -269,7 +283,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) { + if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) { valid = false; } @@ -281,16 +295,13 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) } /* create new stroke */ - new_stroke = MEM_dupallocN(gps_from); - new_stroke->points = MEM_dupallocN(gps_from->points); - new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - new_stroke->tot_triangles = 0; - new_stroke->flag |= GP_STROKE_RECALC_CACHES; + new_stroke = BKE_gpencil_stroke_duplicate(gps_from); if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); + new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints); new_stroke->totpoints = gps_to->totpoints; new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; @@ -302,6 +313,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ new_stroke->totpoints = 0; new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); + new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert)); new_stroke->tot_triangles = 0; new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); new_stroke->flag |= GP_STROKE_RECALC_CACHES; @@ -317,17 +329,17 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) /* Drawing Callbacks */ /* Drawing callback for modal operator in screen mode */ -static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +static void gpencil_interpolate_draw_screen(const struct bContext *C, ARegion *UNUSED(ar), void *arg) { tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); + ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_PIXEL); } /* Drawing callback for modal operator in 3d mode */ -static void gpencil_interpolate_draw_3d(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +static void gpencil_interpolate_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg) { tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); + ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW); } /* ----------------------- */ @@ -392,6 +404,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi = op->customdata; tGPDinterpolate_layer *tgpil; + bGPdata *gpd = tgpi->gpd; /* don't assume that operator data exists at all */ if (tgpi) { @@ -416,6 +429,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) BLI_freelistN(&tgpi->ilayers); MEM_freeN(tgpi); } + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* clear pointer */ @@ -483,9 +497,10 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op) static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmWindow *win = CTX_wm_window(C); - Scene *scene = CTX_data_scene(C); bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); bGPDframe *actframe = gpl->actframe; tGPDinterpolate *tgpi = NULL; @@ -496,7 +511,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent } /* cannot interpolate in extremes */ - if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) { + if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) { BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); return OPERATOR_CANCELLED; } @@ -529,6 +544,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent /* update shift indicator in header */ gpencil_interpolate_status_indicators(C, tgpi); + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* add a modal handler for this operator */ @@ -571,6 +587,8 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent /* make copy of source stroke, then adjust pointer to points too */ gps_dst = MEM_dupallocN(gps_src); gps_dst->points = MEM_dupallocN(gps_src->points); + gps_dst->dvert = MEM_dupallocN(gps_src->dvert); + BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); gps_dst->triangles = MEM_dupallocN(gps_src->triangles); gps_dst->flag |= GP_STROKE_RECALC_CACHES; BLI_addtail(&gpf_dst->strokes, gps_dst); @@ -902,8 +920,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDframe *actframe = active_gpl->actframe; - Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); ToolSettings *ts = CTX_data_tool_settings(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate; eGP_Interpolate_SettingsFlag flag = ipo_settings->flag; @@ -913,7 +934,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } /* cannot interpolate in extremes */ - if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) { + if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) { BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); return OPERATOR_CANCELLED; } @@ -961,7 +982,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) /* create new strokes data with interpolated points reading original stroke */ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { - bGPDstroke *new_stroke; + bGPDstroke *new_stroke = NULL; /* only selected */ if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { @@ -972,7 +993,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) continue; } /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { + if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) { continue; } @@ -990,15 +1011,15 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* create new stroke */ - new_stroke = MEM_dupallocN(gps_from); - new_stroke->points = MEM_dupallocN(gps_from->points); - new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - new_stroke->tot_triangles = 0; - new_stroke->flag |= GP_STROKE_RECALC_CACHES; + new_stroke = BKE_gpencil_stroke_duplicate(gps_from); /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { + /* free weights of removed points */ + BKE_defvert_array_free_elems(gps_from->dvert + gps_to->totpoints, gps_from->totpoints - gps_to->totpoints); + new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); + new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints); new_stroke->totpoints = gps_to->totpoints; new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; @@ -1014,6 +1035,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; @@ -1055,6 +1077,8 @@ static bool gpencil_interpolate_reverse_poll(bContext *C) static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + /* Go through each layer, deleting the breakdowns around the current frame, * but only if there is a keyframe nearby to stop at */ @@ -1123,6 +1147,7 @@ static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) CTX_DATA_END; /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/gpencil/gpencil_old.c b/source/blender/editors/gpencil/gpencil_old.c new file mode 100644 index 00000000000..b7af1c80d4c --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_old.c @@ -0,0 +1,219 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation, + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + * Use deprecated data to convert old 2.7x files + */ + +/** \file blender/editors/gpencil/gpencil_old.c + * \ingroup edgpencil + */ + + /* allow to use deprecated functionality */ +#define DNA_DEPRECATED_ALLOW + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_main.h" +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_object.h" +#include "BKE_material.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_gpencil.h" + +#include "gpencil_intern.h" + + /* Free all of a gp-colors */ +static void free_gpencil_colors(bGPDpalette *palette) +{ + /* error checking */ + if (palette == NULL) { + return; + } + + /* free colors */ + BLI_freelistN(&palette->colors); +} + +/* Free all of the gp-palettes and colors */ +static void free_palettes(ListBase *list) +{ + bGPDpalette *palette_next; + + /* error checking */ + if (list == NULL) { + return; + } + + /* delete palettes */ + for (bGPDpalette *palette = list->first; palette; palette = palette_next) { + palette_next = palette->next; + /* free palette colors */ + free_gpencil_colors(palette); + + MEM_freeN(palette); + } + BLI_listbase_clear(list); +} + +/* ***************** Convert old 2.7 files to 2.8 ************************ */ +static bool gpencil_convert_old_files_poll(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + + return (int) (scene->gpd != NULL); +} + +static int gpencil_convert_old_files_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = CTX_data_tool_settings(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + + /* Convert grease pencil scene datablock to GP object */ + if ((scene->gpd) && (view_layer != NULL)) { + Object *ob; + ob = BKE_object_add_for_data(bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false); + zero_v3(ob->loc); + + Paint *paint = BKE_brush_get_gpencil_paint(ts); + /* if not exist, create a new one */ + if (paint->brush == NULL) { + /* create new brushes */ + BKE_brush_gpencil_presets(C); + } + + /* convert grease pencil palettes (version >= 2.78) to materials and weights */ + bGPdata *gpd = scene->gpd; + for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) { + for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { + + /* create material slot */ + BKE_object_material_slot_add(bmain, ob); + Material *ma = BKE_material_add_gpencil(bmain, palcolor->info); + assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING); + + /* copy color settings */ + MaterialGPencilStyle *gp_style = ma->gp_style; + copy_v4_v4(gp_style->stroke_rgba, palcolor->color); + copy_v4_v4(gp_style->fill_rgba, palcolor->fill); + gp_style->flag = palcolor->flag; + + /* fix strokes */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + if ((gps->colorname[0] != '\0') && + (STREQ(gps->colorname, palcolor->info))) + { + gps->mat_nr = ob->totcol - 1; + gps->colorname[0] = '\0'; + /* create weights array */ + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); + } + } + } + } + } + } + + /* free palettes */ + free_palettes(&gpd->palettes); + + /* disable all GP modes */ + ED_gpencil_setup_modes(C, gpd, 0); + + /* set cache as dirty */ + BKE_gpencil_batch_cache_dirty(ob->data); + + scene->gpd = NULL; + } + +#if 0 /* GPXX */ + /* Handle object-linked grease pencil datablocks */ + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->gpd) { + if (ob->type == OB_GPENCIL) { + /* GP Object - remap the links */ + ob->data = ob->gpd; + ob->gpd = NULL; + } + else if (ob->type == OB_EMPTY) { + /* Empty with GP data - This should be able to be converted + * to a GP object with little data loss + */ + ob->data = ob->gpd; + ob->gpd = NULL; + ob->type = OB_GPENCIL; + } + else { + /* FIXME: What to do in this case? + * + * We cannot create new objects for these, as we don't have a scene & scene layer + * to put them into from here... + */ + printf("WARNING: Old Grease Pencil data ('%s') still exists on Object '%s'\n", + ob->gpd->id.name + 2, ob->id.name + 2); + } + } + } +#endif + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_convert_old_files(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Convert 2.7 Grease Pencil File"; + ot->idname = "GPENCIL_OT_convert_old_files"; + ot->description = "Convert 2.7x grease pencil files to 2.8"; + + /* callbacks */ + ot->exec = gpencil_convert_old_files_exec; + ot->poll = gpencil_convert_old_files_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 3f114a4dd4a..991bfb622b7 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -35,8 +35,14 @@ #include "BLI_sys_types.h" #include "BKE_context.h" +#include "BKE_brush.h" +#include "BKE_gpencil.h" +#include "DNA_brush_types.h" #include "DNA_gpencil_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "WM_api.h" #include "WM_types.h" @@ -52,7 +58,7 @@ /* ****************************************** */ /* Grease Pencil Keymaps */ -/* Generic Drawing Keymap */ +/* Generic Drawing Keymap - Annotations */ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil", 0, 0); @@ -60,36 +66,22 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) /* Draw --------------------------------------- */ /* draw */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, DKEY); + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", LEFTMOUSE, KM_PRESS, 0, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); RNA_boolean_set(kmi->ptr, "wait_for_input", false); /* draw - straight lines */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, DKEY); + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", LEFTMOUSE, KM_PRESS, KM_ALT, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT); RNA_boolean_set(kmi->ptr, "wait_for_input", false); /* draw - poly lines */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, KM_CTRL, DKEY); + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", LEFTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY); RNA_boolean_set(kmi->ptr, "wait_for_input", false); /* erase */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, 0, DKEY); - RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); - - /* Tablet Mappings for Drawing ------------------ */ - /* For now, only support direct drawing using the eraser, as most users using a tablet - * may still want to use that as their primary pointing device! - */ -#if 0 - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_STYLUS, KM_PRESS, 0, 0); - RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); -#endif - - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0); + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_annotate", RIGHTMOUSE, KM_PRESS, 0, DKEY); RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); RNA_boolean_set(kmi->ptr, "wait_for_input", false); @@ -121,67 +113,85 @@ static bool gp_stroke_editmode_poll(bContext *C) return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)); } -/* Stroke Editing Keymap - Only when editmode is enabled */ -static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) +/* Poll callback for stroke painting mode */ +static bool gp_stroke_paintmode_poll(bContext *C) { - wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0); - wmKeyMapItem *kmi; - - /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */ - keymap->poll = gp_stroke_editmode_poll; - - /* ----------------------------------------------- */ - - /* Exit EditMode */ - WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0); - - /* Pie Menu - For settings/tools easy access */ - WM_keymap_add_menu_pie(keymap, "GPENCIL_MT_pie_sculpt", EKEY, KM_PRESS, 0, DKEY); - - /* Brush Settings */ - /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys - * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain - * that the only data being edited is that of the Grease Pencil strokes - */ - - /* CTRL + FKEY = Eraser Radius */ - kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0); - RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius"); - - /* Interpolation */ - WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + /* TODO: limit this to mode, but review 2D editors */ + bGPdata *gpd = CTX_data_gpencil_data(C); + return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE)); +} - /* Sculpting ------------------------------------- */ +/* Poll callback for stroke painting (draw brush) */ +static bool gp_stroke_paintmode_draw_poll(bContext *C) +{ + /* TODO: limit this to mode, but review 2D editors */ + bGPdata *gpd = CTX_data_gpencil_data(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = BKE_brush_getactive_gpencil(ts); + return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) + && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW)); +} - /* Brush-Based Editing: - * EKEY + LMB = Single stroke, draw immediately - * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc. - * - * For the modal version, use D+E -> Sculpt - */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, EKEY); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); +/* Poll callback for stroke painting (erase brush) */ +static bool gp_stroke_paintmode_erase_poll(bContext *C) +{ + /* TODO: limit this to mode, but review 2D editors */ + bGPdata *gpd = CTX_data_gpencil_data(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = BKE_brush_getactive_gpencil(ts); + return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) + && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)); +} - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, EKEY); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); - /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/ +/* Poll callback for stroke painting (fill) */ +static bool gp_stroke_paintmode_fill_poll(bContext *C) +{ + /* TODO: limit this to mode, but review 2D editors */ + bGPdata *gpd = CTX_data_gpencil_data(C); + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = BKE_brush_getactive_gpencil(ts); + return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) + && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_FILL)); +} - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, EKEY); - RNA_boolean_set(kmi->ptr, "wait_for_input", false); - /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/ +/* Poll callback for stroke sculpting mode */ +static bool gp_stroke_sculptmode_poll(bContext *C) +{ + bGPdata *gpd = CTX_data_gpencil_data(C); + Object *ob = CTX_data_active_object(C); + ScrArea *sa = CTX_wm_area(C); + + /* if not gpencil object and not view3d, need sculpt keys if edit mode */ + if (sa->spacetype != SPACE_VIEW3D) { + return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); + } + else { + /* weight paint is a submode of sculpt */ + if ((ob) && (ob->type == OB_GPENCIL)) { + return GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd); + } + } + + return 0; +} +/* Poll callback for stroke weight paint mode */ +static bool gp_stroke_weightmode_poll(bContext *C) +{ + bGPdata *gpd = CTX_data_gpencil_data(C); + Object *ob = CTX_data_active_object(C); - /* Shift-FKEY = Sculpt Strength */ - kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0); - RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength"); + if ((ob) && (ob->type == OB_GPENCIL)) { + return (gpd && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)); + } - /* FKEY = Sculpt Brush Size */ - kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size"); + return 0; +} +static void ed_keymap_gpencil_selection(wmKeyMap *keymap) +{ + wmKeyMapItem *kmi; - /* Selection ------------------------------------- */ /* select all */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0); RNA_enum_set(kmi->ptr, "action", SEL_SELECT); @@ -204,17 +214,14 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) RNA_boolean_set(kmi->ptr, "deselect", true); /* In the Node Editor, lasso select needs ALT modifier too (as somehow CTRL+LMB drag gets taken for "cut" quite early) - * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey - * combo doesn't seem to see much use under standard scenarios? - */ + * There probably isn't too much harm adding this for other editors too as part of standard GP editing keymap. This hotkey + * combo doesn't seem to see much use under standard scenarios? + */ kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "deselect", false); kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "deselect", true); - /* normal select */ - WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "extend", true); RNA_boolean_set(kmi->ptr, "toggle", true); @@ -223,11 +230,18 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "entire_strokes", true); + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "entire_strokes", true); + RNA_boolean_set(kmi->ptr, "extend", true); + /* select linked */ /* NOTE: While LKEY is redundant, not having it breaks the mode illusion too much */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0); + /* select alternate */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select_alternate", LKEY, KM_PRESS, KM_SHIFT, 0); + /* select grouped */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0); @@ -235,6 +249,102 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); +} + +static void ed_keymap_gpencil_sculpt(wmKeyMap *keymap) +{ + wmKeyMapItem *kmi; + + /* Pie Menu - For settings/tools easy access */ + WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_sculpt", EKEY, KM_PRESS, 0, DKEY); + + /* Sculpting ------------------------------------- */ + + /* Brush-Based Editing: + * EKEY + LMB = Single stroke, draw immediately + * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc. + * + * For the modal version, use D+E -> Sculpt + */ + /* GPXX: disabled to make toolsystem works */ + //kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, 0); + //RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + RNA_boolean_set(kmi->ptr, "keep_brush", true); + /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/ + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + RNA_boolean_set(kmi->ptr, "keep_brush", true); + /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/ + + /* Shift-FKEY = Sculpt Strength */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.strength"); + + /* FKEY = Sculpt Brush Size */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.brush.size"); + + /* menu sculpt specials */ + WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_sculpt_specials", WKEY, KM_PRESS, 0, 0); +} + +static void ed_keymap_gpencil_weight(wmKeyMap *keymap) +{ + wmKeyMapItem *kmi; + + + /* Brush-Based Editing: + * EKEY + LMB = Single stroke, draw immediately + * + Other Modifiers (Ctrl/Shift) = Invert, Smooth, etc. + * + * For the modal version, use D+E -> Sculpt + */ + /* GPXX: disabled to make toolsystem works */ + //kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, 0, 0); + //RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + RNA_boolean_set(kmi->ptr, "keep_brush", true); + /*RNA_boolean_set(kmi->ptr, "use_invert", true);*/ + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_brush_paint", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + RNA_boolean_set(kmi->ptr, "keep_brush", true); + /*RNA_boolean_set(kmi->ptr, "use_smooth", true);*/ +} + +/* Stroke Editing Keymap - Only when editmode is enabled */ +static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */ + keymap->poll = gp_stroke_editmode_poll; + + /* ----------------------------------------------- */ + + /* Brush Settings */ + /* NOTE: We cannot expose these in the standard keymap, as they will interfere with regular hotkeys + * in other modes. However, when we are dealing with Stroke Edit Mode, we know for certain + * that the only data being edited is that of the Grease Pencil strokes + */ + + /* Interpolation */ + WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0); + + /* normal select */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); + + /* Selection */ + ed_keymap_gpencil_selection(keymap); + /* Editing ----------------------------------------- */ /* duplicate and move selected points */ @@ -253,6 +363,12 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) /* menu edit specials */ WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_edit_specials", WKEY, KM_PRESS, 0, 0); + /* menu separate */ + WM_keymap_add_menu(keymap, "GPENCIL_MT_separate", PKEY, KM_PRESS, 0, 0); + + /* split strokes */ + WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_split", VKEY, KM_PRESS, 0, 0); + /* join strokes */ WM_keymap_add_item(keymap, "GPENCIL_OT_stroke_join", JKEY, KM_PRESS, KM_CTRL, 0); @@ -271,7 +387,6 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) /* snap */ WM_keymap_add_menu(keymap, "GPENCIL_MT_snap", SKEY, KM_PRESS, KM_SHIFT, 0); - /* convert to geometry */ WM_keymap_add_item(keymap, "GPENCIL_OT_convert", CKEY, KM_PRESS, KM_ALT, 0); @@ -288,6 +403,13 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0); + /* toogle multiedit support */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "toggle_visibility", 0); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "toggle_visibility", 1); + /* Isolate Layer */ WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0); @@ -317,28 +439,246 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) /* Proportional Editing */ ED_keymap_proportional_cycle(keyconf, keymap); ED_keymap_proportional_editmode(keyconf, keymap, true); + + /* menu - add GP object (3d view only) */ + WM_keymap_add_item(keymap, "OBJECT_OT_gpencil_add", AKEY, KM_PRESS, KM_SHIFT, 0); + + /* menu vertex group */ + WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_vertex_group", GKEY, KM_PRESS, KM_CTRL, 0); + + /* toggle edit mode */ + WM_keymap_add_item(keymap, "GPENCIL_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0); +} + +/* keys for draw with a drawing brush (no fill) */ +static void ed_keymap_gpencil_painting_draw(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback */ + keymap->poll = gp_stroke_paintmode_draw_poll; + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + /* draw - straight lines */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_ALT, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + /* draw - poly lines */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + /* erase */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + /* Tablet Mappings for Drawing ------------------ */ + /* For now, only support direct drawing using the eraser, as most users using a tablet + * may still want to use that as their primary pointing device! + */ +#if 0 + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_STYLUS, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); +#endif + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + /* Selection (used by eraser) */ + /* border select */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0); + + /* lasso select */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); +} + +/* keys for draw with a eraser brush (erase) */ +static void ed_keymap_gpencil_painting_erase(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint (Erase)", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback */ + keymap->poll = gp_stroke_paintmode_erase_poll; + + /* erase */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", TABLET_ERASER, KM_PRESS, 0, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + + /* Selection (used by eraser) */ + /* border select */ + WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0); + + /* lasso select */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); +} + +/* keys for draw with a fill brush */ +static void ed_keymap_gpencil_painting_fill(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint (Fill)", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback */ + keymap->poll = gp_stroke_paintmode_fill_poll; + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_fill", LEFTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "on_back", false); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_fill", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "on_back", true); + + /* if press alternative key, the brush now it's for drawing areas */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + /* disable straight lines */ + RNA_boolean_set(kmi->ptr, "disable_straight", true); + + /* if press alternative key, the brush now it's for drawing lines */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_ALT, 0); + RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW); + RNA_boolean_set(kmi->ptr, "wait_for_input", false); + /* disable straight lines */ + RNA_boolean_set(kmi->ptr, "disable_straight", true); + /* enable special stroke with no fill flag */ + RNA_boolean_set(kmi->ptr, "disable_fill", true); +} + +/* Stroke Painting Keymap - Only when paintmode is enabled */ +static void ed_keymap_gpencil_painting(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Paint Mode", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback - so that this keymap only gets enabled when stroke paintmode is enabled */ + keymap->poll = gp_stroke_paintmode_poll; + + /* FKEY = Brush Size */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_paint.brush.size"); + + /* CTRL + FKEY = Eraser Radius */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius"); + + /* menu draw specials */ + WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_draw_specials", WKEY, KM_PRESS, 0, 0); + + /* menu draw delete */ + WM_keymap_add_menu(keymap, "GPENCIL_MT_gpencil_draw_delete", XKEY, KM_PRESS, 0, 0); + } +/* Stroke Sculpting Keymap - Only when sculptmode is enabled */ +static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Sculpt Mode", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */ + keymap->poll = gp_stroke_sculptmode_poll; + + /* Selection */ + ed_keymap_gpencil_selection(keymap); + + /* sculpt */ + ed_keymap_gpencil_sculpt(keymap); + + /* toogle multiedit support */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "toggle_visibility", 0); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "toggle_visibility", 1); + +} + +/* Stroke Weight Paint Keymap - Only when weight is enabled */ +static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf) +{ + wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Weight Mode", 0, 0); + wmKeyMapItem *kmi; + + /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */ + keymap->poll = gp_stroke_weightmode_poll; + + /* Selection */ + ed_keymap_gpencil_selection(keymap); + + /* sculpt */ + ed_keymap_gpencil_weight(keymap); + + /* Shift-FKEY = Sculpt Strength */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.weight_brush.strength"); + + /* FKEY = Sculpt Brush Size */ + kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.weight_brush.size"); + + /* toogle multiedit support */ + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0); + RNA_boolean_set(kmi->ptr, "toggle_visibility", 0); + + kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "toggle_visibility", 1); + +} /* ==================== */ void ED_keymap_gpencil(wmKeyConfig *keyconf) { ed_keymap_gpencil_general(keyconf); ed_keymap_gpencil_editing(keyconf); + ed_keymap_gpencil_painting(keyconf); + ed_keymap_gpencil_painting_draw(keyconf); + ed_keymap_gpencil_painting_erase(keyconf); + ed_keymap_gpencil_painting_fill(keyconf); + ed_keymap_gpencil_sculpting(keyconf); + ed_keymap_gpencil_weightpainting(keyconf); } /* ****************************************** */ void ED_operatortypes_gpencil(void) { + /* Annotations -------------------- */ + + WM_operatortype_append(GPENCIL_OT_annotate); + /* Drawing ----------------------- */ WM_operatortype_append(GPENCIL_OT_draw); + WM_operatortype_append(GPENCIL_OT_fill); /* Editing (Strokes) ------------ */ WM_operatortype_append(GPENCIL_OT_editmode_toggle); + WM_operatortype_append(GPENCIL_OT_paintmode_toggle); + WM_operatortype_append(GPENCIL_OT_sculptmode_toggle); + WM_operatortype_append(GPENCIL_OT_weightmode_toggle); WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle); + WM_operatortype_append(GPENCIL_OT_multiedit_toggle); WM_operatortype_append(GPENCIL_OT_select); WM_operatortype_append(GPENCIL_OT_select_all); @@ -352,6 +692,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_select_less); WM_operatortype_append(GPENCIL_OT_select_first); WM_operatortype_append(GPENCIL_OT_select_last); + WM_operatortype_append(GPENCIL_OT_select_alternate); WM_operatortype_append(GPENCIL_OT_duplicate); WM_operatortype_append(GPENCIL_OT_delete); @@ -391,6 +732,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_active_frame_delete); WM_operatortype_append(GPENCIL_OT_active_frames_delete_all); + WM_operatortype_append(GPENCIL_OT_frame_duplicate); + WM_operatortype_append(GPENCIL_OT_frame_clean_fill); WM_operatortype_append(GPENCIL_OT_convert); @@ -402,36 +745,46 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_stroke_join); WM_operatortype_append(GPENCIL_OT_stroke_flip); WM_operatortype_append(GPENCIL_OT_stroke_subdivide); + WM_operatortype_append(GPENCIL_OT_stroke_simplify); + WM_operatortype_append(GPENCIL_OT_stroke_simplify_fixed); + WM_operatortype_append(GPENCIL_OT_stroke_separate); + WM_operatortype_append(GPENCIL_OT_stroke_split); - WM_operatortype_append(GPENCIL_OT_palette_add); - WM_operatortype_append(GPENCIL_OT_palette_remove); - WM_operatortype_append(GPENCIL_OT_palette_change); - WM_operatortype_append(GPENCIL_OT_palette_lock_layer); - WM_operatortype_append(GPENCIL_OT_palettecolor_add); - WM_operatortype_append(GPENCIL_OT_palettecolor_remove); - WM_operatortype_append(GPENCIL_OT_palettecolor_isolate); - WM_operatortype_append(GPENCIL_OT_palettecolor_hide); - WM_operatortype_append(GPENCIL_OT_palettecolor_reveal); - WM_operatortype_append(GPENCIL_OT_palettecolor_lock_all); - WM_operatortype_append(GPENCIL_OT_palettecolor_unlock_all); - WM_operatortype_append(GPENCIL_OT_palettecolor_move); - WM_operatortype_append(GPENCIL_OT_palettecolor_select); - WM_operatortype_append(GPENCIL_OT_palettecolor_copy); - - WM_operatortype_append(GPENCIL_OT_brush_add); - WM_operatortype_append(GPENCIL_OT_brush_remove); - WM_operatortype_append(GPENCIL_OT_brush_change); - WM_operatortype_append(GPENCIL_OT_brush_move); WM_operatortype_append(GPENCIL_OT_brush_presets_create); - WM_operatortype_append(GPENCIL_OT_brush_copy); WM_operatortype_append(GPENCIL_OT_brush_select); + WM_operatortype_append(GPENCIL_OT_sculpt_select); + + /* vertex groups */ + WM_operatortype_append(GPENCIL_OT_vertex_group_assign); + WM_operatortype_append(GPENCIL_OT_vertex_group_remove_from); + WM_operatortype_append(GPENCIL_OT_vertex_group_select); + WM_operatortype_append(GPENCIL_OT_vertex_group_deselect); + WM_operatortype_append(GPENCIL_OT_vertex_group_invert); + WM_operatortype_append(GPENCIL_OT_vertex_group_smooth); + + /* color handle */ + WM_operatortype_append(GPENCIL_OT_lock_layer); + WM_operatortype_append(GPENCIL_OT_color_isolate); + WM_operatortype_append(GPENCIL_OT_color_hide); + WM_operatortype_append(GPENCIL_OT_color_reveal); + WM_operatortype_append(GPENCIL_OT_color_lock_all); + WM_operatortype_append(GPENCIL_OT_color_unlock_all); + WM_operatortype_append(GPENCIL_OT_color_select); + /* Editing (Time) --------------- */ /* Interpolation */ WM_operatortype_append(GPENCIL_OT_interpolate); WM_operatortype_append(GPENCIL_OT_interpolate_sequence); WM_operatortype_append(GPENCIL_OT_interpolate_reverse); + + /* Primitives */ + WM_operatortype_append(GPENCIL_OT_primitive); + + /* convert old 2.7 files to 2.8 */ + WM_operatortype_append(GPENCIL_OT_convert_old_files); + } void ED_operatormacros_gpencil(void) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 789e9865ae4..995ab91ff8b 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -46,26 +46,34 @@ #include "PIL_time.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_material_types.h" +#include "DNA_brush_types.h" +#include "DNA_windowmanager_types.h" + #include "BKE_colortools.h" +#include "BKE_main.h" +#include "BKE_brush.h" +#include "BKE_paint.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_main.h" #include "BKE_paint.h" #include "BKE_report.h" +#include "BKE_layer.h" +#include "BKE_material.h" #include "BKE_screen.h" #include "BKE_tracking.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_gpencil_types.h" -#include "DNA_brush_types.h" -#include "DNA_windowmanager_types.h" - #include "UI_view2d.h" #include "ED_gpencil.h" #include "ED_screen.h" +#include "ED_object.h" #include "ED_view3d.h" #include "ED_clip.h" @@ -82,6 +90,7 @@ #include "WM_types.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "gpencil_intern.h" @@ -110,6 +119,8 @@ typedef enum eGPencil_PaintFlags { GP_PAINTFLAG_STROKEADDED = (1 << 1), GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2), GP_PAINTFLAG_SELECTMASK = (1 << 3), + GP_PAINTFLAG_HARD_ERASER = (1 << 4), + GP_PAINTFLAG_STROKE_ERASER = (1 << 5), } eGPencil_PaintFlags; @@ -117,10 +128,13 @@ typedef enum eGPencil_PaintFlags { * "p" = op->customdata */ typedef struct tGPsdata { - Main *bmain; + bContext *C; + + Main *bmain; /* main database pointer */ Scene *scene; /* current scene from context */ struct Depsgraph *depsgraph; + Object *ob; /* current object */ wmWindow *win; /* window where painting originated */ ScrArea *sa; /* area where painting originated */ ARegion *ar; /* region where painting originated */ @@ -165,14 +179,23 @@ typedef struct tGPsdata { void *erasercursor; /* radial cursor data for drawing eraser */ - bGPDpalettecolor *palettecolor; /* current palette color */ - bGPDbrush *brush; /* current drawing brush */ + /* mat settings are only used for 3D view */ + Material *material; /* current material */ + + Brush *brush; /* current drawing brush */ + Brush *eraser; /* default eraser brush */ short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */ int lock_axis; /* lock drawing to one axis */ + bool disable_fill; /* the stroke is no fill mode */ RNG *rng; short keymodifier; /* key used for invoking the operator */ + short shift; /* shift modifier flag */ + + float totpixlen; /* size in pixels for uv calculation */ + + ReportList *reports; } tGPsdata; /* ------ */ @@ -183,6 +206,14 @@ typedef struct tGPsdata { /* minimum length of new segment before new point can be added */ #define MIN_EUCLIDEAN_PX (U.gp_euclideandist) +static void gp_update_cache(bGPdata *gpd) +{ + if (gpd) { + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + gpd->flag |= GP_DATA_CACHE_IS_DIRTY; + } +} + static bool gp_stroke_added_check(tGPsdata *p) { return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED); @@ -192,6 +223,9 @@ static void gp_stroke_added_enable(tGPsdata *p) { BLI_assert(p->gpf->strokes.last != NULL); p->flags |= GP_PAINTFLAG_STROKEADDED; + + /* drawing batch cache is dirty now */ + gp_update_cache(p->gpd); } /* ------ */ @@ -206,30 +240,42 @@ static void gp_session_validatebuffer(tGPsdata *p); static bool gpencil_draw_poll(bContext *C) { if (ED_operator_regionactive(C)) { - /* check if current context can support GPencil data */ - if (ED_gpencil_data_get_pointers(C, NULL) != NULL) { - /* check if Grease Pencil isn't already running */ - if (ED_gpencil_session_active() == 0) - return 1; - else - CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active"); + ScrArea *sa = CTX_wm_area(C); + if (!ELEM(sa->spacetype, SPACE_VIEW3D)) { + /* check if current context can support GPencil data */ + if (ED_gpencil_data_get_pointers(C, NULL) != NULL) { + /* check if Grease Pencil isn't already running */ + if (ED_gpencil_session_active() == 0) + return 1; + else + CTX_wm_operator_poll_msg_set(C, "Grease Pencil operator is already active"); + } + else { + CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into"); + } + return 0; } + /* 3D Viewport */ else { - CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into"); + if (ED_gpencil_session_active() == 0) { + return 1; + } + else { + return 0; + } } } else { CTX_wm_operator_poll_msg_set(C, "Active region not set"); + return 0; } - - return 0; } /* check if projecting strokes into 3d-geometry in the 3D-View */ static bool gpencil_project_check(tGPsdata *p) { bGPdata *gpd = p->gpd; - return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE))); + return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) && (*p->align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE))); } /* ******************************************* */ @@ -241,38 +287,39 @@ static bool gpencil_project_check(tGPsdata *p) static void gp_get_3d_reference(tGPsdata *p, float vec[3]) { View3D *v3d = p->sa->spacedata.first; - const float *fp = ED_view3d_cursor3d_get(p->scene, v3d)->location; - - /* the reference point used depends on the owner... */ -#if 0 /* XXX: disabled for now, since we can't draw relative to the owner yet */ + Object *ob = NULL; if (p->ownerPtr.type == &RNA_Object) { - Object *ob = (Object *)p->ownerPtr.data; - - /* active Object - * - use relative distance of 3D-cursor from object center - */ - sub_v3_v3v3(vec, fp, ob->loc); - } - else -#endif - { - /* use 3D-cursor */ - copy_v3_v3(vec, fp); + ob = (Object *)p->ownerPtr.data; } + ED_gp_get_drawing_reference(v3d, p->scene, ob, p->gpl, *p->align_flag, vec); } /* Stroke Editing ---------------------------- */ - /* check if the current mouse position is suitable for adding a new point */ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) { + Brush *brush = p->brush; int dx = abs(mval[0] - pmval[0]); int dy = abs(mval[1] - pmval[1]); + brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP; /* if buffer is empty, just let this go through (i.e. so that dots will work) */ - if (p->gpd->sbuffer_size == 0) + if (p->gpd->runtime.sbuffer_size == 0) { return true; - + } + /* if lazy mouse, check minimum distance */ + else if (GPENCIL_LAZY_MODE(brush, p->shift)) { + brush->gpencil_settings->flag |= GP_BRUSH_STABILIZE_MOUSE_TEMP; + if ((dx * dx + dy * dy) > (brush->smooth_stroke_radius * brush->smooth_stroke_radius)) { + return true; + } + else { + /* If the mouse is moving within the radius of the last move, + * don't update the mouse position. This allows sharp turns. */ + copy_v2_v2_int(p->mval, p->mvalo); + return false; + } + } /* check if mouse moved at least certain distance on both axes (best case) * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand */ @@ -291,47 +338,17 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) return false; } -/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */ -static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis) -{ - float plane_normal[3]; - float vn[3]; - - float ray[3]; - float rpoint[3]; - - /* normal vector for a plane locked to axis */ - zero_v3(plane_normal); - plane_normal[axis] = 1.0f; - - /* Reproject the points in the plane */ - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - - /* get a vector from the point with the current view direction of the viewport */ - ED_view3d_global_to_vector(rv3d, &pt->x, vn); - - /* calculate line extrem point to create a ray that cross the plane */ - mul_v3_fl(vn, -50.0f); - add_v3_v3v3(ray, &pt->x, vn); - - /* if the line never intersect, the point is not changed */ - if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) { - copy_v3_v3(&pt->x, rpoint); - } - } -} - /* reproject stroke to plane locked to axis in 3d cursor location */ static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) { bGPdata *gpd = p->gpd; + Object *obact = (Object *)p->ownerPtr.data; + float origin[3]; - float cursor[3]; RegionView3D *rv3d = p->ar->regiondata; /* verify the stroke mode is CURSOR 3d space mode */ - if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) { + if ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) == 0) { return; } if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { @@ -341,12 +358,9 @@ static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) return; } - /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */ - gp_get_3d_reference(p, cursor); - zero_v3(origin); - origin[p->lock_axis - 1] = cursor[p->lock_axis - 1]; - - gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1); + /* get drawing origin */ + gp_get_3d_reference(p, origin); + ED_gp_project_stroke_to_plane(obact, rv3d, gps, origin, p->lock_axis - 1); } /* convert screen-coordinates to buffer-coordinates */ @@ -356,7 +370,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] bGPdata *gpd = p->gpd; /* in 3d-space - pt->x/y/z are 3 side-by-side floats */ - if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) { + if (gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) { if (gpencil_project_check(p) && (ED_view3d_autodist_simple(p->ar, mval, out, 0, depth))) { /* projecting onto 3D-Geometry * - nothing more needs to be done here, since view_autodist_simple() has already done it @@ -365,7 +379,8 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] else { float mval_prj[2]; float rvec[3], dvec[3]; - float mval_f[2] = {UNPACK2(mval)}; + float mval_f[2]; + copy_v2fl_v2i(mval_f, mval); float zfac; /* Current method just converts each point in screen-coordinates to @@ -390,42 +405,23 @@ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3] } } } - - /* 2d - on 'canvas' (assume that p->v2d is set) */ - else if ((gpd->sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) { - UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]); - mul_v3_m4v3(out, p->imat, out); - } - - /* 2d - relative to screen (viewport area) */ - else { - if (p->subrect == NULL) { /* normal 3D view */ - out[0] = (float)(mval[0]) / (float)(p->ar->winx) * 100; - out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100; - } - else { /* camera view, use subrect */ - out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100; - out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100; - } - } } /* apply jitter to stroke */ -static void gp_brush_jitter( - bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2], int r_mval[2], RNG *rng) +static void gp_brush_jitter(bGPdata *gpd, Brush *brush, tGPspoint *pt, const int mval[2], int r_mval[2], RNG *rng) { float pressure = pt->pressure; float tmp_pressure = pt->pressure; - if (brush->draw_jitter > 0.0f) { - float curvef = curvemapping_evaluateF(brush->cur_jitter, 0, pressure); - tmp_pressure = curvef * brush->draw_sensitivity; + if (brush->gpencil_settings->draw_jitter > 0.0f) { + float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, pressure); + tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity; } - const float exfactor = (brush->draw_jitter + 2.0f) * (brush->draw_jitter + 2.0f); /* exponential value */ + const float exfactor = (brush->gpencil_settings->draw_jitter + 2.0f) * (brush->gpencil_settings->draw_jitter + 2.0f); /* exponential value */ const float fac = BLI_rng_get_float(rng) * exfactor * tmp_pressure; /* Jitter is applied perpendicular to the mouse movement vector (2D space) */ float mvec[2], svec[2]; /* mouse movement in ints -> floats */ - if (gpd->sbuffer_size > 1) { + if (gpd->runtime.sbuffer_size > 1) { mvec[0] = (float)(mval[0] - (pt - 1)->x); mvec[1] = (float)(mval[1] - (pt - 1)->y); normalize_v2(mvec); @@ -451,18 +447,18 @@ static void gp_brush_jitter( } /* apply pressure change depending of the angle of the stroke to simulate a pen with shape */ -static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const int mval[2]) +static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const int mval[2]) { float mvec[2]; - float sen = brush->draw_angle_factor; /* sensitivity */; + float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */; float fac; float mpressure; - float angle = brush->draw_angle; /* default angle of brush in radians */; + float angle = brush->gpencil_settings->draw_angle; /* default angle of brush in radians */; float v0[2] = { cos(angle), sin(angle) }; /* angle vector of the brush with full thickness */ /* Apply to first point (only if there are 2 points because before no data to do it ) */ - if (gpd->sbuffer_size == 1) { + if (gpd->runtime.sbuffer_size == 1) { mvec[0] = (float)(mval[0] - (pt - 1)->x); mvec[1] = (float)(mval[1] - (pt - 1)->y); normalize_v2(mvec); @@ -475,7 +471,7 @@ static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const } /* apply from second point */ - if (gpd->sbuffer_size >= 1) { + if (gpd->runtime.sbuffer_size >= 1) { mvec[0] = (float)(mval[0] - (pt - 1)->x); mvec[1] = (float)(mval[1] - (pt - 1)->y); normalize_v2(mvec); @@ -490,21 +486,83 @@ static void gp_brush_angle(bGPdata *gpd, bGPDbrush *brush, tGPspoint *pt, const } +/* Apply smooth to buffer while drawing +* to smooth point C, use 2 before (A, B) and current point (D): +* +* A----B-----C------D +* +* \param p Temp data +* \param inf Influence factor +* \param idx Index of the last point (need minimum 3 points in the array) +*/ +static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) +{ + bGPdata *gpd = p->gpd; + short num_points = gpd->runtime.sbuffer_size; + + /* Do nothing if not enough points to smooth out */ + if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) { + return; + } + + tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer; + float steps = 4.0f; + if (idx < 4) { + steps--; + } + + tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL; + tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL; + tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL; + tGPspoint *ptd = &points[idx - 1]; + + float sco[2] = { 0.0f }; + float a[2], b[2], c[2], d[2]; + const float average_fac = 1.0f / steps; + + /* Compute smoothed coordinate by taking the ones nearby */ + if (pta) { + copy_v2fl_v2i(a, &pta->x); + madd_v2_v2fl(sco, a, average_fac); + } + if (ptb) { + copy_v2fl_v2i(b, &ptb->x); + madd_v2_v2fl(sco, b, average_fac); + } + if (ptc) { + copy_v2fl_v2i(c, &ptc->x); + madd_v2_v2fl(sco, c, average_fac); + } + if (ptd) { + copy_v2fl_v2i(d, &ptd->x); + madd_v2_v2fl(sco, d, average_fac); + } + + /* Based on influence factor, blend between original and optimal smoothed coordinate */ + interp_v2_v2v2(c, c, sco, inf); + round_v2i_v2fl(&ptc->x, c); +} + /* add current stroke-point to buffer (returns whether point was successfully added) */ static short gp_stroke_addpoint( tGPsdata *p, const int mval[2], float pressure, double curtime) { bGPdata *gpd = p->gpd; - bGPDbrush *brush = p->brush; + Brush *brush = p->brush; tGPspoint *pt; ToolSettings *ts = p->scene->toolsettings; + Object *obact = (Object *)p->ownerPtr.data; + Depsgraph *depsgraph = p->depsgraph; \ + RegionView3D *rv3d = p->ar->regiondata; + View3D *v3d = p->sa->spacedata.first; + MaterialGPencilStyle *gp_style = p->material->gp_style; /* check painting mode */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { /* straight lines only - i.e. only store start and end point in buffer */ - if (gpd->sbuffer_size == 0) { + if (gpd->runtime.sbuffer_size == 0) { /* first point in buffer (start point) */ - pt = (tGPspoint *)(gpd->sbuffer); + pt = (tGPspoint *)(gpd->runtime.sbuffer); /* store settings */ copy_v2_v2_int(&pt->x, mval); @@ -513,13 +571,13 @@ static short gp_stroke_addpoint( pt->time = (float)(curtime - p->inittime); /* increment buffer size */ - gpd->sbuffer_size++; + gpd->runtime.sbuffer_size++; } else { /* just reset the endpoint to the latest value * - assume that pointers for this are always valid... */ - pt = ((tGPspoint *)(gpd->sbuffer) + 1); + pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1); /* store settings */ copy_v2_v2_int(&pt->x, mval); @@ -528,31 +586,35 @@ static short gp_stroke_addpoint( pt->time = (float)(curtime - p->inittime); /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */ - gpd->sbuffer_size = 2; + gpd->runtime.sbuffer_size = 2; } + /* tag depsgraph to update object */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + /* can keep carrying on this way :) */ return GP_STROKEADD_NORMAL; } else if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */ /* check if still room in buffer */ - if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX) + if (gpd->runtime.sbuffer_size >= GP_STROKE_BUFFER_MAX) return GP_STROKEADD_OVERFLOW; /* get pointer to destination point */ - pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size); + pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_size); /* store settings */ /* pressure */ - if (brush->flag & GP_BRUSH_USE_PRESSURE) { - float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure); - pt->pressure = curvef * brush->draw_sensitivity; + if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) { + float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure); + pt->pressure = curvef * brush->gpencil_settings->draw_sensitivity; } else { pt->pressure = 1.0f; } + /* Apply jitter to position */ - if (brush->draw_jitter > 0.0f) { + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush->gpencil_settings->draw_jitter > 0.0f)) { int r_mval[2]; gp_brush_jitter(gpd, brush, pt, mval, r_mval, p->rng); copy_v2_v2_int(&pt->x, r_mval); @@ -561,42 +623,62 @@ static short gp_stroke_addpoint( copy_v2_v2_int(&pt->x, mval); } /* apply randomness to pressure */ - if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_PRESSURE)) { - float curvef = curvemapping_evaluateF(brush->cur_sensitivity, 0, pressure); - float tmp_pressure = curvef * brush->draw_sensitivity; + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && + (brush->gpencil_settings->draw_random_press > 0.0f)) + { + float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure); + float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity; if (BLI_rng_get_float(p->rng) > 0.5f) { - pt->pressure -= tmp_pressure * brush->draw_random_press * BLI_rng_get_float(p->rng); + pt->pressure -= tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng); } else { - pt->pressure += tmp_pressure * brush->draw_random_press * BLI_rng_get_float(p->rng); + pt->pressure += tmp_pressure * brush->gpencil_settings->draw_random_press * BLI_rng_get_float(p->rng); } CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f); } + /* apply randomness to uv texture rotation */ + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush->gpencil_settings->uv_random > 0.0f)) { + if (BLI_rng_get_float(p->rng) > 0.5f) { + pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI * -1) * brush->gpencil_settings->uv_random; + } + else { + pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI) * brush->gpencil_settings->uv_random; + } + CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); + } + else { + pt->uv_rot = 0.0f; + } + /* apply angle of stroke to brush size */ - if (brush->draw_angle_factor > 0.0f) { + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && + (brush->gpencil_settings->draw_angle_factor > 0.0f)) + { gp_brush_angle(gpd, brush, pt, mval); } /* color strength */ - if (brush->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { - float curvef = curvemapping_evaluateF(brush->cur_strength, 0, pressure); - float tmp_pressure = curvef * brush->draw_sensitivity; + if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { + float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_strength, 0, pressure); + float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity; - pt->strength = tmp_pressure * brush->draw_strength; + pt->strength = tmp_pressure * brush->gpencil_settings->draw_strength; } else { - pt->strength = brush->draw_strength; + pt->strength = brush->gpencil_settings->draw_strength; } CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); /* apply randomness to color strength */ - if ((brush->draw_random_press > 0.0f) && (brush->flag & GP_BRUSH_USE_RANDOM_STRENGTH)) { + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && + (brush->gpencil_settings->draw_random_strength > 0.0f)) + { if (BLI_rng_get_float(p->rng) > 0.5f) { - pt->strength -= pt->strength * brush->draw_random_press * BLI_rng_get_float(p->rng); + pt->strength -= pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng); } else { - pt->strength += pt->strength * brush->draw_random_press * BLI_rng_get_float(p->rng); + pt->strength += pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng); } CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); } @@ -604,11 +686,49 @@ static short gp_stroke_addpoint( /* point time */ pt->time = (float)(curtime - p->inittime); + /* point uv (only 3d view) */ + if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_size > 1)) { + float pixsize = gp_style->texture_pixsize / 1000000.0f; + tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 2; + bGPDspoint spt, spt2; + + /* get origin to reproject point */ + float origin[3]; + gp_get_3d_reference(p, origin); + /* reproject current */ + ED_gpencil_tpoint_to_point(p->ar, origin, pt, &spt); + ED_gp_project_point_to_plane(obact, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &spt); + + /* reproject previous */ + ED_gpencil_tpoint_to_point(p->ar, origin, ptb, &spt2); + ED_gp_project_point_to_plane(obact, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &spt2); + + p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize; + pt->uv_fac = p->totpixlen; + if ((gp_style) && (gp_style->sima)) { + pt->uv_fac /= gp_style->sima->gen_x; + } + } + else { + p->totpixlen = 0.0f; + pt->uv_fac = 0.0f; + } + /* increment counters */ - gpd->sbuffer_size++; + gpd->runtime.sbuffer_size++; + + /* smooth while drawing previous points with a reduction factor for previous */ + if (brush->gpencil_settings->active_smooth > 0.0f) { + for (int s = 0; s < 3; s++) { + gp_smooth_buffer(p, brush->gpencil_settings->active_smooth * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_size - s); + } + } + + /* tag depsgraph to update object */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); /* check if another operation can still occur */ - if (gpd->sbuffer_size == GP_STROKE_BUFFER_MAX) + if (gpd->runtime.sbuffer_size == GP_STROKE_BUFFER_MAX) return GP_STROKEADD_FULL; else return GP_STROKEADD_NORMAL; @@ -617,7 +737,7 @@ static short gp_stroke_addpoint( bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); /* get pointer to destination point */ - pt = (tGPspoint *)(gpd->sbuffer); + pt = (tGPspoint *)(gpd->runtime.sbuffer); /* store settings */ copy_v2_v2_int(&pt->x, mval); @@ -632,14 +752,17 @@ static short gp_stroke_addpoint( if (gp_stroke_added_check(p)) { bGPDstroke *gps = p->gpf->strokes.last; bGPDspoint *pts; + MDeformVert *dvert; /* first time point is adding to temporary buffer -- need to allocate new point in stroke */ - if (gpd->sbuffer_size == 0) { + if (gpd->runtime.sbuffer_size == 0) { gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); + gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1)); gps->totpoints++; } pts = &gps->points[gps->totpoints - 1]; + dvert = &gps->dvert[gps->totpoints - 1]; /* special case for poly lines: normally, * depth is needed only when creating new stroke from buffer, @@ -647,8 +770,6 @@ static short gp_stroke_addpoint( * so initialize depth buffer before converting coordinates */ if (gpencil_project_check(p)) { - View3D *v3d = p->sa->spacedata.first; - view3d_region_operator_needs_opengl(p->win, p->ar); ED_view3d_autodist_init( p->depsgraph, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); @@ -656,25 +777,32 @@ static short gp_stroke_addpoint( /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); - /* if axis locked, reproject to plane locked (only in 3d space) */ - if (p->lock_axis > GP_LOCKAXIS_NONE) { - gp_reproject_toplane(p, gps); - } + /* reproject to plane (only in 3d space) */ + gp_reproject_toplane(p, gps); /* if parented change position relative to parent object */ - if (gpl->parent != NULL) { - gp_apply_parent_point(gpl, pts); - } + gp_apply_parent_point(depsgraph, obact, gpd, gpl, pts); /* copy pressure and time */ pts->pressure = pt->pressure; pts->strength = pt->strength; pts->time = pt->time; + pts->uv_fac = pt->uv_fac; + pts->uv_rot = pt->uv_rot; + + dvert->totweight = 0; + dvert->dw = NULL; + /* force fill recalc */ gps->flag |= GP_STROKE_RECALC_CACHES; + /* drawing batch cache is dirty now */ + gp_update_cache(p->gpd); } /* increment counters */ - if (gpd->sbuffer_size == 0) - gpd->sbuffer_size++; + if (gpd->runtime.sbuffer_size == 0) + gpd->runtime.sbuffer_size++; + + /* tag depsgraph to update object */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); return GP_STROKEADD_NORMAL; } @@ -690,9 +818,9 @@ static short gp_stroke_addpoint( static void gp_stroke_simplify(tGPsdata *p) { bGPdata *gpd = p->gpd; - tGPspoint *old_points = (tGPspoint *)gpd->sbuffer; - short num_points = gpd->sbuffer_size; - short flag = gpd->sbuffer_sflag; + tGPspoint *old_points = (tGPspoint *)gpd->runtime.sbuffer; + short num_points = gpd->runtime.sbuffer_size; + short flag = gpd->runtime.sbuffer_sflag; short i, j; /* only simplify if simplification is enabled, and we're not doing a straight line */ @@ -707,9 +835,9 @@ static void gp_stroke_simplify(tGPsdata *p) * - firstly set sbuffer to NULL, so a new one is allocated * - secondly, reset flag after, as it gets cleared auto */ - gpd->sbuffer = NULL; + gpd->runtime.sbuffer = NULL; gp_session_validatebuffer(p); - gpd->sbuffer_sflag = flag; + gpd->runtime.sbuffer_sflag = flag; /* macro used in loop to get position of new point * - used due to the mixture of datatypes in use here @@ -766,8 +894,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) bGPDstroke *gps; bGPDspoint *pt; tGPspoint *ptc; - bGPDbrush *brush = p->brush; + MDeformVert *dvert; + Brush *brush = p->brush; ToolSettings *ts = p->scene->toolsettings; + Depsgraph *depsgraph = p->depsgraph; + Object *obact = (Object *)p->ownerPtr.data; int i, totelem; /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ @@ -777,14 +908,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) * - drawing straight-lines only requires the endpoints */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) - totelem = (gpd->sbuffer_size >= 2) ? 2 : gpd->sbuffer_size; + totelem = (gpd->runtime.sbuffer_size >= 2) ? 2 : gpd->runtime.sbuffer_size; else - totelem = gpd->sbuffer_size; + totelem = gpd->runtime.sbuffer_size; /* exit with error if no valid points from this stroke */ if (totelem == 0) { if (G.debug & G_DEBUG) - printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->sbuffer_size); + printf("Error: No valid points in stroke buffer to convert (tot=%d)\n", gpd->runtime.sbuffer_size); return; } @@ -793,6 +924,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) * interactive behavior */ if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { + /* be sure to hide any lazy cursor */ + ED_gpencil_toggle_brush_cursor(p->C, true, NULL); + if (gp_stroke_added_check(p)) { return; } @@ -803,95 +937,94 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* copy appropriate settings for stroke */ gps->totpoints = totelem; - gps->thickness = brush->thickness; - gps->flag = gpd->sbuffer_sflag; + gps->thickness = brush->size; + gps->flag = gpd->runtime.sbuffer_sflag; gps->inittime = p->inittime; /* enable recalculation flag by default (only used if hq fill) */ gps->flag |= GP_STROKE_RECALC_CACHES; /* allocate enough memory for a continuous array for storage points */ - int sublevel = brush->sublevel; - int new_totpoints = gps->totpoints; + const int subdivide = brush->gpencil_settings->draw_subdivide; + + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); - for (i = 0; i < sublevel; i++) { - new_totpoints += new_totpoints - 1; - } - gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points"); /* initialize triangle memory to dummy data */ gps->triangles = MEM_callocN(sizeof(bGPDtriangle), "GP Stroke triangulation"); gps->flag |= GP_STROKE_RECALC_CACHES; gps->tot_triangles = 0; + /* drawing batch cache is dirty now */ + gp_update_cache(p->gpd); /* set pointer to first non-initialized point */ pt = gps->points + (gps->totpoints - totelem); + dvert = gps->dvert + (gps->totpoints - totelem); /* copy points from the buffer to the stroke */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { /* straight lines only -> only endpoints */ { /* first point */ - ptc = gpd->sbuffer; + ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* if axis locked, reproject to plane locked (only in 3d space) */ - if (p->lock_axis > GP_LOCKAXIS_NONE) { - gp_reproject_toplane(p, gps); - } - /* if parented change position relative to parent object */ - if (gpl->parent != NULL) { - gp_apply_parent_point(gpl, pt); - } /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; + dvert->totweight = 0; + dvert->dw = NULL; + pt++; + dvert++; } if (totelem == 2) { /* last point if applicable */ - ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1); + ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_size - 1); /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* if axis locked, reproject to plane locked (only in 3d space) */ - if (p->lock_axis > GP_LOCKAXIS_NONE) { - gp_reproject_toplane(p, gps); - } - /* if parented change position relative to parent object */ - if (gpl->parent != NULL) { - gp_apply_parent_point(gpl, pt); - } - /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; + + dvert->totweight = 0; + dvert->dw = NULL; + } + + /* reproject to plane (only in 3d space) */ + gp_reproject_toplane(p, gps); + pt = gps->points; + for (i = 0; i < gps->totpoints; i++, pt++) { + /* if parented change position relative to parent object */ + gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt); } } else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { /* first point */ - ptc = gpd->sbuffer; + ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* if axis locked, reproject to plane locked (only in 3d space) */ - if (p->lock_axis > GP_LOCKAXIS_NONE) { - gp_reproject_toplane(p, gps); - } + /* reproject to plane (only in 3d space) */ + gp_reproject_toplane(p, gps); /* if parented change position relative to parent object */ - if (gpl->parent != NULL) { - gp_apply_parent_point(gpl, pt); - } + gp_apply_parent_point(depsgraph, obact, gpd, gpl, pt); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; + + dvert->totweight = 0; + dvert->dw = NULL; + } else { float *depth_arr = NULL; @@ -902,9 +1035,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) int interp_depth = 0; int found_depth = 0; - depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points"); + depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_size, "depth_points"); - for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) { + for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size; i++, ptc++, pt++) { copy_v2_v2_int(mval, &ptc->x); if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) && @@ -921,7 +1054,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) if (found_depth == false) { /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */ - for (i = gpd->sbuffer_size - 1; i >= 0; i--) + for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) depth_arr[i] = 0.9999f; } else { @@ -930,13 +1063,13 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) int first_valid = 0; int last_valid = 0; - for (i = 0; i < gpd->sbuffer_size; i++) { + for (i = 0; i < gpd->runtime.sbuffer_size; i++) { if (depth_arr[i] != FLT_MAX) break; } first_valid = i; - for (i = gpd->sbuffer_size - 1; i >= 0; i--) { + for (i = gpd->runtime.sbuffer_size - 1; i >= 0; i--) { if (depth_arr[i] != FLT_MAX) break; } @@ -950,16 +1083,15 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } if (interp_depth) { - interp_sparse_array(depth_arr, gpd->sbuffer_size, FLT_MAX); + interp_sparse_array(depth_arr, gpd->runtime.sbuffer_size, FLT_MAX); } } } - pt = gps->points; /* convert all points (normal behavior) */ - for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) { + for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_size && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); @@ -968,20 +1100,18 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; + pt->uv_fac = ptc->uv_fac; + pt->uv_rot = ptc->uv_rot; } - /* subdivide the stroke */ - if (sublevel > 0) { - int totpoints = gps->totpoints; - for (i = 0; i < sublevel; i++) { - /* we're adding one new point between each pair of verts on each step */ - totpoints += totpoints - 1; - - gp_subdivide_stroke(gps, totpoints); - } + /* subdivide and smooth the stroke */ + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (subdivide > 0)) { + gp_subdivide_stroke(gps, subdivide); } /* apply randomness to stroke */ - if (brush->draw_random_sub > 0.0f) { + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && + (brush->gpencil_settings->draw_random_sub > 0.0f)) + { gp_randomize_stroke(gps, brush, p->rng); } @@ -989,34 +1119,43 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) * for each iteration, the factor is reduced to get a better smoothing without changing too much * the original stroke */ - if (brush->draw_smoothfac > 0.0f) { + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && + (brush->gpencil_settings->draw_smoothfac > 0.0f)) + { float reduce = 0.0f; - for (int r = 0; r < brush->draw_smoothlvl; ++r) { + for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) { for (i = 0; i < gps->totpoints; i++) { - /* NOTE: No pressure smoothing, or else we get annoying thickness changes while drawing... */ - gp_smooth_stroke(gps, i, brush->draw_smoothfac - reduce, false); + BKE_gpencil_smooth_stroke(gps, i, brush->gpencil_settings->draw_smoothfac - reduce); + BKE_gpencil_smooth_stroke_strength(gps, i, brush->gpencil_settings->draw_smoothfac); } reduce += 0.25f; // reduce the factor } } - - /* if axis locked, reproject to plane locked (only in 3d space) */ - if (p->lock_axis > GP_LOCKAXIS_NONE) { - gp_reproject_toplane(p, gps); - } - /* if parented change position relative to parent object */ - if (gpl->parent != NULL) { - gp_apply_parent(gpl, gps); + /* smooth thickness */ + if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && + (brush->gpencil_settings->thick_smoothfac > 0.0f)) + { + for (int r = 0; r < brush->gpencil_settings->thick_smoothlvl * 2; r++) { + for (i = 0; i < gps->totpoints; i++) { + BKE_gpencil_smooth_stroke_thickness(gps, i, brush->gpencil_settings->thick_smoothfac); + } + } } + /* reproject to plane (only in 3d space) */ + gp_reproject_toplane(p, gps); + /* change position relative to parent object */ + gp_apply_parent(depsgraph, obact, gpd, gpl, gps); + if (depth_arr) MEM_freeN(depth_arr); } - /* Save palette color */ - bGPDpalette *palette = BKE_gpencil_palette_getactive(p->gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - gps->palcolor = palcolor; - BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); + + /* Save material index */ + gps->mat_nr = BKE_object_material_slot_find_index(p->ob, p->material) - 1; + + /* calculate UVs along the stroke */ + ED_gpencil_calc_stroke_uv(obact, gps); /* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke is added on listbase head * because the drawing order is inverse and the head stroke is the first to draw. This is very useful for artist @@ -1047,6 +1186,8 @@ static float view3d_point_depth(const RegionView3D *rv3d, const float co[3]) /* only erase stroke points that are visible */ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y) { + Object *obact = (Object *)p->ownerPtr.data; + if ((p->sa->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) { @@ -1059,7 +1200,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, cons float diff_mat[4][4]; /* calculate difference matrix if parent object */ - ED_gpencil_parent_location(gpl, diff_mat); + ED_gpencil_parent_location(p->depsgraph, obact, p->gpd, gpl, diff_mat); if (ED_view3d_autodist_simple(p->ar, mval, mval_3d, 0, NULL)) { const float depth_mval = view3d_point_depth(rv3d, mval_3d); @@ -1092,6 +1233,24 @@ static float gp_stroke_eraser_calc_influence(tGPsdata *p, const int mval[2], con return fac; } +/* helper to free a stroke */ +static void gp_free_stroke(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps) +{ + if (gps->points) { + MEM_freeN(gps->points); + } + + if (gps->dvert) { + BKE_gpencil_free_stroke_weights(gps); + MEM_freeN(gps->dvert); + } + + if (gps->triangles) + MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + gp_update_cache(gpd); +} + /* eraser tool - evaluation per stroke */ /* TODO: this could really do with some optimization (KD-Tree/BVH?) */ static void gp_stroke_eraser_dostroke(tGPsdata *p, @@ -1099,46 +1258,58 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, const int mval[2], const int mvalo[2], const int radius, const rcti *rect) { + Depsgraph *depsgraph = p->depsgraph; + Object *obact = (Object *)p->ownerPtr.data; + Brush *eraser = p->eraser; bGPDspoint *pt1, *pt2; int pc1[2] = {0}; int pc2[2] = {0}; int i; float diff_mat[4][4]; - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - } + /* calculate difference matrix */ + ED_gpencil_parent_location(depsgraph, obact, p->gpd, gpl, diff_mat); if (gps->totpoints == 0) { /* just free stroke */ - if (gps->points) - MEM_freeN(gps->points); - if (gps->triangles) - MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + gp_free_stroke(p->gpd, gpf, gps); } else if (gps->totpoints == 1) { /* only process if it hasn't been masked out... */ if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { - if (gpl->parent == NULL) { - gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); - } - else { - bGPDspoint pt_temp; - gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); - gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]); + bGPDspoint pt_temp; + gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gp_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]); + /* do boundbox check first */ + if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { + /* only check if point is inside */ + if (len_v2v2_int(mval, pc1) <= radius) { + /* free stroke */ + gp_free_stroke(p->gpd, gpf, gps); + } } + } + } + else if ((p->flags & GP_PAINTFLAG_STROKE_ERASER) || (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_STROKE)) { + for (i = 0; (i + 1) < gps->totpoints; i++) { + + /* only process if it hasn't been masked out... */ + if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) + continue; + + /* get points to work with */ + pt1 = gps->points + i; + bGPDspoint npt; + gp_point_to_parent_space(pt1, diff_mat, &npt); + gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); + /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ if (len_v2v2_int(mval, pc1) <= radius) { /* free stroke */ - // XXX: pressure sensitive eraser should apply here too? - MEM_freeN(gps->points); - if (gps->triangles) - MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + gp_free_stroke(p->gpd, gpf, gps); + return; } } } @@ -1181,18 +1352,12 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) continue; - if (gpl->parent == NULL) { - gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); - gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); - } - else { - bGPDspoint npt; - gp_point_to_parent_space(pt1, diff_mat, &npt); - gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); + bGPDspoint npt; + gp_point_to_parent_space(pt1, diff_mat, &npt); + gp_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); - gp_point_to_parent_space(pt2, diff_mat, &npt); - gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); - } + gp_point_to_parent_space(pt2, diff_mat, &npt); + gp_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); /* Check that point segment of the boundbox of the eraser stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || @@ -1215,11 +1380,15 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, pt2->pressure -= gp_stroke_eraser_calc_influence(p, mval, radius, pc2) * strength / 2.0f; /* 2) Tag any point with overly low influence for removal in the next pass */ - if (pt1->pressure < cull_thresh) { + if ((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) || + (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) + { pt1->flag |= GP_SPOINT_TAG; do_cull = true; } - if (pt2->pressure < cull_thresh) { + if ((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) || + (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) + { pt2->flag |= GP_SPOINT_TAG; do_cull = true; } @@ -1230,8 +1399,9 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* Second Pass: Remove any points that are tagged */ if (do_cull) { - gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG); + gp_stroke_delete_tagged_points(gpf, gps, gps->next, GP_SPOINT_TAG, false); } + gp_update_cache(p->gpd); } } @@ -1275,7 +1445,7 @@ static void gp_stroke_doeraser(tGPsdata *p) for (gps = gpf->strokes.first; gps; gps = gpn) { gpn = gps->next; /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { + if (ED_gpencil_stroke_color_use(p->ob, gpl, gps) == false) { continue; } /* Not all strokes in the datablock may be valid in the current editor/context @@ -1295,107 +1465,178 @@ static void gp_stroke_doeraser(tGPsdata *p) static void gp_session_validatebuffer(tGPsdata *p) { bGPdata *gpd = p->gpd; + Brush *brush = p->brush; /* clear memory of buffer (or allocate it if starting a new session) */ - if (gpd->sbuffer) { + if (gpd->runtime.sbuffer) { /* printf("\t\tGP - reset sbuffer\n"); */ - memset(gpd->sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX); + memset(gpd->runtime.sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX); } else { /* printf("\t\tGP - allocate sbuffer\n"); */ - gpd->sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); + gpd->runtime.sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer"); } /* reset indices */ - gpd->sbuffer_size = 0; + gpd->runtime.sbuffer_size = 0; /* reset flags */ - gpd->sbuffer_sflag = 0; + gpd->runtime.sbuffer_sflag = 0; /* reset inittime */ p->inittime = 0.0; + + /* reset lazy */ + if (brush) { + brush->gpencil_settings->flag &= ~GP_BRUSH_STABILIZE_MOUSE_TEMP; + } } -/* create a new palette color */ -static bGPDpalettecolor *gp_create_new_color(bGPDpalette *palette) +/* helper to get default eraser and create one if no eraser brush */ +static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts) { - bGPDpalettecolor *palcolor; + Brush *brush_dft = NULL; + Paint *paint = BKE_brush_get_gpencil_paint(ts); + Brush *brush_old = paint->brush; + for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) { + if ((brush->ob_mode == OB_MODE_GPENCIL_PAINT) && + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) + { + /* save first eraser to use later if no default */ + if (brush_dft == NULL) { + brush_dft = brush; + } + /* found default */ + if(brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) { + return brush; + } + } + } + /* if no default, but exist eraser brush, return this and set as default */ + if (brush_dft) { + brush_dft->gpencil_settings->flag |= GP_BRUSH_DEFAULT_ERASER; + return brush_dft; + } + /* create a new soft eraser brush */ + else { + brush_dft = BKE_brush_add_gpencil(bmain, ts, "Soft Eraser"); + brush_dft->size = 30.0f; + brush_dft->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER); + brush_dft->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; + brush_dft->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE; + brush_dft->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT; - palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true); + /* reset current brush */ + BKE_paint_brush_set(paint, brush_old); - return palcolor; + return brush_dft; + } } /* initialize a drawing brush */ -static void gp_init_drawing_brush(ToolSettings *ts, tGPsdata *p) +static void gp_init_drawing_brush(bContext *C, tGPsdata *p) { - bGPDbrush *brush; + Brush *brush; + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + Paint *paint = BKE_brush_get_gpencil_paint(ts); /* if not exist, create a new one */ - if (BLI_listbase_is_empty(&ts->gp_brushes)) { + if (paint->brush == NULL) { /* create new brushes */ - BKE_gpencil_brush_init_presets(ts); - brush = BKE_gpencil_brush_getactive(ts); + BKE_brush_gpencil_presets(C); + brush = BKE_brush_getactive_gpencil(ts); } else { /* Use the current */ - brush = BKE_gpencil_brush_getactive(ts); + brush = BKE_brush_getactive_gpencil(ts); } /* be sure curves are initializated */ - curvemapping_initialize(brush->cur_sensitivity); - curvemapping_initialize(brush->cur_strength); - curvemapping_initialize(brush->cur_jitter); + curvemapping_initialize(brush->gpencil_settings->curve_sensitivity); + curvemapping_initialize(brush->gpencil_settings->curve_strength); + curvemapping_initialize(brush->gpencil_settings->curve_jitter); /* asign to temp tGPsdata */ p->brush = brush; + if (brush->gpencil_settings->brush_type != GP_BRUSH_TYPE_ERASE) { + p->eraser = gp_get_default_eraser(p->bmain, ts); + } + else { + p->eraser = brush; + } + /* use radius of eraser */ + p->radius = (short)p->eraser->size; + + /* GPXX: Need this update to synchronize brush with draw manager. + * Maybe this update can be removed when the new tool system + * will be in place, but while, we need this to keep drawing working. + * + */ + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE); } -/* initialize a paint palette brush and a default color if not exist */ -static void gp_init_palette(tGPsdata *p) +/* initialize a paint brush and a default color if not exist */ +static void gp_init_colors(tGPsdata *p) { - bGPdata *gpd; - bGPDpalette *palette; - bGPDpalettecolor *palcolor; + bGPdata *gpd = p->gpd; + Brush *brush = p->brush; - gpd = p->gpd; + Material *ma = NULL; + MaterialGPencilStyle *gp_style = NULL; + + /* use brush material */ + ma = BKE_gpencil_get_material_from_brush(brush); + + /* if no brush defaults, get material and color info + * NOTE: Ensures that everything we need will exist... + */ + if ((ma == NULL) || (ma->gp_style == NULL)) { + BKE_gpencil_material_ensure(p->bmain, p->ob); - /* if not exist, create a new palette */ - if (BLI_listbase_is_empty(&gpd->palettes)) { - /* create new palette */ - palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true); - /* now create a default color */ - palcolor = gp_create_new_color(palette); + /* assign always the first material to the brush */ + p->material = give_current_material(p->ob, 1); + brush->gpencil_settings->material = p->material; } else { - /* Use the current palette and color */ - palette = BKE_gpencil_palette_getactive(gpd); - /* the palette needs one color */ - if (BLI_listbase_is_empty(&palette->colors)) { - palcolor = gp_create_new_color(palette); - } - else { - palcolor = BKE_gpencil_palettecolor_getactive(palette); - } - /* in some situations can be null, so use first */ - if (palcolor == NULL) { - BKE_gpencil_palettecolor_setactive(palette, palette->colors.first); - palcolor = palette->colors.first; - } + p->material = ma; } - /* asign to temp tGPsdata */ - p->palettecolor = palcolor; + /* check if the material is already on object material slots and add it if missing */ + if (BKE_object_material_slot_find_index(p->ob, p->material) == 0) { + BKE_object_material_slot_add(p->bmain, p->ob); + assign_material(p->bmain, p->ob, ma, p->ob->totcol, BKE_MAT_ASSIGN_EXISTING); + } + + /* assign color information to temp tGPsdata */ + gp_style = p->material->gp_style; + if (gp_style) { + + /* set colors */ + copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba); + copy_v4_v4(gpd->runtime.sfill, gp_style->fill_rgba); + /* add some alpha to make easy the filling without hide strokes */ + if (gpd->runtime.sfill[3] > 0.8f) { + gpd->runtime.sfill[3] = 0.8f; + } + + gpd->runtime.mode = (short)gp_style->mode; + gpd->runtime.bstroke_style = gp_style->stroke_style; + gpd->runtime.bfill_style = gp_style->fill_style; + } } /* (re)init new painting data */ -static bool gp_session_initdata(bContext *C, tGPsdata *p) +static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) { Main *bmain = CTX_data_main(C); bGPdata **gpd_ptr = NULL; ScrArea *curarea = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); ToolSettings *ts = CTX_data_tool_settings(C); + Object *obact = CTX_data_active_object(C); + View3D *v3d = curarea->spacedata.first; /* make sure the active view (at the starting time) is a 3d-view */ if (curarea == NULL) { @@ -1406,10 +1647,12 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) } /* pass on current scene and window */ + p->C = C; p->bmain = CTX_data_main(C); p->scene = CTX_data_scene(C); p->depsgraph = CTX_data_depsgraph(C); p->win = CTX_wm_window(C); + p->disable_fill = RNA_boolean_get(op->ptr, "disable_fill"); unit_m4(p->imat); unit_m4(p->mat); @@ -1424,7 +1667,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) /* set current area * - must verify that region data is 3D-view (and not something else) */ - /* CAUTION: If this is the "toolbar", then this will change on the first stroke */ + /* CAUTION: If this is the "toolbar", then this will change on the first stroke */ p->sa = curarea; p->ar = ar; p->align_flag = &ts->gpencil_v3d_align; @@ -1435,92 +1678,19 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n"); return 0; } - break; - } - case SPACE_NODE: - { - /* SpaceNode *snode = curarea->spacedata.first; */ - /* set current area */ - p->sa = curarea; - p->ar = ar; - p->v2d = &ar->v2d; - p->align_flag = &ts->gpencil_v2d_align; - break; - } - case SPACE_SEQ: - { - SpaceSeq *sseq = curarea->spacedata.first; - - /* set current area */ - p->sa = curarea; - p->ar = ar; - p->v2d = &ar->v2d; - p->align_flag = &ts->gpencil_seq_align; - - /* check that gpencil data is allowed to be drawn */ - if (sseq->mainb == SEQ_DRAW_SEQUENCE) { - p->status = GP_STATUS_ERROR; - if (G.debug & G_DEBUG) - printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n"); - return 0; + /* if active object doesn't exist or isn't a GP Object, create one */ + float *cur = ED_view3d_cursor3d_get(p->scene, v3d)->location; + if ((!obact) || (obact->type != OB_GPENCIL)) { + /* create new default object */ + obact = ED_add_gpencil_object(C, p->scene, cur); } - break; - } - case SPACE_IMAGE: - { - /* SpaceImage *sima = curarea->spacedata.first; */ + /* assign object after all checks to be sure we have one active */ + p->ob = obact; - /* set the current area */ - p->sa = curarea; - p->ar = ar; - p->v2d = &ar->v2d; - p->align_flag = &ts->gpencil_ima_align; - break; - } - case SPACE_CLIP: - { - SpaceClip *sc = curarea->spacedata.first; - MovieClip *clip = ED_space_clip_get_clip(sc); - - if (clip == NULL) { - p->status = GP_STATUS_ERROR; - return false; - } - - /* set the current area */ - p->sa = curarea; - p->ar = ar; - p->v2d = &ar->v2d; - p->align_flag = &ts->gpencil_v2d_align; - - invert_m4_m4(p->imat, sc->unistabmat); - - /* custom color for new layer */ - p->custom_color[0] = 1.0f; - p->custom_color[1] = 0.0f; - p->custom_color[2] = 0.5f; - p->custom_color[3] = 0.9f; - - if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) { - int framenr = ED_space_clip_get_clip_frame_number(sc); - MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking); - MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL; - - if (marker) { - p->imat[3][0] -= marker->pos[0]; - p->imat[3][1] -= marker->pos[1]; - } - else { - p->status = GP_STATUS_ERROR; - return false; - } - } - - invert_m4_m4(p->mat, p->imat); - copy_m4_m4(p->gsc.mat, p->mat); break; } + /* unsupported views */ default: { @@ -1533,7 +1703,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) /* get gp-data */ gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr); - if (gpd_ptr == NULL) { + if ((gpd_ptr == NULL) || ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) { p->status = GP_STATUS_ERROR; if (G.debug & G_DEBUG) printf("Error: Current context doesn't allow for any Grease Pencil data\n"); @@ -1555,16 +1725,18 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) /* clear out buffer (stored in gp-data), in case something contaminated it */ gp_session_validatebuffer(p); + /* set brush and create a new one if null */ - gp_init_drawing_brush(ts, p); - /* set palette info and create a new one if null */ - gp_init_palette(p); - /* set palette colors */ - bGPDpalettecolor *palcolor = p->palettecolor; - bGPdata *pdata = p->gpd; - copy_v4_v4(pdata->scolor, palcolor->color); - copy_v4_v4(pdata->sfill, palcolor->fill); - pdata->sflag = palcolor->flag; + gp_init_drawing_brush(C, p); + + /* setup active color */ + if (curarea->spacetype == SPACE_VIEW3D) { + /* NOTE: This is only done for 3D view, as Materials aren't used for + * annotations in 2D editors + */ + gp_init_colors(p); + } + /* lock axis */ p->lock_axis = ts->gp_sculpt.lock_axis; @@ -1572,20 +1744,22 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) } /* init new painting session */ -static tGPsdata *gp_session_initpaint(bContext *C) +static tGPsdata *gp_session_initpaint(bContext *C, wmOperator *op) { tGPsdata *p = NULL; /* create new context data */ p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data"); - gp_session_initdata(C, p); + gp_session_initdata(C, op, p); +#if 0 /* radius for eraser circle is defined in userprefs now */ /* NOTE: we do this here, so that if we exit immediately, * erase size won't get lost */ p->radius = U.gp_eraser; +#endif /* Random generator, only init once. */ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); @@ -1606,15 +1780,15 @@ static void gp_session_cleanup(tGPsdata *p) return; /* free stroke buffer */ - if (gpd->sbuffer) { + if (gpd->runtime.sbuffer) { /* printf("\t\tGP - free sbuffer\n"); */ - MEM_freeN(gpd->sbuffer); - gpd->sbuffer = NULL; + MEM_freeN(gpd->runtime.sbuffer); + gpd->runtime.sbuffer = NULL; } /* clear flags */ - gpd->sbuffer_size = 0; - gpd->sbuffer_sflag = 0; + gpd->runtime.sbuffer_size = 0; + gpd->runtime.sbuffer_sflag = 0; p->inittime = 0.0; } @@ -1632,11 +1806,12 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps { Scene *scene = p->scene; ToolSettings *ts = scene->toolsettings; + int cfra_eval = (int)DEG_get_ctime(p->depsgraph); /* get active layer (or add a new one if non-existent) */ p->gpl = BKE_gpencil_layer_getactive(p->gpd); if (p->gpl == NULL) { - p->gpl = BKE_gpencil_layer_addnew(p->gpd, "GP_Layer", true); + p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true); if (p->custom_color[3]) copy_v3_v3(p->gpl->color, p->custom_color); @@ -1670,7 +1845,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps * -> If there are no strokes in that frame, don't add a new empty frame */ if (gpl->actframe && gpl->actframe->strokes.first) { - gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY); + gpl->actframe = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_COPY); has_layer_to_erase = true; } @@ -1708,7 +1883,9 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps else add_frame_mode = GP_GETFRAME_ADD_NEW; - p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode); + p->gpf = BKE_gpencil_layer_getframe(p->gpl, cfra_eval, add_frame_mode); + /* set as dirty draw manager cache */ + gp_update_cache(p->gpd); if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; @@ -1724,7 +1901,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps /* set 'eraser' for this stroke if using eraser */ p->paintmode = paintmode; if (p->paintmode == GP_PAINTMODE_ERASER) { - p->gpd->sbuffer_sflag |= GP_STROKE_ERASER; + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER; /* check if we should respect depth while erasing */ if (p->sa->spacetype == SPACE_VIEW3D) { @@ -1735,7 +1912,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps } else { /* disable eraser flags - so that we can switch modes during a session */ - p->gpd->sbuffer_sflag &= ~GP_STROKE_ERASER; + p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER; if (p->sa->spacetype == SPACE_VIEW3D) { if (p->gpl->flag & GP_LAYER_NO_XRAY) { @@ -1744,10 +1921,16 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps } } + /* set special fill stroke mode */ + if (p->disable_fill == true) { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_NOFILL; + /* replace stroke color with fill color */ + copy_v4_v4(p->gpd->runtime.scolor, p->gpd->runtime.sfill); + } + /* set 'initial run' flag, which is only used to denote when a new stroke is starting */ p->flags |= GP_PAINTFLAG_FIRSTRUN; - /* when drawing in the camera view, in 2D space, set the subrect */ p->subrect = NULL; if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { @@ -1782,41 +1965,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps switch (p->sa->spacetype) { case SPACE_VIEW3D: { - p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE; - break; - } - case SPACE_NODE: - { - p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE; - break; - } - case SPACE_SEQ: - { - p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE; - break; - } - case SPACE_IMAGE: - { - SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first; - - /* only set these flags if the image editor doesn't have an image active, - * otherwise user will be confused by strokes not appearing after they're drawn - * - * Admittedly, this is a bit hacky, but it works much nicer from an ergonomic standpoint! - */ - if (ELEM(NULL, sima, sima->image)) { - /* make strokes be drawn in screen space */ - p->gpd->sbuffer_sflag &= ~GP_STROKE_2DSPACE; - *(p->align_flag) &= ~GP_PROJECT_VIEWSPACE; - } - else { - p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE; - } - break; - } - case SPACE_CLIP: - { - p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE; + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE; break; } } @@ -1839,7 +1988,7 @@ static void gp_paint_strokeend(tGPsdata *p) } /* check if doing eraser or not */ - if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) { + if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { /* simplify stroke before transferring? */ gp_stroke_simplify(p); @@ -1920,10 +2069,12 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en p->erasercursor = NULL; } else if (enable && !p->erasercursor) { + ED_gpencil_toggle_brush_cursor(p->C, false, NULL); /* enable cursor */ - p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), - NULL, /* XXX */ - gpencil_draw_eraser, p); + p->erasercursor = WM_paint_cursor_activate( + CTX_wm_manager(C), + NULL, /* XXX */ + gpencil_draw_eraser, p); } } @@ -1943,13 +2094,26 @@ static bool gpencil_is_tablet_eraser_active(const wmEvent *event) static void gpencil_draw_exit(bContext *C, wmOperator *op) { tGPsdata *p = op->customdata; + bGPdata *gpd = CTX_data_gpencil_data(C); /* clear undo stack */ gpencil_undo_finish(); /* restore cursor to indicate end of drawing */ - WM_cursor_modal_restore(CTX_wm_window(C)); + if (p->sa->spacetype != SPACE_VIEW3D) { + WM_cursor_modal_restore(CTX_wm_window(C)); + } + else { + /* or restore paint if 3D view */ + if ((p) && (p->paintmode == GP_PAINTMODE_ERASER)) { + WM_cursor_modal_set(p->win, CURSOR_STD); + } + /* drawing batch cache is dirty now */ + if (gpd) { + gp_update_cache(gpd); + } + } /* don't assume that operator data exists at all */ if (p) { /* check size of buffer before cleanup, to determine if anything happened here */ @@ -1962,11 +2126,16 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) * NOTE: Do this even when not in eraser mode, as eraser may * have been toggled at some point. */ - U.gp_eraser = p->radius; + if (p->eraser) { + p->eraser->size = p->radius; + } /* cleanup */ gp_paint_cleanup(p); gp_session_cleanup(p); + ED_gpencil_toggle_brush_cursor(C, true, NULL); + + /* finally, free the temp data */ gp_session_free(p); } @@ -1986,9 +2155,18 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) { tGPsdata *p; eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode"); + ToolSettings *ts = CTX_data_tool_settings(C); + Brush *brush = BKE_brush_getactive_gpencil(ts); + + /* if mode is draw and the brush is eraser, cancel */ + if (paintmode != GP_PAINTMODE_ERASER) { + if ((brush) && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) { + return 0; + } + } /* check context */ - p = op->customdata = gp_session_initpaint(C); + p = op->customdata = gp_session_initpaint(C, op); if ((p == NULL) || (p->status == GP_STATUS_ERROR)) { /* something wasn't set correctly in context */ gpencil_draw_exit(C, op); @@ -2009,6 +2187,8 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) p->keymodifier = -1; } + p->reports = op->reports; + /* everything is now setup ok */ return 1; } @@ -2019,10 +2199,15 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event) /* ensure that the correct cursor icon is set */ static void gpencil_draw_cursor_set(tGPsdata *p) { - if (p->paintmode == GP_PAINTMODE_ERASER) + Brush *brush = p->brush; + if ((p->paintmode == GP_PAINTMODE_ERASER) || + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) + { WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */ - else - WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR); + } + else { + WM_cursor_modal_set(p->win, CURSOR_STD); + } } /* update UI indicators of status, including cursor and header prints */ @@ -2030,11 +2215,21 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) { /* header prints */ switch (p->status) { - case GP_STATUS_PAINTING: - /* only print this for paint-sessions, otherwise it gets annoying */ - if (GPENCIL_SKETCH_SESSIONS_ON(p->scene)) - ED_workspace_status_text(C, IFACE_("Grease Pencil: Drawing/erasing stroke... Release to end stroke")); - break; + +#if 0 /* FIXME, this never runs! */ + switch (p->paintmode) { + case GP_PAINTMODE_DRAW_POLY: + /* Provide usage tips, since this is modal, and unintuitive without hints */ + ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | " + "ESC/Enter to end (or click outside this area)")); + break; + default: + /* Do nothing - the others are self explanatory, exit quickly once the mouse is released + * Showing any text would just be annoying as it would flicker. + */ + break; + } +#endif case GP_STATUS_IDLING: /* print status info */ @@ -2048,12 +2243,11 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) "ESC/Enter to end (or click outside this area)")); break; case GP_PAINTMODE_DRAW: - ED_workspace_status_text(C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | " - "E/ESC/Enter to end (or click outside this area)")); + ED_workspace_status_text(C, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw")); break; case GP_PAINTMODE_DRAW_POLY: ED_workspace_status_text(C, IFACE_("Grease Pencil Poly Session: LMB click to place next stroke vertex | " - "ESC/Enter to end (or click outside this area)")); + "Release Shift/ESC/Enter to end (or click outside this area)")); break; default: /* unhandled future cases */ @@ -2067,14 +2261,19 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) /* clear status string */ ED_workspace_status_text(C, NULL); break; + case GP_STATUS_PAINTING: + break; } } /* ------------------------------- */ /* create a new stroke point at the point indicated by the painting context */ -static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph) +static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph) { + bGPdata *gpd = p->gpd; + tGPspoint *pt = NULL; + /* handle drawing/erasing -> test for erasing first */ if (p->paintmode == GP_PAINTMODE_ERASER) { /* do 'live' erasing now */ @@ -2087,6 +2286,17 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph } /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */ else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) { + + /* if lazy mouse, interpolate the last and current mouse positions */ + if (GPENCIL_LAZY_MODE(p->brush, p->shift)) { + float now_mouse[2]; + float last_mouse[2]; + copy_v2fl_v2i(now_mouse, p->mval); + copy_v2fl_v2i(last_mouse, p->mvalo); + interp_v2_v2v2(now_mouse, now_mouse, last_mouse, p->brush->smooth_stroke_factor); + round_v2i_v2fl(p->mval, now_mouse); + } + /* try to add point */ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); @@ -2124,11 +2334,24 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph p->mvalo[1] = p->mval[1]; p->opressure = p->pressure; p->ocurtime = p->curtime; + + pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1; + if (p->paintmode != GP_PAINTMODE_ERASER) { + ED_gpencil_toggle_brush_cursor(C, true, &pt->x); + } + } + else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) && + (gpd->runtime.sbuffer_size > 0)) + { + pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_size - 1; + if (p->paintmode != GP_PAINTMODE_ERASER) { + ED_gpencil_toggle_brush_cursor(C, true, &pt->x); + } } } /* handle draw event */ -static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsgraph *depsgraph) +static void gpencil_draw_apply_event(bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, int x, int y) { tGPsdata *p = op->customdata; PointerRNA itemptr; @@ -2136,13 +2359,15 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg int tablet = 0; /* convert from window-space to area-space mouse coordinates + * add any x,y override position for fake events * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding... */ - p->mval[0] = event->mval[0] + 1; - p->mval[1] = event->mval[1] + 1; + p->mval[0] = event->mval[0] + 1 - x; + p->mval[1] = event->mval[1] + 1 - y; + p->shift = event->shift; /* verify key status for straight lines */ - if ((event->ctrl > 0) || (event->alt > 0)) { + if ((event->alt > 0) && (RNA_boolean_get(op->ptr, "disable_straight") == false)) { if (p->straight[0] == 0) { int dx = abs(p->mval[0] - p->mvalo[0]); int dy = abs(p->mval[1] - p->mvalo[1]); @@ -2151,12 +2376,12 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg if (dx >= dy) { /* horizontal */ p->straight[0] = 1; - p->straight[1] = p->mval[1]; /* save y */ + p->straight[1] = (short)p->mval[1]; /* save y */ } else { /* vertical */ p->straight[0] = 2; - p->straight[1] = p->mval[0]; /* save x */ + p->straight[1] = (short)p->mval[0]; /* save x */ } } } @@ -2191,6 +2416,22 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg p->pressure = 1.0f; } + /* special eraser modes */ + if (p->paintmode == GP_PAINTMODE_ERASER) { + if (event->shift > 0) { + p->flags |= GP_PAINTFLAG_HARD_ERASER; + } + else { + p->flags &= ~GP_PAINTFLAG_HARD_ERASER; + } + if (event->alt > 0) { + p->flags |= GP_PAINTFLAG_STROKE_ERASER; + } + else { + p->flags &= ~GP_PAINTFLAG_STROKE_ERASER; + } + } + /* special exception for start of strokes (i.e. maybe for just a dot) */ if (p->flags & GP_PAINTFLAG_FIRSTRUN) { p->flags &= ~GP_PAINTFLAG_FIRSTRUN; @@ -2233,7 +2474,7 @@ static void gpencil_draw_apply_event(wmOperator *op, const wmEvent *event, Depsg RNA_float_set(&itemptr, "time", p->curtime - p->inittime); /* apply the current latest drawing point */ - gpencil_draw_apply(op, p, depsgraph); + gpencil_draw_apply(C, op, p, depsgraph); /* force refresh */ ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */ @@ -2251,7 +2492,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) /* try to initialize context data needed while drawing */ if (!gpencil_draw_init(C, op, NULL)) { - if (op->customdata) MEM_freeN(op->customdata); + MEM_SAFE_FREE(op->customdata); /* printf("\tGP - no valid data\n"); */ return OPERATOR_CANCELLED; } @@ -2298,7 +2539,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op) } /* apply this data as necessary now (as per usual) */ - gpencil_draw_apply(op, p, depsgraph); + gpencil_draw_apply(C, op, p, depsgraph); } RNA_END; @@ -2324,6 +2565,11 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event if (G.debug & G_DEBUG) printf("GPencil - Starting Drawing\n"); + /* support for tablets eraser pen */ + if (gpencil_is_tablet_eraser_active(event)) { + RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER); + } + /* try to initialize context data needed while drawing */ if (!gpencil_draw_init(C, op, event)) { if (op->customdata) @@ -2344,6 +2590,9 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event if (p->paintmode == GP_PAINTMODE_ERASER) { gpencil_draw_toggle_eraser_cursor(C, p, true); } + else { + ED_gpencil_toggle_brush_cursor(C, true, NULL); + } /* set cursor * NOTE: This may change later (i.e. intentionally via brush toggle, * or unintentionally if the user scrolls outside the area)... @@ -2357,7 +2606,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ - gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); + gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0, 0); op->flag |= OP_IS_MODAL_CURSOR_REGION; } else { @@ -2366,9 +2615,29 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event op->flag |= OP_IS_MODAL_CURSOR_REGION; } + /* enable paint mode */ + if (p->sa->spacetype == SPACE_VIEW3D) { + Object *ob = CTX_data_active_object(C); + if (ob && (ob->type == OB_GPENCIL) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) { + /* Just set paintmode flag... */ + p->gpd->flag |= GP_DATA_STROKE_PAINTMODE; + /* disable other GP modes */ + p->gpd->flag &= ~GP_DATA_STROKE_EDITMODE; + p->gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE; + p->gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE; + /* set workspace mode */ + ob->restore_mode = ob->mode; + ob->mode = OB_MODE_GPENCIL_PAINT; + /* redraw mode on screen */ + WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + } + } + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + /* add a modal handler for this operator, so that we can then draw continuous strokes */ WM_event_add_modal_handler(C, op); + return OPERATOR_RUNNING_MODAL; } @@ -2397,7 +2666,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) /* XXX: watch it with the paintmode! in future, * it'd be nice to allow changing paint-mode when in sketching-sessions */ - if (gp_session_initdata(C, p)) + if (gp_session_initdata(C, op, p)) gp_paint_initstroke(p, p->paintmode, CTX_data_depsgraph(C)); if (p->status != GP_STATUS_ERROR) { @@ -2448,6 +2717,76 @@ static void gpencil_move_last_stroke_to_back(bContext *C) BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps); } +/* add events for missing mouse movements when the artist draw very fast */ +static void gpencil_add_missing_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p) +{ + Brush *brush = p->brush; + if (brush->gpencil_settings->input_samples == 0) { + return; + } + RegionView3D *rv3d = p->ar->regiondata; + float defaultpixsize = rv3d->pixsize * 1000.0f; + int samples = (GP_MAX_INPUT_SAMPLES - brush->gpencil_settings->input_samples + 1); + float thickness = (float)brush->size; + + float pt[2], a[2], b[2]; + float vec[3]; + float scale = 1.0f; + + /* get pixel scale */ + gp_get_3d_reference(p, vec); + mul_m4_v3(rv3d->persmat, vec); + if (rv3d->is_persp) { + scale = vec[2] * defaultpixsize; + } + else { + scale = defaultpixsize; + } + + /* The thickness of the brush is reduced of thickness to get overlap dots */ + float dot_factor = 0.50f; + if (samples < 2) { + dot_factor = 0.05f; + } + else if (samples < 4) { + dot_factor = 0.10f; + } + else if (samples < 7) { + dot_factor = 0.3f; + } + else if (samples < 10) { + dot_factor = 0.4f; + } + float factor = ((thickness * dot_factor) / scale) * samples; + + copy_v2fl_v2i(a, p->mvalo); + b[0] = event->mval[0] + 1; + b[1] = event->mval[1] + 1; + + /* get distance in pixels */ + float dist = len_v2v2(a, b); + + /* for very small distances, add a half way point */ + if (dist <= 2.0f) { + interp_v2_v2v2(pt, a, b, 0.5f); + sub_v2_v2v2(pt, b, pt); + /* create fake event */ + gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), + (int)pt[0], (int)pt[1]); + } + else if (dist >= factor) { + int slices = 2 + (int)((dist - 1.0) / factor); + float n = 1.0f / slices; + for (int i = 1; i < slices; i++) { + interp_v2_v2v2(pt, a, b, n * i); + sub_v2_v2v2(pt, b, pt); + /* create fake event */ + gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), + (int)pt[0], (int)pt[1]); + } + } +} + /* events handling during interactive drawing part of operator */ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) { @@ -2488,10 +2827,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) * is essential for ensuring that they can quickly return to that view */ } - else if ((ELEM(event->type, p->keymodifier)) && (event->val == KM_RELEASE)) { - /* enable continuous if release D key in mid drawing */ - p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON; - } else if ((event->type == BKEY) && (event->val == KM_RELEASE)) { /* Add Blank Frame * - Since this operator is non-modal, we can just call it here, and keep going... @@ -2510,7 +2845,10 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* exit painting mode (and/or end current stroke) * NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647] */ - if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) { + /* if polyline and release shift must cancel */ + if ((ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY, EKEY)) || + ((p->paintmode == GP_PAINTMODE_DRAW_POLY) && (event->shift == 0))) + { /* exit() ends the current stroke before cleaning up */ /* printf("\t\tGP - end of paint op + end of stroke\n"); */ /* if drawing polygon and enable on back, must move stroke */ @@ -2537,10 +2875,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) int sketch = 0; /* basically, this should be mouse-button up = end stroke - * BUT what happens next depends on whether we 'painting sessions' is enabled + * BUT, polyline drawing is an exception -- all knots should be added during one session */ - sketch |= GPENCIL_SKETCH_SESSIONS_ON(p->scene); - /* polyline drawing is also 'sketching' -- all knots should be added during one session */ sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY); if (sketch) { @@ -2585,6 +2921,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } } } + /* drawing batch cache is dirty now */ + gp_update_cache(p->gpd); + p->status = GP_STATUS_DONE; estate = OPERATOR_FINISHED; } @@ -2689,7 +3028,9 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) { /* handle drawing event */ /* printf("\t\tGP - add point\n"); */ - gpencil_draw_apply_event(op, event, CTX_data_depsgraph(C)); + gpencil_add_missing_events(C, op, event, p); + + gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph(C), 0, 0); /* finish painting operation if anything went wrong just now */ if (p->status == GP_STATUS_ERROR) { @@ -2791,7 +3132,7 @@ void GPENCIL_OT_draw(wmOperatorType *ot) /* identifiers */ ot->name = "Grease Pencil Draw"; ot->idname = "GPENCIL_OT_draw"; - ot->description = "Make annotations on the active data"; + ot->description = "Draw a new stroke in the active Grease Pencil Object"; /* api callbacks */ ot->exec = gpencil_draw_exec; @@ -2811,5 +3152,11 @@ void GPENCIL_OT_draw(wmOperatorType *ot) /* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, "disable_straight", false, "No Straight lines", "Disable key for straight lines"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_boolean(ot->srna, "disable_fill", false, "No Fill Areas", "Disable fill to use stroke as fill boundary"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c new file mode 100644 index 00000000000..ef09c5c3f76 --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -0,0 +1,712 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + * Operators for creating new Grease Pencil primitives (boxes, circles, ...) + */ + +/** \file blender/editors/gpencil/gpencil_primitive.c + * \ingroup edgpencil + */ + + +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "BLT_translation.h" + +#include "DNA_brush_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BKE_main.h" +#include "BKE_brush.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_library.h" +#include "BKE_material.h" +#include "BKE_paint.h" +#include "BKE_report.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "ED_gpencil.h" +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_space_api.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "gpencil_intern.h" + +#define MIN_EDGES 2 +#define MAX_EDGES 100 + +#define IDLE 0 +#define IN_PROGRESS 1 + +/* ************************************************ */ +/* Core/Shared Utilities */ + +/* Poll callback for primitive operators */ +static bool gpencil_primitive_add_poll(bContext *C) +{ + /* only 3D view */ + ScrArea *sa = CTX_wm_area(C); + if (sa && sa->spacetype != SPACE_VIEW3D) { + return 0; + } + + /* need data to create primitive */ + bGPdata *gpd = CTX_data_gpencil_data(C); + if (gpd == NULL) { + return 0; + } + + /* only in edit and paint modes + * - paint as it's the "drawing/creation mode" + * - edit as this is more of an atomic editing operation + * (similar to copy/paste), and also for consistency + */ + if ((gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE)) == 0) { + CTX_wm_operator_poll_msg_set(C, "Primitives can only be added in Draw or Edit modes"); + return 0; + } + + /* don't allow operator to function if the active layer is locked/hidden + * (BUT, if there isn't an active layer, we are free to add new layer when the time comes) + */ + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + if ((gpl) && (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE))) { + CTX_wm_operator_poll_msg_set(C, "Primitives cannot be added as active layer is locked or hidden"); + return 0; + } + + return 1; +} + + +/* ****************** Primitive Interactive *********************** */ + +/* Helper: Create internal strokes primitives data */ +static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + Brush *brush; + + /* if brush doesn't exist, create a new one */ + Paint *paint = BKE_brush_get_gpencil_paint(ts); + /* if not exist, create a new one */ + if (paint->brush == NULL) { + /* create new brushes */ + BKE_brush_gpencil_presets(C); + brush = BKE_brush_getactive_gpencil(ts); + } + else { + /* Use the current */ + brush = BKE_brush_getactive_gpencil(ts); + } + tgpi->brush = brush; + + /* if layer doesn't exist, create a new one */ + if (gpl == NULL) { + gpl = BKE_gpencil_layer_addnew(tgpi->gpd, DATA_("Primitives"), true); + } + tgpi->gpl = gpl; + + /* create a new temporary frame */ + tgpi->gpf = MEM_callocN(sizeof(bGPDframe), "Temp bGPDframe"); + tgpi->gpf->framenum = tgpi->cframe = cfra_eval; + + /* create new temp stroke */ + bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke"); + gps->thickness = 2.0f; + gps->inittime = 0.0f; + + /* enable recalculation flag by default */ + gps->flag |= GP_STROKE_RECALC_CACHES; + /* the polygon must be closed, so enabled cyclic */ + gps->flag |= GP_STROKE_CYCLIC; + gps->flag |= GP_STROKE_3DSPACE; + + gps->mat_nr = BKE_object_material_slot_find_index(tgpi->ob, tgpi->mat) - 1; + + /* allocate memory for storage points, but keep empty */ + gps->totpoints = 0; + gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert), "gp_stroke_weights"); + /* initialize triangle memory to dummy data */ + gps->tot_triangles = 0; + gps->triangles = NULL; + gps->flag |= GP_STROKE_RECALC_CACHES; + + /* add to strokes */ + BLI_addtail(&tgpi->gpf->strokes, gps); +} + +/* ----------------------- */ +/* Drawing Callbacks */ + +/* Drawing callback for modal operator in 3d mode */ +static void gpencil_primitive_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg) +{ + tGPDprimitive *tgpi = (tGPDprimitive *)arg; + ED_gp_draw_primitives(C, tgpi, REGION_DRAW_POST_VIEW); +} + +/* ----------------------- */ + +/* Helper: Draw status message while the user is running the operator */ +static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi) +{ + Scene *scene = tgpi->scene; + char status_str[UI_MAX_DRAW_STR]; + char msg_str[UI_MAX_DRAW_STR]; + + if (tgpi->type == GP_STROKE_BOX) { + BLI_strncpy(msg_str, IFACE_("Rectangle: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm, Shift to square"), UI_MAX_DRAW_STR); + } + else if (tgpi->type == GP_STROKE_LINE) { + BLI_strncpy(msg_str, IFACE_("Line: ESC/RMB to cancel, LMB set origin, Enter/LMB to confirm"), UI_MAX_DRAW_STR); + } + else { + BLI_strncpy(msg_str, IFACE_("Circle: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL to adjust edge number, Shift to square"), UI_MAX_DRAW_STR); + } + + if (tgpi->type == GP_STROKE_CIRCLE) { + if (hasNumInput(&tgpi->num)) { + char str_offs[NUM_STR_REP_LEN]; + + outputNumInput(&tgpi->num, str_offs, &scene->unit); + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); + } + else { + if (tgpi->flag == IN_PROGRESS) { + BLI_snprintf(status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, (int)tgpi->tot_edges, + tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, (int)tgpi->tot_edges, + tgpi->bottom[0], tgpi->bottom[1]); + } + } + } + else { + if (tgpi->flag == IN_PROGRESS) { + BLI_snprintf(status_str, sizeof(status_str), "%s: (%d, %d) (%d, %d)", msg_str, + tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: (%d, %d)", msg_str, + tgpi->bottom[0], tgpi->bottom[1]); + } + } + ED_workspace_status_text(C, status_str); +} + +/* ----------------------- */ + +/* create a rectangle */ +static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D) +{ + BLI_assert(tgpi->tot_edges == 4); + + points2D[0].x = tgpi->top[0]; + points2D[0].y = tgpi->top[1]; + + points2D[1].x = tgpi->bottom[0]; + points2D[1].y = tgpi->top[1]; + + points2D[2].x = tgpi->bottom[0]; + points2D[2].y = tgpi->bottom[1]; + + points2D[3].x = tgpi->top[0]; + points2D[3].y = tgpi->bottom[1]; +} + +/* create a line */ +static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D) +{ + BLI_assert(tgpi->tot_edges == 2); + + points2D[0].x = tgpi->top[0]; + points2D[0].y = tgpi->top[1]; + + points2D[1].x = tgpi->bottom[0]; + points2D[1].y = tgpi->bottom[1]; +} + +/* create a circle */ +static void gp_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D) +{ + const int totpoints = tgpi->tot_edges; + const float step = (2.0f * M_PI) / (float)(totpoints); + float center[2]; + float radius[2]; + float a = 0.0f; + + /* TODO: Use math-lib functions for these? */ + center[0] = tgpi->top[0] + ((tgpi->bottom[0] - tgpi->top[0]) / 2.0f); + center[1] = tgpi->top[1] + ((tgpi->bottom[1] - tgpi->top[1]) / 2.0f); + radius[0] = fabsf(((tgpi->bottom[0] - tgpi->top[0]) / 2.0f)); + radius[1] = fabsf(((tgpi->bottom[1] - tgpi->top[1]) / 2.0f)); + + for (int i = 0; i < totpoints; i++) { + tGPspoint *p2d = &points2D[i]; + + p2d->x = (int)(center[0] + cosf(a) * radius[0]); + p2d->y = (int)(center[1] + sinf(a) * radius[1]); + a += step; + } +} + +/* Helper: Update shape of the stroke */ +static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) +{ + ToolSettings *ts = tgpi->scene->toolsettings; + bGPdata *gpd = tgpi->gpd; + bGPDstroke *gps = tgpi->gpf->strokes.first; + + /* realloc points to new size */ + /* TODO: only do this if the size has changed? */ + gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * tgpi->tot_edges); + gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * tgpi->tot_edges); + gps->totpoints = tgpi->tot_edges; + + /* compute screen-space coordinates for points */ + tGPspoint *points2D = MEM_callocN(sizeof(tGPspoint) * tgpi->tot_edges, "gp primitive points2D"); + switch (tgpi->type) { + case GP_STROKE_BOX: + gp_primitive_rectangle(tgpi, points2D); + break; + case GP_STROKE_LINE: + gp_primitive_line(tgpi, points2D); + break; + case GP_STROKE_CIRCLE: + gp_primitive_circle(tgpi, points2D); + break; + default: + break; + } + + /* convert screen-coordinates to 3D coordinates */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + tGPspoint *p2d = &points2D[i]; + + + /* convert screen-coordinates to 3D coordinates */ + gp_stroke_convertcoords_tpoint(tgpi->scene, tgpi->ar, tgpi->v3d, tgpi->ob, tgpi->gpl, p2d, NULL, &pt->x); + + pt->pressure = 1.0f; + pt->strength = tgpi->brush->gpencil_settings->draw_strength; + pt->time = 0.0f; + + dvert->totweight = 0; + dvert->dw = NULL; + } + + /* if axis locked, reproject to plane locked */ + if (tgpi->lock_axis > GP_LOCKAXIS_NONE) { + bGPDspoint *tpt = gps->points; + float origin[3]; + ED_gp_get_drawing_reference(tgpi->v3d, tgpi->scene, tgpi->ob, tgpi->gpl, + ts->gpencil_v3d_align, origin); + + for (int i = 0; i < gps->totpoints; i++, tpt++) { + ED_gp_project_point_to_plane(tgpi->ob, tgpi->rv3d, origin, + ts->gp_sculpt.lock_axis - 1, + tpt); + } + } + + /* if parented change position relative to parent object */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + gp_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpd, tgpi->gpl, pt); + } + + /* force fill recalc */ + gps->flag |= GP_STROKE_RECALC_CACHES; + + /* free temp data */ + MEM_SAFE_FREE(points2D); + + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); +} + +/* Update screen and stroke */ +static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive *tgpi) +{ + /* update indicator in header */ + gpencil_primitive_status_indicators(C, tgpi); + /* apply... */ + tgpi->type = RNA_enum_get(op->ptr, "type"); + tgpi->tot_edges = RNA_int_get(op->ptr, "edges"); + /* update points position */ + gp_primitive_update_strokes(C, tgpi); +} + +/* ----------------------- */ + +/* Exit and free memory */ +static void gpencil_primitive_exit(bContext *C, wmOperator *op) +{ + tGPDprimitive *tgpi = op->customdata; + bGPdata *gpd = tgpi->gpd; + + /* don't assume that operator data exists at all */ + if (tgpi) { + /* remove drawing handler */ + if (tgpi->draw_handle_3d) { + ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); + } + + /* clear status message area */ + ED_workspace_status_text(C, NULL); + + /* finally, free memory used by temp data */ + BKE_gpencil_free_strokes(tgpi->gpf); + MEM_freeN(tgpi->gpf); + MEM_freeN(tgpi); + } + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + + /* clear pointer */ + op->customdata = NULL; +} + +/* Init new temporary primitive data */ +static void gpencil_primitive_init(bContext *C, wmOperator *op) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); + + /* create temporary operator data */ + tGPDprimitive *tgpi = MEM_callocN(sizeof(tGPDprimitive), "GPencil Primitive Data"); + op->customdata = tgpi; + + /* set current scene and window info */ + tgpi->scene = scene; + tgpi->ob = CTX_data_active_object(C); + tgpi->sa = CTX_wm_area(C); + tgpi->ar = CTX_wm_region(C); + tgpi->rv3d = tgpi->ar->regiondata; + tgpi->v3d = tgpi->sa->spacedata.first; + tgpi->depsgraph = CTX_data_depsgraph(C); + tgpi->win = CTX_wm_window(C); + + /* set current frame number */ + tgpi->cframe = cfra_eval; + + /* set GP datablock */ + tgpi->gpd = gpd; + + /* getcolor info */ + tgpi->mat = BKE_gpencil_material_ensure(bmain, tgpi->ob); + + /* set parameters */ + tgpi->type = RNA_enum_get(op->ptr, "type"); + + /* if circle set default to 32 */ + if (tgpi->type == GP_STROKE_CIRCLE) { + RNA_int_set(op->ptr, "edges", 32); + } + else if(tgpi->type == GP_STROKE_BOX) { + RNA_int_set(op->ptr, "edges", 4); + } + else { /* LINE */ + RNA_int_set(op->ptr, "edges", 2); + } + + tgpi->tot_edges = RNA_int_get(op->ptr, "edges"); + tgpi->flag = IDLE; + + tgpi->lock_axis = ts->gp_sculpt.lock_axis; + + /* set temp layer, frame and stroke */ + gp_primitive_set_initdata(C, tgpi); +} + +/* ----------------------- */ + +/* Invoke handler: Initialize the operator */ +static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + wmWindow *win = CTX_wm_window(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + tGPDprimitive *tgpi = NULL; + + /* initialize operator runtime data */ + gpencil_primitive_init(C, op); + tgpi = op->customdata; + + /* if in tools region, wait till we get to the main (3d-space) + * region before allowing drawing to take place. + */ + op->flag |= OP_IS_MODAL_CURSOR_REGION; + + /* Enable custom drawing handlers */ + tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_primitive_draw_3d, tgpi, REGION_DRAW_POST_VIEW); + + /* set cursor to indicate modal */ + WM_cursor_modal_set(win, BC_CROSSCURSOR); + + /* update sindicator in header */ + gpencil_primitive_status_indicators(C, tgpi); + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + + /* add a modal handler for this operator */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +/* Helper to complete a primitive */ +static void gpencil_primitive_done(bContext *C, wmOperator *op, wmWindow *win, tGPDprimitive *tgpi) +{ + bGPDframe *gpf; + bGPDstroke *gps; + + /* return to normal cursor and header status */ + ED_workspace_status_text(C, NULL); + WM_cursor_modal_restore(win); + + /* insert keyframes as required... */ + gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); + + /* prepare stroke to get transfered */ + gps = tgpi->gpf->strokes.first; + if (gps) { + gps->thickness = tgpi->brush->size; + gps->flag |= GP_STROKE_RECALC_CACHES; + } + + /* transfer stroke from temporary buffer to the actual frame */ + BLI_movelisttolist(&gpf->strokes, &tgpi->gpf->strokes); + BLI_assert(BLI_listbase_is_empty(&tgpi->gpf->strokes)); + + /* clean up temp data */ + gpencil_primitive_exit(C, op); +} + +/* Modal handler: Events handling during interactive part */ +static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + tGPDprimitive *tgpi = op->customdata; + wmWindow *win = CTX_wm_window(C); + const bool has_numinput = hasNumInput(&tgpi->num); + + switch (event->type) { + case LEFTMOUSE: + if ((event->val == KM_PRESS) && (tgpi->flag == IDLE)) { + /* start drawing primitive */ + /* TODO: Ignore if not in main region yet */ + tgpi->flag = IN_PROGRESS; + + tgpi->top[0] = event->mval[0]; + tgpi->top[1] = event->mval[1]; + + tgpi->bottom[0] = event->mval[0]; + tgpi->bottom[1] = event->mval[1]; + } + else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) { + /* stop drawing primitive */ + tgpi->flag = IDLE; + gpencil_primitive_done(C, op, win, tgpi); + /* done! */ + return OPERATOR_FINISHED; + } + else { + if (G.debug & G_DEBUG) { + printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag); + } + } + break; + case RETKEY: /* confirm */ + { + tgpi->flag = IDLE; + gpencil_primitive_done(C, op, win, tgpi); + /* done! */ + return OPERATOR_FINISHED; + } + + case ESCKEY: /* cancel */ + case RIGHTMOUSE: + { + /* return to normal cursor and header status */ + ED_workspace_status_text(C, NULL); + WM_cursor_modal_restore(win); + + /* clean up temp data */ + gpencil_primitive_exit(C, op); + + /* canceled! */ + return OPERATOR_CANCELLED; + } + + case WHEELUPMOUSE: + { + if (tgpi->type == GP_STROKE_CIRCLE) { + tgpi->tot_edges = tgpi->tot_edges + 1; + CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + RNA_int_set(op->ptr, "edges", tgpi->tot_edges); + + /* update screen */ + gpencil_primitive_update(C, op, tgpi); + } + break; + } + case WHEELDOWNMOUSE: + { + if (tgpi->type == GP_STROKE_CIRCLE) { + tgpi->tot_edges = tgpi->tot_edges - 1; + CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + RNA_int_set(op->ptr, "edges", tgpi->tot_edges); + + /* update screen */ + gpencil_primitive_update(C, op, tgpi); + } + break; + } + case MOUSEMOVE: /* calculate new position */ + { + /* only handle mousemove if not doing numinput */ + if (has_numinput == false) { + /* update position of mouse */ + tgpi->bottom[0] = event->mval[0]; + tgpi->bottom[1] = event->mval[1]; + if (tgpi->flag == IDLE) { + tgpi->top[0] = event->mval[0]; + tgpi->top[1] = event->mval[1]; + } + /* Keep square if shift key */ + if (event->shift) { + tgpi->bottom[1] = tgpi->top[1] - (tgpi->bottom[0] - tgpi->top[0]); + } + /* update screen */ + gpencil_primitive_update(C, op, tgpi); + } + break; + } + default: + { + if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) { + float value; + + /* Grab data from numeric input, and store this new value (the user see an int) */ + value = tgpi->tot_edges; + applyNumInput(&tgpi->num, &value); + tgpi->tot_edges = value; + + CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + RNA_int_set(op->ptr, "edges", tgpi->tot_edges); + + /* update screen */ + gpencil_primitive_update(C, op, tgpi); + + break; + } + else { + /* unhandled event - allow to pass through */ + return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; + } + } + } + + /* still running... */ + return OPERATOR_RUNNING_MODAL; +} + +/* Cancel handler */ +static void gpencil_primitive_cancel(bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + gpencil_primitive_exit(C, op); +} + +void GPENCIL_OT_primitive(wmOperatorType *ot) +{ + static EnumPropertyItem primitive_type[] = { + { GP_STROKE_BOX, "BOX", 0, "Box", "" }, + { GP_STROKE_LINE, "LINE", 0, "Line", "" }, + { GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", "" }, + { 0, NULL, 0, NULL, NULL } + }; + + /* identifiers */ + ot->name = "Grease Pencil Shapes"; + ot->idname = "GPENCIL_OT_primitive"; + ot->description = "Create predefined grease pencil stroke shapes"; + + /* callbacks */ + ot->invoke = gpencil_primitive_invoke; + ot->modal = gpencil_primitive_modal; + ot->cancel = gpencil_primitive_cancel; + ot->poll = gpencil_primitive_add_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* properties */ + RNA_def_int(ot->srna, "edges", 4, MIN_EDGES, MAX_EDGES, "Edges", "Number of polygon edges", MIN_EDGES, MAX_EDGES); + RNA_def_enum(ot->srna, "type", primitive_type, GP_STROKE_BOX, "Type", "Type of shape"); +} + +/* *************************************************************** */ diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index dd556e99264..9386bfb3333 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -43,6 +43,7 @@ #include "DNA_gpencil_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "DNA_screen_types.h" #include "DNA_object_types.h" @@ -62,6 +63,9 @@ #include "ED_gpencil.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + #include "gpencil_intern.h" /* ********************************************** */ @@ -71,8 +75,8 @@ static bool gpencil_select_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); - /* we just need some visible strokes, and to be in editmode */ - if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { + /* we just need some visible strokes, and to be in editmode or other modes only to catch event */ + if (GPENCIL_ANY_MODE(gpd)) { /* TODO: include a check for visible strokes? */ if (gpd->layers.first) return true; @@ -94,6 +98,11 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + /* for "toggle", test for existing selected strokes */ if (action == SEL_TOGGLE) { action = SEL_SELECT; @@ -180,6 +189,11 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op) } /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -213,6 +227,11 @@ static int gpencil_select_linked_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + /* select all points in selected strokes */ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { @@ -228,6 +247,11 @@ static int gpencil_select_linked_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -247,6 +271,86 @@ void GPENCIL_OT_select_linked(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ********************************************** */ +/* Select Alternate */ + +static int gpencil_select_alternate_exec(bContext *C, wmOperator *op) +{ + const bool unselect_ends = RNA_boolean_get(op->ptr, "unselect_ends"); + bGPdata *gpd = ED_gpencil_data_get_active(C); + + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + + /* select all points in selected strokes */ + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) { + bGPDspoint *pt; + int row = 0; + int start = 0; + if (unselect_ends) { + start = 1; + } + + for (int i = start; i < gps->totpoints; i++) { + pt = &gps->points[i]; + if ((row % 2) == 0) { + pt->flag |= GP_SPOINT_SELECT; + } + else { + pt->flag &= ~GP_SPOINT_SELECT; + } + row++; + } + + /* unselect start and end points */ + if (unselect_ends) { + pt = &gps->points[0]; + pt->flag &= ~GP_SPOINT_SELECT; + + pt = &gps->points[gps->totpoints - 1]; + pt->flag &= ~GP_SPOINT_SELECT; + } + } + } + CTX_DATA_END; + + /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_select_alternate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Alternated"; + ot->idname = "GPENCIL_OT_select_alternate"; + ot->description = "Select alternative points in same strokes as already selected points"; + + /* callbacks */ + ot->exec = gpencil_select_alternate_exec; + ot->poll = gpencil_select_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "unselect_ends", true, "Unselect Ends", "Do not select the first and last point of the stroke"); +} + /* ********************************************** */ /* Select Grouped */ @@ -266,11 +370,12 @@ typedef enum eGP_SelectGrouped { /* On each visible layer, check for selected strokes - if found, select all others */ static void gp_select_same_layer(bContext *C) { - Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + int cfra_eval = (int)DEG_get_ctime(depsgraph); CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, 0); + bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, 0); bGPDstroke *gps; bool found = false; @@ -309,10 +414,7 @@ static void gp_select_same_layer(bContext *C) /* Select all strokes with same colors as selected ones */ static void gp_select_same_color(bContext *C) { - /* First, build set containing all the colors of selected strokes - * - We use the palette names, so that we can select all strokes with one - * (potentially missing) color, and remap them to something else - */ + /* First, build set containing all the colors of selected strokes */ GSet *selected_colors = BLI_gset_str_new("GP Selected Colors"); CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) @@ -321,7 +423,7 @@ static void gp_select_same_color(bContext *C) /* add instead of insert here, otherwise the uniqueness check gets skipped, * and we get many duplicate entries... */ - BLI_gset_add(selected_colors, gps->colorname); + BLI_gset_add(selected_colors, &gps->mat_nr); } } CTX_DATA_END; @@ -329,7 +431,7 @@ static void gp_select_same_color(bContext *C) /* Second, select any visible stroke that uses these colors */ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { - if (BLI_gset_haskey(selected_colors, gps->colorname)) { + if (BLI_gset_haskey(selected_colors, &gps->mat_nr)) { /* select this stroke */ bGPDspoint *pt; int i; @@ -342,6 +444,11 @@ static void gp_select_same_color(bContext *C) } } CTX_DATA_END; + + /* free memomy */ + if (selected_colors != NULL) { + BLI_gset_free(selected_colors, NULL); + } } @@ -350,6 +457,11 @@ static void gp_select_same_color(bContext *C) static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) { eGP_SelectGrouped mode = RNA_enum_get(op->ptr, "type"); + bGPdata *gpd = ED_gpencil_data_get_active(C); + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } switch (mode) { case GP_SEL_SAME_LAYER: @@ -365,6 +477,11 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op) } /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -399,6 +516,12 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot) static int gpencil_select_first_exec(bContext *C, wmOperator *op) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); const bool extend = RNA_boolean_get(op->ptr, "extend"); @@ -429,6 +552,11 @@ static int gpencil_select_first_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -459,6 +587,12 @@ void GPENCIL_OT_select_first(wmOperatorType *ot) static int gpencil_select_last_exec(bContext *C, wmOperator *op) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + const bool only_selected = RNA_boolean_get(op->ptr, "only_selected_strokes"); const bool extend = RNA_boolean_get(op->ptr, "extend"); @@ -489,6 +623,11 @@ static int gpencil_select_last_exec(bContext *C, wmOperator *op) CTX_DATA_END; /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -519,6 +658,12 @@ void GPENCIL_OT_select_last(wmOperatorType *ot) static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { if (gps->flag & GP_STROKE_SELECT) { @@ -565,6 +710,11 @@ static int gpencil_select_more_exec(bContext *C, wmOperator *UNUSED(op)) CTX_DATA_END; /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -589,6 +739,12 @@ void GPENCIL_OT_select_more(wmOperatorType *ot) static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) { if (gps->flag & GP_STROKE_SELECT) { @@ -636,6 +792,11 @@ static int gpencil_select_less_exec(bContext *C, wmOperator *UNUSED(op)) CTX_DATA_END; /* updates */ + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); return OPERATOR_FINISHED; } @@ -665,7 +826,7 @@ void GPENCIL_OT_select_less(wmOperatorType *ot) static bool gp_stroke_do_circle_sel( bGPDstroke *gps, GP_SpaceConversion *gsc, const int mx, const int my, const int radius, - const bool select, rcti *rect, const bool parented, float diff_mat[4][4]) + const bool select, rcti *rect, float diff_mat[4][4]) { bGPDspoint *pt1, *pt2; int x0 = 0, y0 = 0, x1 = 0, y1 = 0; @@ -673,14 +834,9 @@ static bool gp_stroke_do_circle_sel( bool changed = false; if (gps->totpoints == 1) { - if (!parented) { - gp_point_to_xy(gsc, gps, gps->points, &x0, &y0); - } - else { - bGPDspoint pt_temp; - gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); - gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); - } + bGPDspoint pt_temp; + gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); + gp_point_to_xy(gsc, gps, &pt_temp, &x0, &y0); /* do boundbox check first */ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) { @@ -708,18 +864,12 @@ static bool gp_stroke_do_circle_sel( /* get points to work with */ pt1 = gps->points + i; pt2 = gps->points + i + 1; - if (!parented) { - gp_point_to_xy(gsc, gps, pt1, &x0, &y0); - gp_point_to_xy(gsc, gps, pt2, &x1, &y1); - } - else { - bGPDspoint npt; - gp_point_to_parent_space(pt1, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &x0, &y0); + bGPDspoint npt; + gp_point_to_parent_space(pt1, diff_mat, &npt); + gp_point_to_xy(gsc, gps, &npt, &x0, &y0); - gp_point_to_parent_space(pt2, diff_mat, &npt); - gp_point_to_xy(gsc, gps, &npt, &x1, &y1); - } + gp_point_to_parent_space(pt2, diff_mat, &npt); + gp_point_to_xy(gsc, gps, &npt, &x1, &y1); /* check that point segment of the boundbox of the selection stroke */ if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) || @@ -763,6 +913,12 @@ static bool gp_stroke_do_circle_sel( static int gpencil_circle_select_exec(bContext *C, wmOperator *op) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + /* if not edit/sculpt mode, the event is catched but not processed */ + if (GPENCIL_NONE_EDIT_MODE(gpd)) { + return OPERATOR_CANCELLED; + } + ScrArea *sa = CTX_wm_area(C); const int mx = RNA_int_get(op->ptr, "x"); @@ -798,13 +954,17 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) { changed |= gp_stroke_do_circle_sel( - gps, &gsc, mx, my, radius, select, &rect, - (gpl->parent != NULL), diff_mat); + gps, &gsc, mx, my, radius, select, &rect, diff_mat); } GP_EDITABLE_STROKES_END; /* updates */ if (changed) { + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } @@ -837,10 +997,11 @@ void GPENCIL_OT_select_circle(wmOperatorType *ot) static int gpencil_border_select_exec(bContext *C, wmOperator *op) { + bGPdata *gpd = ED_gpencil_data_get_active(C); ScrArea *sa = CTX_wm_area(C); const bool select = !RNA_boolean_get(op->ptr, "deselect"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool extend = RNA_boolean_get(op->ptr, "extend") && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0); GP_SpaceConversion gsc = {NULL}; rcti rect = {0}; @@ -888,14 +1049,9 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op) int x0, y0; /* convert point coords to screenspace */ - if (gpl->parent == NULL) { - gp_point_to_xy(&gsc, gps, pt, &x0, &y0); - } - else { - bGPDspoint pt2; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); - } + bGPDspoint pt2; + gp_point_to_parent_space(pt, diff_mat, &pt2); + gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); /* test if in selection rect */ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) { @@ -915,8 +1071,20 @@ static int gpencil_border_select_exec(bContext *C, wmOperator *op) } GP_EDITABLE_STROKES_END; + /* if paint mode,delete selected points */ + if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { + gp_delete_selected_point_wrap(C); + changed = true; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + } + /* updates */ if (changed) { + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } @@ -950,10 +1118,11 @@ void GPENCIL_OT_select_border(wmOperatorType *ot) static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) { + bGPdata *gpd = ED_gpencil_data_get_active(C); GP_SpaceConversion gsc = {NULL}; rcti rect = {0}; - const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool extend = RNA_boolean_get(op->ptr, "extend") && ((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0); const bool select = !RNA_boolean_get(op->ptr, "deselect"); int mcords_tot; @@ -997,14 +1166,9 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) int x0, y0; /* convert point coords to screenspace */ - if (gpl->parent == NULL) { - gp_point_to_xy(&gsc, gps, pt, &x0, &y0); - } - else { - bGPDspoint pt2; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); - } + bGPDspoint pt2; + gp_point_to_parent_space(pt, diff_mat, &pt2); + gp_point_to_xy(&gsc, gps, &pt2, &x0, &y0); /* test if in lasso boundbox + within the lasso noose */ if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0) && BLI_lasso_is_point_inside(mcords, mcords_tot, x0, y0, INT_MAX)) @@ -1028,8 +1192,20 @@ static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) /* cleanup */ MEM_freeN((void *)mcords); + /* if paint mode,delete selected points */ + if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { + gp_delete_selected_point_wrap(C); + changed = true; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + } + /* updates */ if (changed) { + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } @@ -1061,6 +1237,7 @@ void GPENCIL_OT_select_lasso(wmOperatorType *ot) static int gpencil_select_exec(bContext *C, wmOperator *op) { ScrArea *sa = CTX_wm_area(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); /* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */ const float radius = 0.75f * U.widget_unit; @@ -1102,14 +1279,9 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { int xy[2]; - if (gpl->parent == NULL) { - gp_point_to_xy(&gsc, gps, pt, &xy[0], &xy[1]); - } - else { - bGPDspoint pt2; - gp_point_to_parent_space(pt, diff_mat, &pt2); - gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]); - } + bGPDspoint pt2; + gp_point_to_parent_space(pt, diff_mat, &pt2); + gp_point_to_xy(&gsc, gps, &pt2, &xy[0], &xy[1]); /* do boundbox check first */ if (!ELEM(V2D_IS_CLIPPED, xy[0], xy[1])) { @@ -1197,6 +1369,11 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) /* updates */ if (hit_point != NULL) { + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + + /* copy on write tag is needed, or else no refresh happens */ + DEG_id_tag_update(&gpd->id, DEG_TAG_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL); } diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index d35df8bc380..708d8f37e58 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" #include "DNA_gpencil_types.h" +#include "DNA_object_types.h" #include "DNA_listBase.h" #include "DNA_windowmanager_types.h" @@ -51,6 +52,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "DEG_depsgraph.h" + #include "gpencil_intern.h" typedef struct bGPundonode { @@ -111,6 +114,9 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) } } } + /* drawing batch cache is dirty now */ + DEG_id_tag_update(&new_gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + new_gpd->flag |= GP_DATA_CACHE_IS_DIRTY; } WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 8b65855f7c4..7262c537321 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -40,7 +40,9 @@ #include "BLT_translation.h" #include "BLI_rand.h" +#include "DNA_meshdata_types.h" #include "DNA_gpencil_types.h" +#include "DNA_brush_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -48,9 +50,13 @@ #include "DNA_view3d_types.h" #include "BKE_action.h" +#include "BKE_main.h" +#include "BKE_brush.h" #include "BKE_context.h" #include "BKE_gpencil.h" -#include "BKE_main.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_material.h" #include "BKE_tracking.h" #include "WM_api.h" @@ -65,8 +71,14 @@ #include "ED_gpencil.h" #include "ED_clip.h" #include "ED_view3d.h" +#include "ED_object.h" +#include "ED_screen.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "gpencil_intern.h" @@ -76,7 +88,7 @@ /* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it, * when context info is not available. */ -bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr) +bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob, PointerRNA *r_ptr) { /* if there's an active area, check if the particular editor may * have defined any special Grease Pencil context for editing... @@ -85,26 +97,37 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr SpaceLink *sl = sa->spacedata.first; switch (sa->spacetype) { - case SPACE_VIEW3D: /* 3D-View */ + /* XXX: Should we reduce reliance on context.gpencil_data for these cases? */ + case SPACE_BUTS: /* properties */ + case SPACE_INFO: /* header info (needed after workspaces merge) */ { - BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src, - GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT)); + if (ob && (ob->type == OB_GPENCIL)) { + /* GP Object */ + if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr); + return (bGPdata **)&ob->data; + } + else { + return NULL; + } - if (scene->toolsettings->gpencil_src == GP_TOOL_SOURCE_OBJECT) { - /* legacy behaviour for usage with old addons requiring object-linked to objects */ + break; + } - /* just in case no active/selected object... */ - if (ob && (ob->flag & SELECT)) { - /* for now, as long as there's an object, default to using that in 3D-View */ - if (ptr) RNA_id_pointer_create(&ob->id, ptr); - return &ob->gpd; - } - /* else: defaults to scene... */ + case SPACE_TOPBAR: /* Topbar (needed after topbar merge) */ + case SPACE_VIEW3D: /* 3D-View */ + { + if (ob && (ob->type == OB_GPENCIL)) { + /* GP Object */ + if (r_ptr) RNA_id_pointer_create(&ob->id, r_ptr); + return (bGPdata **)&ob->data; } else { - if (ptr) RNA_id_pointer_create(&scene->id, ptr); + /* Annotations */ + /* XXX: */ + if (r_ptr) RNA_id_pointer_create(&scene->id, r_ptr); return &scene->gpd; } + break; } case SPACE_NODE: /* Nodes Editor */ @@ -114,7 +137,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr /* return the GP data for the active node block/node */ if (snode && snode->nodetree) { /* for now, as long as there's an active node tree, default to using that in the Nodes Editor */ - if (ptr) RNA_id_pointer_create(&snode->nodetree->id, ptr); + if (r_ptr) RNA_id_pointer_create(&snode->nodetree->id, r_ptr); return &snode->nodetree->gpd; } @@ -127,7 +150,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr /* for now, Grease Pencil data is associated with the space (actually preview region only) */ /* XXX our convention for everything else is to link to data though... */ - if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, ptr); + if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceSequenceEditor, sseq, r_ptr); return &sseq->gpd; } case SPACE_IMAGE: /* Image/UV Editor */ @@ -136,7 +159,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr /* for now, Grease Pencil data is associated with the space... */ /* XXX our convention for everything else is to link to data though... */ - if (ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, ptr); + if (r_ptr) RNA_pointer_create(screen_id, &RNA_SpaceImageEditor, sima, r_ptr); return &sima->gpd; } case SPACE_CLIP: /* Nodes Editor */ @@ -151,15 +174,11 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr if (!track) return NULL; - if (ptr) - RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, ptr); - + if (r_ptr) RNA_pointer_create(&clip->id, &RNA_MovieTrackingTrack, track, r_ptr); return &track->gpd; } else { - if (ptr) - RNA_id_pointer_create(&clip->id, ptr); - + if (r_ptr) RNA_id_pointer_create(&clip->id, r_ptr); return &clip->gpd; } } @@ -170,79 +189,102 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr } } - /* just fall back on the scene's GP data */ - if (ptr) RNA_id_pointer_create((ID *)scene, ptr); - return (scene) ? &scene->gpd : NULL; + return NULL; } /* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */ -bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr) +bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr) { ID *screen_id = (ID *)CTX_wm_screen(C); Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); Object *ob = CTX_data_active_object(C); - return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr); + return ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, r_ptr); } /* -------------------------------------------------------- */ /* Get the active Grease Pencil datablock, when context is not available */ -bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob) +bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene, Object *ob) { - bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL); + bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, sa, scene, ob, NULL); return (gpd_ptr) ? *(gpd_ptr) : NULL; } -/* Get the active Grease Pencil datablock */ +/** + * Get the active Grease Pencil datablock + * \note This is the original (bmain) copy of the datablock, stored in files. + * Do not use for reading evaluated copies of GP Objects data + */ bGPdata *ED_gpencil_data_get_active(const bContext *C) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); return (gpd_ptr) ? *(gpd_ptr) : NULL; } +/** + * Get the evaluated copy of the active Grease Pencil datablock (where applicable) + * - For the 3D View (i.e. "GP Objects"), this gives the evaluated copy of the GP datablock + * (i.e. a copy of the active GP datablock for the active object, where modifiers have been + * applied). This is needed to correctly work with "Copy-on-Write" + * - For all other editors (i.e. "GP Annotations"), this just gives the active datablock + * like for ED_gpencil_data_get_active() + */ +bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C) +{ + ID *screen_id = (ID *)CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + + const Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *ob = CTX_data_active_object(C); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + + /* if (ob && ob->type == OB_GPENCIL) BLI_assert(ob_eval->data == DEG_get_evaluated_id(ob->data)); */ + return ED_gpencil_data_get_active_direct(screen_id, sa, scene_eval, ob_eval); +} + +/* -------------------------------------------------------- */ + +/** + * Utility to check whether the r_ptr output of ED_gpencil_data_get_pointers() + * is for annotation usage. + */ +bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr) +{ + /* Key Assumption: If the pointer is an object, we're dealing with a GP Object's data. + * Otherwise, the GP datablock is being used for annotations (i.e. everywhere else) + */ + return ((owner_ptr) && (owner_ptr->type != &RNA_Object)); +} + /* -------------------------------------------------------- */ // XXX: this should be removed... We really shouldn't duplicate logic like this! -bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, ViewLayer *view_layer) +bGPdata *ED_gpencil_data_get_active_v3d(ViewLayer *view_layer) { Base *base = view_layer->basact; bGPdata *gpd = NULL; + /* We have to make sure active object is actually visible and selected, else we must use default scene gpd, * to be consistent with ED_gpencil_data_get_active's behavior. */ - if (base && TESTBASE(base)) { - gpd = base->object->gpd; + if (base->object->type == OB_GPENCIL) + gpd = base->object->data; } - return gpd ? gpd : scene->gpd; + return gpd ? gpd : NULL; } /* ******************************************************** */ /* Keyframe Indicator Checks */ /* Check whether there's an active GP keyframe on the current frame */ -bool ED_gpencil_has_keyframe_v3d(Scene *scene, Object *ob, int cfra) +bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra) { - /* just check both for now... */ - // XXX: this could get confusing (e.g. if only on the object, but other places don't show this) - if (scene->gpd) { - bGPDlayer *gpl = BKE_gpencil_layer_getactive(scene->gpd); - if (gpl) { - if (gpl->actframe) { - // XXX: assumes that frame has been fetched already - return (gpl->actframe->framenum == cfra); - } - else { - /* XXX: disabled as could be too much of a penalty */ - /* return BKE_gpencil_layer_find_frame(gpl, cfra); */ - } - } - } - - if (ob && ob->gpd) { - bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->gpd); + if (ob && ob->data && (ob->type == OB_GPENCIL)) { + bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data); if (gpl) { if (gpl->actframe) { // XXX: assumes that frame has been fetched already @@ -281,28 +323,13 @@ bool gp_active_layer_poll(bContext *C) bool gp_active_brush_poll(bContext *C) { ToolSettings *ts = CTX_data_tool_settings(C); - bGPDbrush *brush = BKE_gpencil_brush_getactive(ts); - - return (brush != NULL); -} - -/* poll callback for checking if there is an active palette */ -bool gp_active_palette_poll(bContext *C) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - - return (palette != NULL); -} - -/* poll callback for checking if there is an active palette color */ -bool gp_active_palettecolor_poll(bContext *C) -{ - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - - return (palcolor != NULL); + Paint *paint = &ts->gp_paint->paint; + if (paint) { + return (paint->brush != NULL); + } + else { + return false; + } } /* ******************************************************** */ @@ -360,7 +387,7 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf( /* Create new layer */ /* TODO: have some way of specifying that we don't want this? */ { - /* active Keying Set */ + /* "New Layer" entry */ item_tmp.identifier = "__CREATE__"; item_tmp.name = "New Layer"; item_tmp.value = -1; @@ -392,7 +419,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf( } - /* ******************************************************** */ /* Brush Tool Core */ @@ -426,7 +452,7 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]), /* Stroke Validity Testing */ /* Check whether given stroke can be edited given the supplied context */ -// XXX: do we need additional flags for screenspace vs dataspace? +/* TODO: do we need additional flags for screenspace vs dataspace? */ bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps) { /* sanity check */ @@ -436,7 +462,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps) /* filter stroke types by flags + spacetype */ if (gps->flag & GP_STROKE_3DSPACE) { /* 3D strokes - only in 3D view */ - return (sa->spacetype == SPACE_VIEW3D); + return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_BUTS)); } else if (gps->flag & GP_STROKE_2DIMAGE) { /* Special "image" strokes - only in Image Editor */ @@ -460,59 +486,21 @@ bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps) } /* Check whether given stroke can be edited for the current color */ -bool ED_gpencil_stroke_color_use(const bGPDlayer *gpl, const bGPDstroke *gps) +bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps) { /* check if the color is editable */ - bGPDpalettecolor *palcolor = gps->palcolor; - if (palcolor != NULL) { - if (palcolor->flag & PC_COLOR_HIDE) + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + + if (gp_style != NULL) { + if (gp_style->flag & GP_STYLE_COLOR_HIDE) return false; - if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (palcolor->flag & PC_COLOR_LOCKED)) + if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED)) return false; } return true; } -/* Get palette color or create a new one */ -bGPDpalettecolor *ED_gpencil_stroke_getcolor(bGPdata *gpd, bGPDstroke *gps) -{ - bGPDpalette *palette; - bGPDpalettecolor *palcolor; - - if ((gps->palcolor != NULL) && ((gps->flag & GP_STROKE_RECALC_COLOR) == 0)) - return gps->palcolor; - - /* get palette */ - palette = BKE_gpencil_palette_getactive(gpd); - if (palette == NULL) { - palette = BKE_gpencil_palette_addnew(gpd, DATA_("GP_Palette"), true); - } - /* get color */ - palcolor = BKE_gpencil_palettecolor_getbyname(palette, gps->colorname); - if (palcolor == NULL) { - if (gps->palcolor == NULL) { - palcolor = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true); - /* set to a different color */ - ARRAY_SET_ITEMS(palcolor->color, 1.0f, 0.0f, 1.0f, 0.9f); - } - else { - palcolor = BKE_gpencil_palettecolor_addnew(palette, gps->colorname, true); - /* set old color and attributes */ - bGPDpalettecolor *gpscolor = gps->palcolor; - copy_v4_v4(palcolor->color, gpscolor->color); - copy_v4_v4(palcolor->fill, gpscolor->fill); - palcolor->flag = gpscolor->flag; - } - } - - /* clear flag and set pointer */ - gps->flag &= ~GP_STROKE_RECALC_COLOR; - gps->palcolor = palcolor; - - return palcolor; -} - /* ******************************************************** */ /* Space Conversion */ @@ -573,9 +561,9 @@ void gp_point_to_parent_space(bGPDspoint *pt, float diff_mat[4][4], bGPDspoint * } /** - * Change points position relative to parent object + * Change position relative to parent object */ -void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps) +void gp_apply_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDstroke *gps) { bGPDspoint *pt; int i; @@ -585,7 +573,7 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps) float inverse_diff_mat[4][4]; float fpt[3]; - ED_gpencil_parent_location(gpl, diff_mat); + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); for (i = 0; i < gps->totpoints; i++) { @@ -598,14 +586,14 @@ void gp_apply_parent(bGPDlayer *gpl, bGPDstroke *gps) /** * Change point position relative to parent object */ -void gp_apply_parent_point(bGPDlayer *gpl, bGPDspoint *pt) +void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPdata *gpd, bGPDlayer *gpl, bGPDspoint *pt) { /* undo matrix */ float diff_mat[4][4]; float inverse_diff_mat[4][4]; float fpt[3]; - ED_gpencil_parent_location(gpl, diff_mat); + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x); @@ -770,194 +758,259 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen } /** - * Apply smooth to stroke point - * \param gps Stroke to smooth - * \param i Point index - * \param inf Amount of smoothing to apply - * \param affect_pressure Apply smoothing to pressure values too? + * Convert tGPspoint (temporary 2D/screenspace point data used by GP modal operators) + * to 3D coordinates. + * + * \param point2D: The screenspace 2D point data to convert + * \param depth: Depth array (via ED_view3d_autodist_depth()) + * \param[out] r_out: The resulting 2D point data */ -bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) +void gp_stroke_convertcoords_tpoint( + Scene *scene, ARegion *ar, View3D *v3d, + Object *ob, bGPDlayer *gpl, + const tGPspoint *point2D, float *depth, + float r_out[3]) { - bGPDspoint *pt = &gps->points[i]; - float pressure = 0.0f; - float sco[3] = {0.0f}; - - /* Do nothing if not enough points to smooth out */ - if (gps->totpoints <= 2) { - return false; - } + ToolSettings *ts = scene->toolsettings; + const int mval[2] = {point2D->x, point2D->y}; - /* Only affect endpoints by a fraction of the normal strength, - * to prevent the stroke from shrinking too much - */ - if ((i == 0) || (i == gps->totpoints - 1)) { - inf *= 0.1f; + if ((depth != NULL) && (ED_view3d_autodist_simple(ar, mval, r_out, 0, depth))) { + /* projecting onto 3D-Geometry + * - nothing more needs to be done here, since view_autodist_simple() has already done it + */ } - - /* Compute smoothed coordinate by taking the ones nearby */ - /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */ - { - // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total) - const int steps = 2; - const float average_fac = 1.0f / (float)(steps * 2 + 1); - int step; - - /* add the point itself */ - madd_v3_v3fl(sco, &pt->x, average_fac); - - if (affect_pressure) { - pressure += pt->pressure * average_fac; + else { + float mval_f[2] = {(float)point2D->x, (float)point2D->y}; + float mval_prj[2]; + float rvec[3], dvec[3]; + float zfac; + + /* Current method just converts each point in screen-coordinates to + * 3D-coordinates using the 3D-cursor as reference. + */ + ED_gp_get_drawing_reference(v3d, scene, ob, gpl, ts->gpencil_v3d_align, rvec); + zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL); + + if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + sub_v2_v2v2(mval_f, mval_prj, mval_f); + ED_view3d_win_to_delta(ar, mval_f, dvec, zfac); + sub_v3_v3v3(r_out, rvec, dvec); } + else { + zero_v3(r_out); + } + } +} - /* n-steps before/after current point */ - // XXX: review how the endpoints are treated by this algorithm - // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight - for (step = 1; step <= steps; step++) { - bGPDspoint *pt1, *pt2; - int before = i - step; - int after = i + step; - - CLAMP_MIN(before, 0); - CLAMP_MAX(after, gps->totpoints - 1); - - pt1 = &gps->points[before]; - pt2 = &gps->points[after]; - - /* add both these points to the average-sum (s += p[i]/n) */ - madd_v3_v3fl(sco, &pt1->x, average_fac); - madd_v3_v3fl(sco, &pt2->x, average_fac); - -#if 0 - /* XXX: Disabled because get weird result */ - /* do pressure too? */ - if (affect_pressure) { - pressure += pt1->pressure * average_fac; - pressure += pt2->pressure * average_fac; +/** + * Get drawing reference point for conversion or projection of the stroke + * \param[out] r_vec : Reference point found + */ +void ED_gp_get_drawing_reference( + View3D *v3d, Scene *scene, Object *ob, bGPDlayer *UNUSED(gpl), + char align_flag, float r_vec[3]) +{ + const float *fp = ED_view3d_cursor3d_get(scene, v3d)->location; + + /* if using a gpencil object at cursor mode, can use the location of the object */ + if (align_flag & GP_PROJECT_VIEWSPACE) { + if (ob && (ob->type == OB_GPENCIL)) { + /* fallback (no strokes) - use cursor or object location */ + if (align_flag & GP_PROJECT_CURSOR) { + /* use 3D-cursor */ + copy_v3_v3(r_vec, fp); + } + else { + /* use object location */ + copy_v3_v3(r_vec, ob->obmat[3]); } -#endif } } - - /* Based on influence factor, blend between original and optimal smoothed coordinate */ - interp_v3_v3v3(&pt->x, &pt->x, sco, inf); - -#if 0 - /* XXX: Disabled because get weird result */ - if (affect_pressure) { - pt->pressure = pressure; + else { + /* use 3D-cursor */ + copy_v3_v3(r_vec, fp); } -#endif - - return true; } + /** -* Apply smooth for strength to stroke point -* \param gps Stroke to smooth -* \param i Point index -* \param inf Amount of smoothing to apply -*/ -bool gp_smooth_stroke_strength(bGPDstroke *gps, int i, float inf) + * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset + */ +void ED_gp_project_stroke_to_plane(Object *ob, RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis) { - bGPDspoint *ptb = &gps->points[i]; - - /* Do nothing if not enough points */ - if (gps->totpoints <= 2) { - return false; + float plane_normal[3]; + float vn[3]; + + float ray[3]; + float rpoint[3]; + + /* normal vector for a plane locked to axis */ + zero_v3(plane_normal); + if (axis < 0) { + /* if the axis is not locked, need a vector to the view direction + * in order to get the right size of the stroke. + */ + ED_view3d_global_to_vector(rv3d, origin, plane_normal); + } + else { + plane_normal[axis] = 1.0f; + /* if object, apply object rotation */ + if (ob && (ob->type == OB_GPENCIL)) { + mul_mat3_m4_v3(ob->obmat, plane_normal); + } } - /* Compute theoretical optimal value using distances */ - bGPDspoint *pta, *ptc; - int before = i - 1; - int after = i + 1; - - CLAMP_MIN(before, 0); - CLAMP_MAX(after, gps->totpoints - 1); - - pta = &gps->points[before]; - ptc = &gps->points[after]; + /* Reproject the points in the plane */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; - /* the optimal value is the corresponding to the interpolation of the strength - * at the distance of point b - */ - const float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); - const float optimal = (1.0f - fac) * pta->strength + fac * ptc->strength; + /* get a vector from the point with the current view direction of the viewport */ + ED_view3d_global_to_vector(rv3d, &pt->x, vn); - /* Based on influence factor, blend between original and optimal */ - ptb->strength = (1.0f - inf) * ptb->strength + inf * optimal; + /* calculate line extreme point to create a ray that cross the plane */ + mul_v3_fl(vn, -50.0f); + add_v3_v3v3(ray, &pt->x, vn); - return true; + /* if the line never intersect, the point is not changed */ + if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) { + copy_v3_v3(&pt->x, rpoint); + } + } } /** -* Apply smooth for thickness to stroke point (use pressure) -* \param gps Stroke to smooth -* \param i Point index -* \param inf Amount of smoothing to apply -*/ -bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf) + * Reproject given point to a plane locked to axis to avoid stroke offset + * \param[in, out] pt : Point to affect + */ +void ED_gp_project_point_to_plane(Object *ob, RegionView3D *rv3d, const float origin[3], const int axis, bGPDspoint *pt) { - bGPDspoint *ptb = &gps->points[i]; - - /* Do nothing if not enough points */ - if (gps->totpoints <= 2) { - return false; + float plane_normal[3]; + float vn[3]; + + float ray[3]; + float rpoint[3]; + + /* normal vector for a plane locked to axis */ + zero_v3(plane_normal); + if (axis < 0) { + /* if the axis is not locked, need a vector to the view direction + * in order to get the right size of the stroke. + */ + ED_view3d_global_to_vector(rv3d, origin, plane_normal); + } + else { + plane_normal[axis] = 1.0f; + /* if object, apply object rotation */ + if (ob && (ob->type == OB_GPENCIL)) { + mul_mat3_m4_v3(ob->obmat, plane_normal); + } } - /* Compute theoretical optimal value using distances */ - bGPDspoint *pta, *ptc; - int before = i - 1; - int after = i + 1; - - CLAMP_MIN(before, 0); - CLAMP_MAX(after, gps->totpoints - 1); - - pta = &gps->points[before]; - ptc = &gps->points[after]; - /* the optimal value is the corresponding to the interpolation of the pressure - * at the distance of point b - */ - float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x); - float optimal = (1.0f - fac) * pta->pressure + fac * ptc->pressure; + /* Reproject the points in the plane */ + /* get a vector from the point with the current view direction of the viewport */ + ED_view3d_global_to_vector(rv3d, &pt->x, vn); - /* Based on influence factor, blend between original and optimal */ - ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal; + /* calculate line extrem point to create a ray that cross the plane */ + mul_v3_fl(vn, -50.0f); + add_v3_v3v3(ray, &pt->x, vn); - return true; + /* if the line never intersect, the point is not changed */ + if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) { + copy_v3_v3(&pt->x, rpoint); + } } +/* ******************************************************** */ +/* Stroke Operations */ +// XXX: Check if these functions duplicate stuff in blenkernel, and/or whether we should just deduplicate + /** * Subdivide a stroke once, by adding a point half way between each pair of existing points * \param gps Stroke data - * \param new_totpoints Total number of points (after subdividing) + * \param subdivide Number of times to subdivide */ -void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints) +void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide) { - /* Move points towards end of enlarged points array to leave space for new points */ - int y = 1; - for (int i = gps->totpoints - 1; i > 0; i--) { - gps->points[new_totpoints - y] = gps->points[i]; - y += 2; - } + bGPDspoint *temp_points; + int totnewpoints, oldtotpoints; + int i2; + + /* loop as many times as levels */ + for (int s = 0; s < subdivide; s++) { + totnewpoints = gps->totpoints - 1; + /* duplicate points in a temp area */ + temp_points = MEM_dupallocN(gps->points); + oldtotpoints = gps->totpoints; + + /* resize the points arrys */ + gps->totpoints += totnewpoints; + gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + gps->flag |= GP_STROKE_RECALC_CACHES; + + /* move points from last to first to new place */ + i2 = gps->totpoints - 1; + for (int i = oldtotpoints - 1; i > 0; i--) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *pt_final = &gps->points[i2]; + MDeformVert *dvert = &gps->dvert[i]; + MDeformVert *dvert_final = &gps->dvert[i2]; + + copy_v3_v3(&pt_final->x, &pt->x); + pt_final->pressure = pt->pressure; + pt_final->strength = pt->strength; + pt_final->time = pt->time; + pt_final->flag = pt->flag; + pt_final->uv_fac = pt->uv_fac; + pt_final->uv_rot = pt->uv_rot; + + dvert_final->totweight = dvert->totweight; + dvert_final->dw = dvert->dw; + + i2 -= 2; + } + /* interpolate mid points */ + i2 = 1; + for (int i = 0; i < oldtotpoints - 1; i++) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *next = &temp_points[i + 1]; + bGPDspoint *pt_final = &gps->points[i2]; + MDeformVert *dvert_final = &gps->dvert[i2]; + + /* add a half way point */ + interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); + pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f); + pt_final->strength = interpf(pt->strength, next->strength, 0.5f); + CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); + pt_final->time = interpf(pt->time, next->time, 0.5f); + pt_final->uv_fac = interpf(pt->uv_fac, next->uv_fac, 0.5f); + pt_final->uv_rot = interpf(pt->uv_rot, next->uv_rot, 0.5f); + + dvert_final->totweight = 0; + dvert_final->dw = NULL; + + i2 += 2; + } - /* Create interpolated points */ - for (int i = 0; i < new_totpoints - 1; i += 2) { - bGPDspoint *prev = &gps->points[i]; - bGPDspoint *pt = &gps->points[i + 1]; - bGPDspoint *next = &gps->points[i + 2]; + MEM_SAFE_FREE(temp_points); - /* Interpolate all values */ - interp_v3_v3v3(&pt->x, &prev->x, &next->x, 0.5f); + /* move points to smooth stroke */ + /* duplicate points in a temp area with the new subdivide data */ + temp_points = MEM_dupallocN(gps->points); - pt->pressure = interpf(prev->pressure, next->pressure, 0.5f); - pt->strength = interpf(prev->strength, next->strength, 0.5f); - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); - pt->time = interpf(prev->time, next->time, 0.5f); - } + /* extreme points are not changed */ + for (int i = 0; i < gps->totpoints - 2; i++) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *next = &temp_points[i + 1]; + bGPDspoint *pt_final = &gps->points[i + 1]; - /* Update to new total number of points */ - gps->totpoints = new_totpoints; + /* move point */ + interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); + } + /* free temp memory */ + MEM_SAFE_FREE(temp_points); + } } /** @@ -965,7 +1018,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints) * \param gps Stroke data * \param brush Brush data */ -void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, RNG *rng) +void gp_randomize_stroke(bGPDstroke *gps, Brush *brush, RNG *rng) { bGPDspoint *pt1, *pt2, *pt3; float v1[3]; @@ -995,10 +1048,10 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, RNG *rng) normalize_v3(ortho); /* Read all points and apply shift vector (first and last point not modified) */ - for (int i = 1; i < gps->totpoints - 1; ++i) { + for (int i = 1; i < gps->totpoints - 1; i++) { bGPDspoint *pt = &gps->points[i]; /* get vector with shift (apply a division because random is too sensitive */ - const float fac = BLI_rng_get_float(rng) * (brush->draw_random_sub / 10.0f); + const float fac = BLI_rng_get_float(rng) * (brush->gpencil_settings->draw_random_sub / 10.0f); float svec[3]; copy_v3_v3(svec, ortho); if (BLI_rng_get_float(rng) > 0.5f) { @@ -1011,31 +1064,46 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush, RNG *rng) /* apply shift */ add_v3_v3(&pt->x, svec); } - } + +/* ******************************************************** */ +/* Layer Parenting - Compute Parent Transforms */ + /* calculate difference matrix */ -void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4]) +void ED_gpencil_parent_location( + const Depsgraph *depsgraph, Object *obact, bGPdata *UNUSED(gpd), + bGPDlayer *gpl, float diff_mat[4][4]) { - Object *ob = gpl->parent; - - if (ob == NULL) { + Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obact) : obact; + Object *obparent = gpl->parent; + Object *obparent_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, obparent) : obparent; + + /* if not layer parented, try with object parented */ + if (obparent_eval == NULL) { + if (ob_eval != NULL) { + if (ob_eval->type == OB_GPENCIL) { + copy_m4_m4(diff_mat, ob_eval->obmat); + return; + } + } + /* not gpencil object */ unit_m4(diff_mat); return; } else { if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { - mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse); + mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); return; } else if (gpl->partype == PARBONE) { - bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, gpl->parsubstr); + bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr); if (pchan) { float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, ob->obmat, pchan->pose_mat); + mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat); mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse); } else { - mul_m4_m4m4(diff_mat, ob->obmat, gpl->inverse); /* if bone not found use object (armature) */ + mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); /* if bone not found use object (armature) */ } return; } @@ -1046,7 +1114,7 @@ void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4]) } /* reset parent matrix for all layers */ -void ED_gpencil_reset_layers_parent(bGPdata *gpd) +void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd) { bGPDspoint *pt; int i; @@ -1071,7 +1139,7 @@ void ED_gpencil_reset_layers_parent(bGPdata *gpd) /* only redo if any change */ if (!equals_m4m4(gpl->inverse, cur_mat)) { /* first apply current transformation to all strokes */ - ED_gpencil_parent_location(gpl, diff_mat); + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { @@ -1086,90 +1154,580 @@ void ED_gpencil_reset_layers_parent(bGPdata *gpd) } } /* ******************************************************** */ -bool ED_gpencil_stroke_minmax( - const bGPDstroke *gps, const bool use_select, - float r_min[3], float r_max[3]) +/* GP Object Stuff */ + +/* Helper function to create new OB_GPENCIL Object */ +Object *ED_add_gpencil_object(bContext *C, Scene *scene, const float loc[3]) { - const bGPDspoint *pt; - int i; - bool changed = false; + float rot[3] = {0.0f}; + + Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, scene->lay); + + /* define size */ + BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE); + /* create default brushes and colors */ + ED_gpencil_add_defaults(C); - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {; - minmax_v3v3_v3(r_min, r_max, &pt->x); - changed = true; + return ob; +} + +/* Helper function to create default colors and drawing brushes */ +void ED_gpencil_add_defaults(bContext *C) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + /* first try to reuse default material */ + if (ob->actcol > 0) { + Material *ma = give_current_material(ob, ob->actcol); + if ((ma) && (ma->gp_style == NULL)) { + BKE_material_init_gpencil_settings(ma); } } - return changed; + + /* ensure color exist */ + BKE_gpencil_material_ensure(bmain, ob); + + Paint *paint = BKE_brush_get_gpencil_paint(ts); + /* if not exist, create a new one */ + if (paint->brush == NULL) { + /* create new brushes */ + BKE_brush_gpencil_presets(C); + } + } -/* Dynamic Enums of GP Brushes */ -const EnumPropertyItem *ED_gpencil_brushes_enum_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), - bool *r_free) +/* ******************************************************** */ +/* Vertex Groups */ + +/* assign points to vertex group */ +void ED_gpencil_vgroup_assign(bContext *C, Object *ob, float weight) { - ToolSettings *ts = CTX_data_tool_settings(C); - bGPDbrush *brush; - EnumPropertyItem *item = NULL, item_tmp = { 0 }; - int totitem = 0; - int i = 0; + const int def_nr = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, def_nr)) + return; - if (ELEM(NULL, C, ts)) { - return DummyRNA_DEFAULT_items; + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + if (gps->flag & GP_STROKE_SELECT) { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + if (pt->flag & GP_SPOINT_SELECT) { + BKE_gpencil_vgroup_add_point_weight(dvert, def_nr, weight); + } + } + } } + CTX_DATA_END; +} - /* Existing brushes */ - for (brush = ts->gp_brushes.first; brush; brush = brush->next, i++) { - item_tmp.identifier = brush->info; - item_tmp.name = brush->info; - item_tmp.value = i; +/* remove points from vertex group */ +void ED_gpencil_vgroup_remove(bContext *C, Object *ob) +{ + const int def_nr = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, def_nr)) + return; - if (brush->flag & GP_BRUSH_ACTIVE) - item_tmp.icon = ICON_BRUSH_DATA; - else - item_tmp.icon = ICON_NONE; + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; - RNA_enum_item_add(&item, &totitem, &item_tmp); + if ((pt->flag & GP_SPOINT_SELECT) && (dvert->totweight > 0)) { + BKE_gpencil_vgroup_remove_point_weight(dvert, def_nr); + } + } } + CTX_DATA_END; +} - RNA_enum_item_end(&item, &totitem); - *r_free = true; +/* select points of vertex group */ +void ED_gpencil_vgroup_select(bContext *C, Object *ob) +{ + const int def_nr = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, def_nr)) + return; - return item; + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + if (BKE_gpencil_vgroup_use_index(dvert, def_nr) > -1.0f) { + pt->flag |= GP_SPOINT_SELECT; + gps->flag |= GP_STROKE_SELECT; + } + } + } + CTX_DATA_END; } -/* Dynamic Enums of GP Palettes */ -const EnumPropertyItem *ED_gpencil_palettes_enum_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), - bool *r_free) +/* unselect points of vertex group */ +void ED_gpencil_vgroup_deselect(bContext *C, Object *ob) { - bGPdata *gpd = CTX_data_gpencil_data(C); - bGPDpalette *palette; - EnumPropertyItem *item = NULL, item_tmp = { 0 }; - int totitem = 0; - int i = 0; + const int def_nr = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, def_nr)) + return; - if (ELEM(NULL, C, gpd)) { - return DummyRNA_DEFAULT_items; + CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes) + { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + if (BKE_gpencil_vgroup_use_index(dvert, def_nr) > -1.0f) { + pt->flag &= ~GP_SPOINT_SELECT; + gps->flag |= GP_STROKE_SELECT; + } + } } + CTX_DATA_END; +} - /* Existing palettes */ - for (palette = gpd->palettes.first; palette; palette = palette->next, i++) { - item_tmp.identifier = palette->info; - item_tmp.name = palette->info; - item_tmp.value = i; +/* ******************************************************** */ +/* Cursor drawing */ - if (palette->flag & PL_PALETTE_ACTIVE) - item_tmp.icon = ICON_COLOR; - else - item_tmp.icon = ICON_NONE; +/* check if cursor is in drawing region */ +static bool gp_check_cursor_region(bContext *C, int mval[2]) +{ + ARegion *ar = CTX_wm_region(C); + ScrArea *sa = CTX_wm_area(C); + /* TODO: add more spacetypes */ + if (!ELEM(sa->spacetype, SPACE_VIEW3D)) { + return false; + } + if ((ar) && (ar->regiontype != RGN_TYPE_WINDOW)) { + return false; + } + else if (ar) { + rcti region_rect; - RNA_enum_item_add(&item, &totitem, &item_tmp); + /* Perform bounds check using */ + ED_region_visible_rect(ar, ®ion_rect); + return BLI_rcti_isect_pt_v(®ion_rect, mval); + } + else { + return false; } +} - RNA_enum_item_end(&item, &totitem); - *r_free = true; +/* draw eraser cursor */ +void ED_gpencil_brush_draw_eraser(Brush *brush, int x, int y) +{ + short radius = (short)brush->size; - return item; + GPUVertFormat *format = immVertexFormat(); + const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + immUniformColor4ub(255, 100, 100, 20); + imm_draw_circle_fill_2d(shdr_pos, x, y, radius, 40); + + immUnbindProgram(); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); + + float viewport_size[4]; + glGetFloatv(GL_VIEWPORT, viewport_size); + immUniform2f("viewport_size", viewport_size[2], viewport_size[3]); + + immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f); + immUniform1i("colors_len", 0); /* "simple" mode */ + immUniform1f("dash_width", 12.0f); + immUniform1f("dash_factor", 0.5f); + + imm_draw_circle_wire_2d(shdr_pos, x, y, radius, + /* XXX Dashed shader gives bad results with sets of small segments currently, + * temp hack around the issue. :( */ + max_ii(8, radius / 2)); /* was fixed 40 */ + + immUnbindProgram(); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); +} + +/* Helper callback for drawing the cursor itself */ +static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + ARegion *ar = CTX_wm_region(C); + + GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt; + bGPdata *gpd = ED_gpencil_data_get_active(C); + GP_EditBrush_Data *brush = NULL; + Brush *paintbrush = NULL; + Material *ma = NULL; + MaterialGPencilStyle *gp_style = NULL; + int *last_mouse_position = customdata; + + if ((gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE)) { + brush = &gset->brush[gset->weighttype]; + } + else { + brush = &gset->brush[gset->brushtype]; + } + + /* default radius and color */ + float color[3] = {1.0f, 1.0f, 1.0f}; + float darkcolor[3]; + float radius = 3.0f; + + int mval[2] = {x, y}; + /* check if cursor is in drawing region and has valid datablock */ + if ((!gp_check_cursor_region(C, mval)) || (gpd == NULL)) { + return; + } + + /* for paint use paint brush size and color */ + if (gpd->flag & GP_DATA_STROKE_PAINTMODE) { + paintbrush = BKE_brush_getactive_gpencil(scene->toolsettings); + /* while drawing hide */ + if ((gpd->runtime.sbuffer_size > 0) && + (paintbrush) && ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && + ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0)) + { + return; + } + + if (paintbrush) { + if ((paintbrush->gpencil_settings->flag & GP_BRUSH_ENABLE_CURSOR) == 0) { + return; + } + + /* eraser has special shape and use a different shader program */ + if (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE) { + ED_gpencil_brush_draw_eraser(paintbrush, x, y); + return; + } + + /* get current drawing color */ + ma = BKE_gpencil_get_material_from_brush(paintbrush); + if (ma == NULL) { + BKE_gpencil_material_ensure(bmain, ob); + /* assign the first material to the brush */ + ma = give_current_material(ob, 1); + paintbrush->gpencil_settings->material = ma; + } + gp_style = ma->gp_style; + + /* after some testing, display the size of the brush is not practical because + * is too disruptive and the size of cursor does not change with zoom factor. + * The decision was to use a fix size, instead of paintbrush->thickness value. + */ + if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) && + ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && + ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) && + (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW)) + { + radius = 2.0f; + copy_v3_v3(color, gp_style->stroke_rgba); + } + else { + radius = 5.0f; + copy_v3_v3(color, paintbrush->add_col); + } + } + else { + return; + } + } + + /* for sculpt use sculpt brush size */ + if (GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd)) { + if (brush) { + if ((brush->flag & GP_EDITBRUSH_FLAG_ENABLE_CURSOR) == 0) { + return; + } + + radius = brush->size; + if (brush->flag & (GP_EDITBRUSH_FLAG_INVERT | GP_EDITBRUSH_FLAG_TMP_INVERT)) { + copy_v3_v3(color, brush->curcolor_sub); + } + else { + copy_v3_v3(color, brush->curcolor_add); + } + } + } + + /* draw icon */ + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + /* Inner Ring: Color from UI panel */ + immUniformColor4f(color[0], color[1], color[2], 0.8f); + if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) && + ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && + ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) && + (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW)) + { + imm_draw_circle_fill_2d(pos, x, y, radius, 40); + } + else { + imm_draw_circle_wire_2d(pos, x, y, radius, 40); + } + + /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ + mul_v3_v3fl(darkcolor, color, 0.40f); + immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f); + imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + + /* Draw line for lazy mouse */ + if ((last_mouse_position) && + (paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP)) + { + glEnable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + + copy_v3_v3(color, paintbrush->add_col); + immUniformColor4f(color[0], color[1], color[2], 0.8f); + + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, x, y); + immVertex2f(pos, last_mouse_position[0] + ar->winrct.xmin, + last_mouse_position[1] + ar->winrct.ymin); + immEnd(); + + glDisable(GL_BLEND); + glDisable(GL_LINE_SMOOTH); + } + + immUnbindProgram(); +} + +/* Turn brush cursor in on/off */ +void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata) +{ + Scene *scene = CTX_data_scene(C); + GP_BrushEdit_Settings *gset = &scene->toolsettings->gp_sculpt; + int *lastpost = customdata; + + if (gset->paintcursor && !enable) { + /* clear cursor */ + WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor); + gset->paintcursor = NULL; + } + else if (enable) { + /* in some situations cursor could be duplicated, so it is better disable first if exist */ + if (gset->paintcursor) { + /* clear cursor */ + WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor); + gset->paintcursor = NULL; + } + /* enable cursor */ + gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C), + NULL, + gp_brush_drawcursor, + (lastpost) ? customdata : NULL); + } +} + +/* verify if is using the right brush */ +static void gpencil_verify_brush_type(bContext *C, int newmode) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + GP_BrushEdit_Settings *gset = &ts->gp_sculpt; + + switch (newmode) { + case OB_MODE_GPENCIL_SCULPT: + gset->flag &= ~GP_BRUSHEDIT_FLAG_WEIGHT_MODE; + if ((gset->brushtype < 0) || (gset->brushtype >= GP_EDITBRUSH_TYPE_WEIGHT)) { + gset->brushtype = GP_EDITBRUSH_TYPE_PUSH; + } + break; + case OB_MODE_GPENCIL_WEIGHT: + gset->flag |= GP_BRUSHEDIT_FLAG_WEIGHT_MODE; + if ((gset->weighttype < GP_EDITBRUSH_TYPE_WEIGHT) || (gset->weighttype >= TOT_GP_EDITBRUSH_TYPES)) { + gset->weighttype = GP_EDITBRUSH_TYPE_WEIGHT; + } + break; + default: + break; + } +} + +/* set object modes */ +void ED_gpencil_setup_modes(bContext *C, bGPdata *gpd, int newmode) +{ + if (!gpd) { + return; + } + + switch (newmode) { + case OB_MODE_GPENCIL_EDIT: + gpd->flag |= GP_DATA_STROKE_EDITMODE; + gpd->flag &= ~GP_DATA_STROKE_PAINTMODE; + gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE; + gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE; + ED_gpencil_toggle_brush_cursor(C, false, NULL); + break; + case OB_MODE_GPENCIL_PAINT: + gpd->flag &= ~GP_DATA_STROKE_EDITMODE; + gpd->flag |= GP_DATA_STROKE_PAINTMODE; + gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE; + gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE; + ED_gpencil_toggle_brush_cursor(C, true, NULL); + break; + case OB_MODE_GPENCIL_SCULPT: + gpd->flag &= ~GP_DATA_STROKE_EDITMODE; + gpd->flag &= ~GP_DATA_STROKE_PAINTMODE; + gpd->flag |= GP_DATA_STROKE_SCULPTMODE; + gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE; + gpencil_verify_brush_type(C, OB_MODE_GPENCIL_SCULPT); + ED_gpencil_toggle_brush_cursor(C, true, NULL); + break; + case OB_MODE_GPENCIL_WEIGHT: + gpd->flag &= ~GP_DATA_STROKE_EDITMODE; + gpd->flag &= ~GP_DATA_STROKE_PAINTMODE; + gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE; + gpd->flag |= GP_DATA_STROKE_WEIGHTMODE; + gpencil_verify_brush_type(C, OB_MODE_GPENCIL_WEIGHT); + ED_gpencil_toggle_brush_cursor(C, true, NULL); + break; + default: + gpd->flag &= ~GP_DATA_STROKE_EDITMODE; + gpd->flag &= ~GP_DATA_STROKE_PAINTMODE; + gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE; + gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE; + ED_gpencil_toggle_brush_cursor(C, false, NULL); + break; + } +} + +/* helper to convert 2d to 3d for simple drawing buffer */ +static void gpencil_stroke_convertcoords(ARegion *ar, const tGPspoint *point2D, float origin[3], float out[3]) +{ + float mval_f[2] = { (float)point2D->x, (float)point2D->y }; + float mval_prj[2]; + float rvec[3], dvec[3]; + float zfac; + + copy_v3_v3(rvec, origin); + + zfac = ED_view3d_calc_zfac(ar->regiondata, rvec, NULL); + + if (ED_view3d_project_float_global(ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { + sub_v2_v2v2(mval_f, mval_prj, mval_f); + ED_view3d_win_to_delta(ar, mval_f, dvec, zfac); + sub_v3_v3v3(out, rvec, dvec); + } + else { + zero_v3(out); + } +} + +/* convert 2d tGPspoint to 3d bGPDspoint */ +void ED_gpencil_tpoint_to_point(ARegion *ar, float origin[3], const tGPspoint *tpt, bGPDspoint *pt) +{ + float p3d[3]; + /* conversion to 3d format */ + gpencil_stroke_convertcoords(ar, tpt, origin, p3d); + copy_v3_v3(&pt->x, p3d); + + pt->pressure = tpt->pressure; + pt->strength = tpt->strength; + pt->uv_fac = tpt->uv_fac; + pt->uv_rot = tpt->uv_rot; +} + +/* texture coordinate utilities */ +void ED_gpencil_calc_stroke_uv(Object *ob, bGPDstroke *gps) +{ + if (gps == NULL) { + return; + } + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + float pixsize; + if (gp_style) { + pixsize = gp_style->texture_pixsize / 1000000.0f; + } + else { + /* use this value by default */ + pixsize = 0.000100f; + } + pixsize = MAX2(pixsize, 0.0000001f); + + bGPDspoint *pt = NULL; + bGPDspoint *ptb = NULL; + int i; + float totlen = 0; + + /* first read all points and calc distance */ + for (i = 0; i < gps->totpoints; i++) { + pt = &gps->points[i]; + /* first point */ + if (i == 0) { + pt->uv_fac = 0.0f; + continue; + } + + ptb = &gps->points[i - 1]; + totlen += len_v3v3(&pt->x, &ptb->x) / pixsize; + pt->uv_fac = totlen; + } + /* normalize the distance using a factor */ + float factor; + /* if image, use texture width */ + if ((gp_style) && (gp_style->sima)) { + factor = gp_style->sima->gen_x; + } + else { + factor = totlen; + } + for (i = 0; i < gps->totpoints; i++) { + pt = &gps->points[i]; + pt->uv_fac /= factor; + } +} + +/* recalc uv for any stroke using the material */ +void ED_gpencil_update_color_uv(Main *bmain, Material *mat) +{ + Material *gps_ma = NULL; + /* read all strokes */ + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + if (gpd == NULL) { + continue; + } + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* only editable and visible layers are considered */ + if (gpencil_layer_is_editable(gpl)) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* check if it is editable */ + if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { + continue; + } + gps_ma = give_current_material(ob, gps->mat_nr + 1); + /* update */ + if ((gps_ma) && (gps_ma == mat)) { + ED_gpencil_calc_stroke_uv(ob, gps); + } + } + } + } + } + } + } } /* ******************************************************** */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 59a54f03e56..ae86e4a5fbf 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -197,6 +197,8 @@ typedef enum eAnim_ChannelType { ANIMTYPE_NLATRACK, ANIMTYPE_NLAACTION, + ANIMTYPE_PALETTE, + /* always as last item, the total number of channel types... */ ANIMTYPE_NUM_TYPES } eAnim_ChannelType; @@ -347,6 +349,9 @@ typedef enum eAnimFilter_Flags { /* Movie clip only */ #define EXPANDED_MCLIP(clip) (clip->flag & MCLIP_DATA_EXPAND) +/* Palette only */ +#define EXPANDED_PALETTE(palette) (palette->flag & PALETTE_DATA_EXPAND) + /* AnimData - NLA mostly... */ #define SEL_ANIMDATA(adt) (adt->flag & ADT_UI_SELECTED) diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h index 7d509d1243a..333e3d72615 100644 --- a/source/blender/editors/include/ED_datafiles.h +++ b/source/blender/editors/include/ED_datafiles.h @@ -42,6 +42,9 @@ extern char datatoc_preview_blend[]; extern int datatoc_preview_cycles_blend_size; extern char datatoc_preview_cycles_blend[]; +extern int datatoc_preview_grease_pencil_blend_size; +extern char datatoc_preview_grease_pencil_blend[]; + extern int datatoc_blender_icons16_png_size; extern char datatoc_blender_icons16_png[]; @@ -239,6 +242,66 @@ extern char datatoc_mc23_jpg[]; extern int datatoc_mc24_jpg_size; extern char datatoc_mc24_jpg[]; +/* grease pencil sculpt brushes files */ + +extern int datatoc_gp_brush_smooth_png_size; +extern char datatoc_gp_brush_smooth_png[]; + +extern int datatoc_gp_brush_thickness_png_size; +extern char datatoc_gp_brush_thickness_png[]; + +extern int datatoc_gp_brush_strength_png_size; +extern char datatoc_gp_brush_strength_png[]; + +extern int datatoc_gp_brush_grab_png_size; +extern char datatoc_gp_brush_grab_png[]; + +extern int datatoc_gp_brush_push_png_size; +extern char datatoc_gp_brush_push_png[]; + +extern int datatoc_gp_brush_twist_png_size; +extern char datatoc_gp_brush_twist_png[]; + +extern int datatoc_gp_brush_pinch_png_size; +extern char datatoc_gp_brush_pinch_png[]; + +extern int datatoc_gp_brush_randomize_png_size; +extern char datatoc_gp_brush_randomize_png[]; + +extern int datatoc_gp_brush_clone_png_size; +extern char datatoc_gp_brush_clone_png[]; + +extern int datatoc_gp_brush_weight_png_size; +extern char datatoc_gp_brush_weight_png[]; + +extern int datatoc_gp_brush_pencil_png_size; +extern char datatoc_gp_brush_pencil_png[]; + +extern int datatoc_gp_brush_pen_png_size; +extern char datatoc_gp_brush_pen_png[]; + +extern int datatoc_gp_brush_ink_png_size; +extern char datatoc_gp_brush_ink_png[]; + +extern int datatoc_gp_brush_inknoise_png_size; +extern char datatoc_gp_brush_inknoise_png[]; + +extern int datatoc_gp_brush_block_png_size; +extern char datatoc_gp_brush_block_png[]; + +extern int datatoc_gp_brush_marker_png_size; +extern char datatoc_gp_brush_marker_png[]; + +extern int datatoc_gp_brush_fill_png_size; +extern char datatoc_gp_brush_fill_png[]; + +extern int datatoc_gp_brush_erase_soft_png_size; +extern char datatoc_gp_brush_erase_soft_png[]; + +extern int datatoc_gp_brush_erase_hard_png_size; +extern char datatoc_gp_brush_erase_hard_png[]; +extern int datatoc_gp_brush_erase_stroke_png_size; +extern char datatoc_gp_brush_erase_stroke_png[]; #endif /* __ED_DATAFILES_H__ */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index f1f2ce29e7f..3013b455de4 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -30,64 +30,44 @@ #ifndef __ED_GPENCIL_H__ #define __ED_GPENCIL_H__ -#include "ED_numinput.h" - struct ID; struct ListBase; -struct bContext; -struct Depsgraph; -struct ScrArea; -struct ARegion; -struct View3D; -struct Object; +struct PointerRNA; +struct rcti; + struct bGPdata; struct bGPDlayer; struct bGPDframe; struct bGPDstroke; -struct bGPDpalette; -struct bGPDpalettecolor; -struct bAnimContext; -struct KeyframeEditData; -struct PointerRNA; +struct bGPDspoint; +struct Brush; + +struct Main; +struct bContext; +struct EvaluationContext; +struct Depsgraph; +struct ScrArea; +struct ARegion; +struct RegionView3D; struct Scene; +struct ToolSettings; struct ViewLayer; -struct wmWindowManager; -struct wmKeyConfig; - - -/* ------------- Grease-Pencil Helpers ---------------- */ -typedef struct tGPDinterpolate_layer { - struct tGPDinterpolate_layer *next, *prev; - - struct bGPDlayer *gpl; /* layer */ - struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */ - struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */ - struct bGPDframe *interFrame; /* interpolated frame */ - float factor; /* interpolate factor */ +struct View3D; -} tGPDinterpolate_layer; +struct Object; +struct Material; -/* Temporary interpolate operation data */ -typedef struct tGPDinterpolate { - struct Scene *scene; /* current scene from context */ - struct ScrArea *sa; /* area where painting originated */ - struct ARegion *ar; /* region where painting originated */ - struct bGPdata *gpd; /* current GP datablock */ +struct bAnimContext; +struct KeyframeEditData; - int cframe; /* current frame number */ - ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */ - float shift; /* value for determining the displacement influence */ - float init_factor; /* initial interpolation factor for active layer */ - float low_limit; /* shift low limit (-100%) */ - float high_limit; /* shift upper limit (200%) */ - int flag; /* flag from toolsettings */ +struct wmKeyConfig; +struct wmOperator; +struct wmWindow; +struct wmWindowManager; - NumInput num; /* numeric input */ - void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */ - void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */ -} tGPDinterpolate; +/* ------------- Grease-Pencil Runtime Data ---------------- */ -/* Temporary 'Stroke Point' data +/* Temporary 'Stroke Point' data (2D / screen-space) * * Used as part of the 'stroke cache' used during drawing of new strokes */ @@ -96,27 +76,43 @@ typedef struct tGPspoint { float pressure; /* pressure of tablet at this point */ float strength; /* pressure of tablet at this point for alpha factor */ float time; /* Time relative to stroke start (used when converting to path) */ + float uv_fac; /* factor of uv along the stroke */ + float uv_rot; /* uv rotation for dor mode */ } tGPspoint; - -/* Check if 'sketching sessions' are enabled */ -#define GPENCIL_SKETCH_SESSIONS_ON(scene) ((scene)->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINTSESSIONS_ON) +/* used to sort by zdepth gpencil objects in viewport */ +/* TODO: this could be a system parameter in userprefs screen */ +#define GP_CACHE_BLOCK_SIZE 16 +typedef struct tGPencilSort { + struct Base *base; + float zdepth; +} tGPencilSort; /* ----------- Grease Pencil Tools/Context ------------- */ /* Context-dependent */ -struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr); +struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *r_ptr); + struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C); +struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C); /* Context independent (i.e. each required part is passed in instead) */ -struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ID *screen_id, struct Scene *scene, - struct ScrArea *sa, struct Object *ob, - struct PointerRNA *ptr); -struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct Scene *scene, - struct ScrArea *sa, struct Object *ob); +struct bGPdata **ED_gpencil_data_get_pointers_direct( + struct ID *screen_id, + struct ScrArea *sa, + struct Scene *scene, + struct Object *ob, + struct PointerRNA *r_ptr); +struct bGPdata *ED_gpencil_data_get_active_direct( + struct ID *screen_id, + struct ScrArea *sa, + struct Scene *scene, + struct Object *ob); + +bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr); /* 3D View */ -struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct ViewLayer *view_layer); +struct bGPdata *ED_gpencil_data_get_active_v3d(struct ViewLayer *view_layer); bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfra); @@ -124,13 +120,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps); bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps); -bool ED_gpencil_stroke_color_use(const struct bGPDlayer *gpl, const struct bGPDstroke *gps); - -struct bGPDpalettecolor *ED_gpencil_stroke_getcolor(struct bGPdata *gpd, struct bGPDstroke *gps); - -bool ED_gpencil_stroke_minmax( - const struct bGPDstroke *gps, const bool use_select, - float r_min[3], float r_max[3]); +bool ED_gpencil_stroke_color_use(struct Object *ob, const struct bGPDlayer *gpl, const struct bGPDstroke *gps); /* ----------- Grease Pencil Operators ----------------- */ @@ -150,16 +140,29 @@ void ED_gpencil_strokes_copybuf_free(void); void ED_gpencil_draw_2dimage(const struct bContext *C); void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d); -void ED_gpencil_draw_view3d(struct wmWindowManager *wm, - struct Scene *scene, - struct ViewLayer *view_layer, - struct Depsgraph *depsgraph, - struct View3D *v3d, - struct ARegion *ar, - bool only3d); -void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy, - const int cfra, const char spacetype); -void ED_gp_draw_interpolation(struct tGPDinterpolate *tgpi, const int type); +void ED_gpencil_draw_view3d( + struct wmWindowManager *wm, + struct Scene *scene, + struct ViewLayer *view_layer, + struct Depsgraph *depsgraph, + struct View3D *v3d, + struct ARegion *ar, + bool only3d); +void ED_gpencil_draw_view3d_annotations( + struct Scene *scene, struct Depsgraph *depsgraph, + struct View3D *v3d, struct ARegion *ar, + bool only3d); +void ED_gpencil_draw_view3d_object( + struct wmWindowManager *wm, + struct Scene *scene, + struct Depsgraph *depsgraph, + struct Object *ob, + struct View3D *v3d, + struct ARegion *ar, + bool only3d); +void ED_gpencil_draw_ex( + struct RegionView3D *rv3d, struct Scene *scene, struct bGPdata *gpd, int winx, int winy, + const int cfra, const char spacetype); /* ----------- Grease-Pencil AnimEdit API ------------------ */ bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene, @@ -192,10 +195,45 @@ int ED_undo_gpencil_step(struct bContext *C, int step, const char *name); /* ------------ Transformation Utilities ------------ */ -/* get difference matrix using parent */ -void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]); +/* get difference matrix */ +void ED_gpencil_parent_location( + const struct Depsgraph *depsgraph, struct Object *obact, struct bGPdata *gpd, + struct bGPDlayer *gpl, float diff_mat[4][4]); /* reset parent matrix for all layers */ -void ED_gpencil_reset_layers_parent(struct bGPdata *gpd); +void ED_gpencil_reset_layers_parent(struct Depsgraph *depsgraph, struct Object *obact, struct bGPdata *gpd); + +/* cursor utilities */ +void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y); + +/* ----------- Add Primitive Utilities -------------- */ + +void ED_gpencil_create_monkey(struct bContext *C, float mat[4][4]); + +/* ------------ Object Utilities ------------ */ +struct Object *ED_add_gpencil_object(struct bContext *C, struct Scene *scene, const float loc[3]); +void ED_gpencil_add_defaults(struct bContext *C); +/* set object modes */ +void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode); + +void ED_gp_project_stroke_to_plane(struct Object *ob, struct RegionView3D *rv3d, struct bGPDstroke *gps, const float origin[3], const int axis); +void ED_gp_project_point_to_plane(struct Object *ob, struct RegionView3D *rv3d, const float origin[3], const int axis, struct bGPDspoint *pt); +void ED_gp_get_drawing_reference(struct View3D *v3d, struct Scene *scene, struct Object *ob, struct bGPDlayer *gpl, char align_flag, float vec[3]); + +/* set sculpt cursor */ +void ED_gpencil_toggle_brush_cursor(struct bContext *C, bool enable, void *customdata); + +/* vertex groups */ +void ED_gpencil_vgroup_assign(struct bContext *C, struct Object *ob, float weight); +void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob); +void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob); +void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob); + +/* join objects */ +int ED_gpencil_join_objects_exec(struct bContext *C, struct wmOperator *op); +/* texture coordinate utilities */ +void ED_gpencil_tpoint_to_point(struct ARegion *ar, float origin[3], const struct tGPspoint *tpt, struct bGPDspoint *pt); +void ED_gpencil_calc_stroke_uv(struct Object *ob, struct bGPDstroke *gps); +void ED_gpencil_update_color_uv(struct Main *bmain, struct Material *mat); #endif /* __ED_GPENCIL_H__ */ diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index 64dee410526..45a0680e0c1 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -42,6 +42,7 @@ struct bActionGroup; struct Object; struct ListBase; struct bGPDlayer; +struct Palette; struct MaskLayer; struct Scene; struct View2D; @@ -151,9 +152,11 @@ void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tr /* DopeSheet Summary */ void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); /* Grease Pencil datablock summary */ -void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys); +void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys, const bool active); /* Grease Pencil Layer */ void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys); +/* Palette */ +void palette_to_keylist(struct bDopeSheet *ads, struct Palette *palette, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks); /* Mask */ void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay, struct DLRBT_Tree *keys); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 9fd5cc99073..a39523983ba 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -42,6 +42,7 @@ struct ID; struct Main; struct Menu; struct ModifierData; +struct ShaderFxData; struct Object; struct ReportList; struct Scene; @@ -261,6 +262,40 @@ bool ED_object_iter_other( bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v); + +/* object_greasepencil_modifier.c */ +struct GpencilModifierData *ED_object_gpencil_modifier_add( + struct ReportList *reports, struct Main *bmain, struct Scene *scene, + struct Object *ob, const char *name, int type); +bool ED_object_gpencil_modifier_remove( + struct ReportList *reports, struct Main *bmain, + struct Object *ob, struct GpencilModifierData *md); +void ED_object_gpencil_modifier_clear( + struct Main *bmain, struct Object *ob); +int ED_object_gpencil_modifier_move_down( + struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md); +int ED_object_gpencil_modifier_move_up( + struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md); +int ED_object_gpencil_modifier_apply( + struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph, + struct Object *ob, struct GpencilModifierData *md, int mode); +int ED_object_gpencil_modifier_copy( + struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md); + +/* object_shader_fx.c */ +struct ShaderFxData *ED_object_shaderfx_add( + struct ReportList *reports, struct Main *bmain, struct Scene *scene, + struct Object *ob, const char *name, int type); +bool ED_object_shaderfx_remove( + struct ReportList *reports, struct Main *bmain, + struct Object *ob, struct ShaderFxData *fx); +void ED_object_shaderfx_clear( + struct Main *bmain, struct Object *ob); +int ED_object_shaderfx_move_down( + struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx); +int ED_object_shaderfx_move_up( + struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx); + /* object_select.c */ void ED_object_select_linked_by_id(struct bContext *C, struct ID *id); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index ec4c7dddd4c..dec02faf85c 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -1001,6 +1001,30 @@ DEF_ICON(MATCAP_22) DEF_ICON(MATCAP_23) DEF_ICON(MATCAP_24) +/* grease pencil sculpt */ +DEF_ICON(GPBRUSH_SMOOTH) +DEF_ICON(GPBRUSH_THICKNESS) +DEF_ICON(GPBRUSH_STRENGTH) +DEF_ICON(GPBRUSH_GRAB) +DEF_ICON(GPBRUSH_PUSH) +DEF_ICON(GPBRUSH_TWIST) +DEF_ICON(GPBRUSH_PINCH) +DEF_ICON(GPBRUSH_RANDOMIZE) +DEF_ICON(GPBRUSH_CLONE) +DEF_ICON(GPBRUSH_WEIGHT) + +DEF_ICON(GPBRUSH_PENCIL) +DEF_ICON(GPBRUSH_PEN) +DEF_ICON(GPBRUSH_INK) +DEF_ICON(GPBRUSH_INKNOISE) +DEF_ICON(GPBRUSH_BLOCK) +DEF_ICON(GPBRUSH_MARKER) +DEF_ICON(GPBRUSH_CUSTOM) +DEF_ICON(GPBRUSH_FILL) +DEF_ICON(GPBRUSH_ERASE_SOFT) +DEF_ICON(GPBRUSH_ERASE_HARD) +DEF_ICON(GPBRUSH_ERASE_STROKE) + /* vector icons, VICO_ prefix added */ DEF_VICO(SMALL_TRI_RIGHT_VEC) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index b4756eaed0f..fc3dd3f9968 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1022,7 +1022,8 @@ uiLayout *uiLayoutRadial(uiLayout *layout); void uiTemplateHeader(uiLayout *layout, struct bContext *C); void uiTemplateID( uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, - const char *newop, const char *openop, const char *unlinkop, int filter); + const char *newop, const char *openop, const char *unlinkop, + int filter, const bool live_icon); void uiTemplateIDBrowse( uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter); @@ -1052,6 +1053,12 @@ void uiTemplatePathBuilder( uiLayout *layout, struct PointerRNA *ptr, const char *propname, struct PointerRNA *root_ptr, const char *text); uiLayout *uiTemplateModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); +uiLayout *uiTemplateGpencilModifier(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); +void uiTemplateGpencilColorPreview( + uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, + int rows, int cols, float scale, int filter); + +uiLayout *uiTemplateShaderFx(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr); void uiTemplateOperatorRedoProperties(uiLayout *layout, const struct bContext *C); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 7255640bedc..4f77b797ec0 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -47,6 +47,7 @@ #include "DNA_brush_types.h" #include "DNA_curve_types.h" #include "DNA_dynamicpaint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -109,6 +110,7 @@ typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha); #define ICON_TYPE_VECTOR 4 #define ICON_TYPE_GEOM 5 #define ICON_TYPE_EVENT 6 /* draw keymap entries using custom renderer. */ +#define ICON_TYPE_GPLAYER 7 typedef struct DrawInfo { int type; @@ -391,6 +393,28 @@ DEF_VICON_COLORSET_DRAW_NTH(20, 19) #undef DEF_VICON_COLORSET_DRAW_NTH +/* Dynamically render icon instead of rendering a plain color to a texture/buffer + * This is mot strictly a "vicon", as it needs access to icon->obj to get the color info, + * but it works in a very similar way. + */ +static void vicon_gplayer_color_draw(Icon *icon, int x, int y, int w, int h) +{ + bGPDlayer *gpl = (bGPDlayer *)icon->obj; + + /* Just draw a colored rect - Like for vicon_colorset_draw() */ + /* TODO: Make this have rounded corners, and maybe be a bit smaller. + * However, UI_draw_roundbox_aa() draws the colors too dark, so can't be used. + */ + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor3fv(gpl->color); + immRecti(pos, x, y, x + w - 1, y + h - 1); + + immUnbindProgram(); +} + + #ifndef WITH_HEADLESS static void init_brush_icons(void) @@ -443,6 +467,30 @@ static void init_brush_icons(void) INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist); INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw); + /* grease pencil sculpt */ + INIT_BRUSH_ICON(ICON_GPBRUSH_SMOOTH, gp_brush_smooth); + INIT_BRUSH_ICON(ICON_GPBRUSH_THICKNESS, gp_brush_thickness); + INIT_BRUSH_ICON(ICON_GPBRUSH_STRENGTH, gp_brush_strength); + INIT_BRUSH_ICON(ICON_GPBRUSH_GRAB, gp_brush_grab); + INIT_BRUSH_ICON(ICON_GPBRUSH_PUSH, gp_brush_push); + INIT_BRUSH_ICON(ICON_GPBRUSH_TWIST, gp_brush_twist); + INIT_BRUSH_ICON(ICON_GPBRUSH_PINCH, gp_brush_pinch); + INIT_BRUSH_ICON(ICON_GPBRUSH_RANDOMIZE, gp_brush_randomize); + INIT_BRUSH_ICON(ICON_GPBRUSH_CLONE, gp_brush_clone); + INIT_BRUSH_ICON(ICON_GPBRUSH_WEIGHT, gp_brush_weight); + + /* grease pencil drawing brushes */ + INIT_BRUSH_ICON(ICON_GPBRUSH_PENCIL, gp_brush_pencil); + INIT_BRUSH_ICON(ICON_GPBRUSH_PEN, gp_brush_pen); + INIT_BRUSH_ICON(ICON_GPBRUSH_INK, gp_brush_ink); + INIT_BRUSH_ICON(ICON_GPBRUSH_INKNOISE, gp_brush_inknoise); + INIT_BRUSH_ICON(ICON_GPBRUSH_BLOCK, gp_brush_block); + INIT_BRUSH_ICON(ICON_GPBRUSH_MARKER, gp_brush_marker); + INIT_BRUSH_ICON(ICON_GPBRUSH_FILL, gp_brush_fill); + INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_SOFT, gp_brush_erase_soft); + INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard); + INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke); + #undef INIT_BRUSH_ICON } @@ -877,6 +925,9 @@ static DrawInfo *icon_create_drawinfo(Icon *icon) else if (icon_data_type == ICON_DATA_STUDIOLIGHT) { di->type = ICON_TYPE_BUFFER; } + else if (icon_data_type == ICON_DATA_GPLAYER) { + di->type = ICON_TYPE_GPLAYER; + } else { BLI_assert(0); } @@ -1484,6 +1535,15 @@ static void icon_draw_size( GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); } } + else if (di->type == ICON_TYPE_GPLAYER) { + BLI_assert(icon->obj != NULL); + + /* We need to flush widget base first to ensure correct ordering. */ + UI_widgetbase_draw_cache_flush(); + + /* Just draw a colored rect - Like for vicon_colorset_draw() */ + vicon_gplayer_color_draw(icon, (int)x, (int)y, w, h); + } } static void ui_id_preview_image_render_size( @@ -1576,7 +1636,45 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id) } /* reset the icon */ - if (mode == OB_MODE_SCULPT) { + if (ob->mode & OB_MODE_GPENCIL_PAINT) { + switch (br->gpencil_settings->icon_id) { + case GP_BRUSH_ICON_PENCIL: + br->id.icon_id = ICON_GPBRUSH_PENCIL; + break; + case GP_BRUSH_ICON_PEN: + br->id.icon_id = ICON_GPBRUSH_PEN; + break; + case GP_BRUSH_ICON_INK: + br->id.icon_id = ICON_GPBRUSH_INK; + break; + case GP_BRUSH_ICON_INKNOISE: + br->id.icon_id = ICON_GPBRUSH_INKNOISE; + break; + case GP_BRUSH_ICON_BLOCK: + br->id.icon_id = ICON_GPBRUSH_BLOCK; + break; + case GP_BRUSH_ICON_MARKER: + br->id.icon_id = ICON_GPBRUSH_MARKER; + break; + case GP_BRUSH_ICON_FILL: + br->id.icon_id = ICON_GPBRUSH_FILL; + break; + case GP_BRUSH_ICON_ERASE_SOFT: + br->id.icon_id = ICON_GPBRUSH_ERASE_SOFT; + break; + case GP_BRUSH_ICON_ERASE_HARD: + br->id.icon_id = ICON_GPBRUSH_ERASE_HARD; + break; + case GP_BRUSH_ICON_ERASE_STROKE: + br->id.icon_id = ICON_GPBRUSH_ERASE_STROKE; + break; + default: + br->id.icon_id = ICON_GPBRUSH_PEN; + break; + } + return id->icon_id; + } + else if (mode == OB_MODE_SCULPT) { items = rna_enum_brush_sculpt_tool_items; tool = br->sculpt_tool; } diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 82ed4c5acba..89e1a8caec8 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1244,7 +1244,15 @@ void uiItemsFullEnumO( bool free; if (ui_layout_is_radial(layout)) { + /* XXX: While "_all()" guarantees spatial stability, it's bad when an enum has > 8 items total, + * but only a small subset will ever be shown at once (e.g. Mode Switch menu, after the + * introduction of GP editing modes) + */ +#if 0 RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, &totitem, &free); +#else + RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free); +#endif } else { RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, &totitem, &free); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 131ffbca377..513bfd32191 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -39,6 +39,8 @@ #include "DNA_object_force_types.h" #include "DNA_brush_types.h" #include "DNA_texture_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_shader_fx_types.h" #include "BLI_utildefines.h" #include "BLI_alloca.h" @@ -57,6 +59,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_gpencil_modifier.h" #include "BKE_idcode.h" #include "BKE_idprop.h" #include "BKE_layer.h" @@ -71,6 +74,7 @@ #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_screen.h" +#include "BKE_shader_fx.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -110,7 +114,7 @@ static void template_add_button_search_menu( const bContext *C, uiLayout *layout, uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, uiBlockCreateFunc block_func, void *block_argN, const char * const tip, - const bool use_previews, const bool editable) + const bool use_previews, const bool editable, const bool live_icon) { PointerRNA active_ptr = RNA_property_pointer_get(ptr, prop); ID *id = (active_ptr.data && RNA_struct_is_ID(active_ptr.type)) ? active_ptr.data : NULL; @@ -146,7 +150,14 @@ static void template_add_button_search_menu( } else { but = uiDefBlockButN(block, block_func, block_argN, "", 0, 0, UI_UNIT_X * 1.6, UI_UNIT_Y, tip); - ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON); + + if (live_icon) { + int icon = id ? ui_id_icon_get(C, id, false) : RNA_struct_ui_icon(type); + ui_def_but_icon(but, icon, UI_HAS_ICON | UI_BUT_ICON_PREVIEW); + } + else { + ui_def_but_icon(but, RNA_struct_ui_icon(type), UI_HAS_ICON); + } if (id) { /* default dragging of icon for id browse buttons */ UI_but_drag_set_id(but, id); @@ -162,7 +173,8 @@ static uiBlock *template_common_search_menu( const bContext *C, ARegion *region, uiButSearchFunc search_func, void *search_arg, uiButHandleFunc handle_func, void *active_item, - const int preview_rows, const int preview_cols) + const int preview_rows, const int preview_cols, + float scale) { static char search[256]; wmWindow *win = CTX_wm_window(C); @@ -177,8 +189,8 @@ static uiBlock *template_common_search_menu( /* preview thumbnails */ if (preview_rows > 0 && preview_cols > 0) { - const int w = 4 * U.widget_unit * preview_cols; - const int h = 5 * U.widget_unit * preview_rows; + const int w = 4 * U.widget_unit * preview_cols * scale; + const int h = 5 * U.widget_unit * preview_rows * scale; /* fake button, it holds space for search items */ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 26, w, h, NULL, 0, 0, 0, 0, NULL); @@ -237,6 +249,7 @@ typedef struct TemplateID { short filter; int prv_rows, prv_cols; bool preview; + float scale; } TemplateID; /* Search browse menu, assign */ @@ -382,7 +395,7 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) return template_common_search_menu( C, ar, id_search_cb_p, &template_ui, template_ID_set_property_cb, active_item_ptr.data, - template_ui.prv_rows, template_ui.prv_cols); + template_ui.prv_rows, template_ui.prv_cols, template_ui.scale); } /************************ ID Template ***************************/ @@ -630,7 +643,8 @@ static uiBut *template_id_def_new_but( static void template_ID( bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag, - const char *newop, const char *openop, const char *unlinkop) + const char *newop, const char *openop, const char *unlinkop, + const bool live_icon) { uiBut *but; uiBlock *block; @@ -655,7 +669,7 @@ static void template_ID( template_add_button_search_menu( C, layout, block, &template_ui->ptr, template_ui->prop, id_search_menu, MEM_dupallocN(template_ui), TIP_(template_id_browse_tip(type)), - use_previews, editable); + use_previews, editable, live_icon); } /* text button with name */ @@ -860,7 +874,8 @@ static void ui_template_id( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, - int flag, int prv_rows, int prv_cols, int filter, bool use_tabs) + int flag, int prv_rows, int prv_cols, int filter, bool use_tabs, + float scale, bool live_icon) { TemplateID *template_ui; PropertyRNA *prop; @@ -879,6 +894,7 @@ static void ui_template_id( template_ui->prop = prop; template_ui->prv_rows = prv_rows; template_ui->prv_cols = prv_cols; + template_ui->scale = scale; if ((flag & UI_ID_PIN) == 0) { template_ui->filter = filter; @@ -907,7 +923,7 @@ static void ui_template_id( } else { uiLayoutRow(layout, true); - template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop); + template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop, live_icon); } } @@ -916,13 +932,14 @@ static void ui_template_id( void uiTemplateID( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, - const char *openop, const char *unlinkop, int filter) + const char *openop, const char *unlinkop, + int filter, const bool live_icon) { ui_template_id( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, - 0, 0, filter, false); + 0, 0, filter, false, 1.0f, live_icon); } void uiTemplateIDBrowse( @@ -933,7 +950,7 @@ void uiTemplateIDBrowse( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME, - 0, 0, filter, false); + 0, 0, filter, false, 1.0f, false); } void uiTemplateIDPreview( @@ -944,7 +961,18 @@ void uiTemplateIDPreview( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS, - rows, cols, filter, false); + rows, cols, filter, false, 1.0f, false); +} + +void uiTemplateGpencilColorPreview( + uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, + int rows, int cols, float scale, int filter) +{ + ui_template_id( + layout, C, ptr, propname, + NULL, NULL, NULL, + UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE, + rows, cols, filter, false, scale < 0.5f ? 0.5f : scale, false); } /** @@ -960,7 +988,7 @@ void uiTemplateIDTabs( layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE, - 0, 0, filter, true); + 0, 0, filter, true, 1.0f, false); } /************************ ID Chooser Template ***************************/ @@ -1057,12 +1085,12 @@ static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_tem return template_common_search_menu( C, region, ui_rna_collection_search_cb, &template_search, template_search_handle_cb, active_ptr.data, - template_search.preview_rows, template_search.preview_cols); + template_search.preview_rows, template_search.preview_cols, 1.0f); } static void template_search_add_button_searchmenu( const bContext *C, uiLayout *layout, uiBlock *block, - TemplateSearch *template_search, const bool editable) + TemplateSearch *template_search, const bool editable, const bool live_icon) { const char *ui_description = RNA_property_ui_description(template_search->search_data.target_prop); @@ -1070,7 +1098,7 @@ static void template_search_add_button_searchmenu( C, layout, block, &template_search->search_data.target_ptr, template_search->search_data.target_prop, template_search_menu, MEM_dupallocN(template_search), ui_description, - template_search->use_previews, editable); + template_search->use_previews, editable, live_icon); } static void template_search_add_button_name( @@ -1116,7 +1144,7 @@ static void template_search_buttons( uiLayoutRow(layout, true); UI_block_align_begin(block); - template_search_add_button_searchmenu(C, layout, block, template_search, editable); + template_search_add_button_searchmenu(C, layout, block, template_search, editable, false); template_search_add_button_name(block, &active_ptr, type); template_search_add_button_operator(block, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, editable); template_search_add_button_operator(block, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, editable); @@ -1539,6 +1567,246 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) return NULL; } +/************************ Grease Pencil Modifier Template *************************/ + +static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, + GpencilModifierData *md) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + PointerRNA ptr; + uiBlock *block; + uiLayout *box, *column, *row, *sub; + uiLayout *result = NULL; + + /* create RNA pointer */ + RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr); + + column = uiLayoutColumn(layout, true); + uiLayoutSetContextPointer(column, "modifier", &ptr); + + /* rounded header ------------------------------------------------------------------- */ + box = uiLayoutBox(column); + + row = uiLayoutRow(box, false); + block = uiLayoutGetBlock(row); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + /* Open/Close ................................. */ + uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE); + + /* modifier-type icon */ + uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); + UI_block_emboss_set(block, UI_EMBOSS); + + /* modifier name */ + if (mti->isDisabled && mti->isDisabled(md, 0)) { + uiLayoutSetRedAlert(row, true); + } + uiItemR(row, &ptr, "name", 0, "", ICON_NONE); + uiLayoutSetRedAlert(row, false); + + /* mode enabling buttons */ + UI_block_align_begin(block); + uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); + uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); + + if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) { + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, false); + uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); + } + + UI_block_align_end(block); + + /* Up/Down + Delete ........................... */ + UI_block_align_begin(block); + uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_gpencil_modifier_move_up"); + uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_gpencil_modifier_move_down"); + UI_block_align_end(block); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiItemO(row, "", ICON_X, "OBJECT_OT_gpencil_modifier_remove"); + UI_block_emboss_set(block, UI_EMBOSS); + + /* modifier settings (under the header) --------------------------------------------------- */ + if (md->mode & eGpencilModifierMode_Expanded) { + /* apply/convert/copy */ + box = uiLayoutBox(column); + row = uiLayoutRow(box, false); + + /* only here obdata, the rest of modifiers is ob level */ + UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE); + + uiLayoutSetOperatorContext(row, WM_OP_INVOKE_DEFAULT); + uiItemEnumO(row, "OBJECT_OT_gpencil_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply"), + 0, "apply_as", MODIFIER_APPLY_DATA); + + uiItemO(row, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE, + "OBJECT_OT_gpencil_modifier_copy"); + + /* result is the layout block inside the box, that we return so that modifier settings can be drawn */ + result = uiLayoutColumn(box, false); + block = uiLayoutAbsoluteBlock(box); + } + + /* error messages */ + if (md->error) { + box = uiLayoutBox(column); + row = uiLayoutRow(box, false); + uiItemL(row, md->error, ICON_ERROR); + } + + return result; +} + +uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + Object *ob; + GpencilModifierData *md, *vmd; + int i; + + /* verify we have valid data */ + if (!RNA_struct_is_a(ptr->type, &RNA_GpencilModifier)) { + RNA_warning("Expected modifier on object"); + return NULL; + } + + ob = ptr->id.data; + md = ptr->data; + + if (!ob || !(GS(ob->id.name) == ID_OB)) { + RNA_warning("Expected modifier on object"); + return NULL; + } + + UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE); + + /* find modifier and draw it */ + vmd = ob->greasepencil_modifiers.first; + for (i = 0; vmd; i++, vmd = vmd->next) { + if (md == vmd) + return gpencil_draw_modifier(layout, ob, md); + } + + return NULL; +} + +/************************ Shader FX Template *************************/ + +static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob, + ShaderFxData *md) +{ + const ShaderFxTypeInfo *mti = BKE_shaderfxType_getInfo(md->type); + PointerRNA ptr; + uiBlock *block; + uiLayout *box, *column, *row, *sub; + uiLayout *result = NULL; + + /* create RNA pointer */ + RNA_pointer_create(&ob->id, &RNA_ShaderFx, md, &ptr); + + column = uiLayoutColumn(layout, true); + uiLayoutSetContextPointer(column, "shaderfx", &ptr); + + /* rounded header ------------------------------------------------------------------- */ + box = uiLayoutBox(column); + + row = uiLayoutRow(box, false); + block = uiLayoutGetBlock(row); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + /* Open/Close ................................. */ + uiItemR(row, &ptr, "show_expanded", 0, "", ICON_NONE); + + /* shader-type icon */ + uiItemL(row, "", RNA_struct_ui_icon(ptr.type)); + UI_block_emboss_set(block, UI_EMBOSS); + + /* effect name */ + if (mti->isDisabled && mti->isDisabled(md, 0)) { + uiLayoutSetRedAlert(row, true); + } + uiItemR(row, &ptr, "name", 0, "", ICON_NONE); + uiLayoutSetRedAlert(row, false); + + /* mode enabling buttons */ + UI_block_align_begin(block); + uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE); + uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE); + + if (mti->flags & eShaderFxTypeFlag_SupportsEditmode) { + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, false); + uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE); + } + + UI_block_align_end(block); + + /* Up/Down + Delete ........................... */ + UI_block_align_begin(block); + uiItemO(row, "", ICON_TRIA_UP, "OBJECT_OT_shaderfx_move_up"); + uiItemO(row, "", ICON_TRIA_DOWN, "OBJECT_OT_shaderfx_move_down"); + UI_block_align_end(block); + + UI_block_emboss_set(block, UI_EMBOSS_NONE); + uiItemO(row, "", ICON_X, "OBJECT_OT_shaderfx_remove"); + UI_block_emboss_set(block, UI_EMBOSS); + + /* effect settings (under the header) --------------------------------------------------- */ + if (md->mode & eShaderFxMode_Expanded) { + /* apply/convert/copy */ + box = uiLayoutBox(column); + row = uiLayoutRow(box, false); + + /* only here obdata, the rest of effect is ob level */ + UI_block_lock_set(block, BKE_object_obdata_is_libdata(ob), ERROR_LIBDATA_MESSAGE); + + /* result is the layout block inside the box, that we return so that effect settings can be drawn */ + result = uiLayoutColumn(box, false); + block = uiLayoutAbsoluteBlock(box); + } + + /* error messages */ + if (md->error) { + box = uiLayoutBox(column); + row = uiLayoutRow(box, false); + uiItemL(row, md->error, ICON_ERROR); + } + + return result; +} + +uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + Object *ob; + ShaderFxData *fx, *vfx; + int i; + + /* verify we have valid data */ + if (!RNA_struct_is_a(ptr->type, &RNA_ShaderFx)) { + RNA_warning("Expected shader fx on object"); + return NULL; + } + + ob = ptr->id.data; + fx = ptr->data; + + if (!ob || !(GS(ob->id.name) == ID_OB)) { + RNA_warning("Expected shader fx on object"); + return NULL; + } + + UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE); + + /* find modifier and draw it */ + vfx = ob->shader_fx.first; + for (i = 0; vfx; i++, vfx = vfx->next) { + if (fx == vfx) + return gpencil_draw_shaderfx(layout, ob, fx); + } + + return NULL; +} /************************ Redo Buttons Template *************************/ @@ -4638,7 +4906,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr); - uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (!file) { return; diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 3cb8a277e9a..e6422c423b9 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1536,15 +1536,6 @@ void init_userdef_do_versions(Main *bmain) #undef USER_VERSION_ATLEAST #define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST((&(U)), ver, subver) - - if (!USER_VERSION_ATLEAST(269, 9)) { - /* grease pencil - new layer color */ - if (U.gpencil_new_layer_col[3] < 0.1f) { - /* defaults to black, but must at least be visible! */ - U.gpencil_new_layer_col[3] = 0.9f; - } - } - if (!USER_VERSION_ATLEAST(271, 5)) { U.pie_menu_radius = 100; U.pie_menu_threshold = 12; @@ -1582,6 +1573,17 @@ void init_userdef_do_versions(Main *bmain) for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) { memcpy(btheme, &U_theme_default, sizeof(*btheme)); } + + /* Annotations - new layer color + * Replace anything that used to be set if it looks like was left + * on the old default (i.e. black), which most users used + */ + if ((U.gpencil_new_layer_col[3] < 0.1f) || (U.gpencil_new_layer_col[0] < 0.1f)) { + /* - New color matches the annotation pencil icon + * - Non-full alpha looks better! + */ + ARRAY_SET_ITEMS(U.gpencil_new_layer_col, 0.38f, 0.61f, 0.78f, 0.9f); + } } /** diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 305e3287029..739975a6278 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -31,6 +31,8 @@ set(INC ../../makesdna ../../makesrna ../../modifiers + ../../gpencil_modifiers + ../../shader_fx ../../python ../../render/extern/include ../../windowmanager @@ -53,6 +55,8 @@ set(SRC object_hook.c object_modes.c object_modifier.c + object_gpencil_modifier.c + object_shader_fx.c object_ops.c object_random.c object_relations.c diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 68e84ec3f3b..87eddc2674c 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -71,6 +71,7 @@ #include "BKE_displist.h" #include "BKE_effect.h" #include "BKE_font.h" +#include "BKE_gpencil.h" #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_layer.h" @@ -103,6 +104,7 @@ #include "ED_armature.h" #include "ED_curve.h" +#include "ED_gpencil.h" #include "ED_mball.h" #include "ED_mesh.h" #include "ED_node.h" @@ -985,6 +987,106 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot) ED_object_add_generic_props(ot, false); } +/********************* Add Gpencil Operator ********************/ + +static int object_gpencil_add_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL; + + const int type = RNA_enum_get(op->ptr, "type"); + + float loc[3], rot[3]; + unsigned int layer; + bool newob = false; + + /* Hack: Force view-align to be on by default + * since it's not nice for adding shapes in 2D + * for them to end up aligned oddly, but only for Monkey + */ + if ((RNA_struct_property_is_set(op->ptr, "view_align") == false) && + (type == GP_MONKEY)) { + RNA_boolean_set(op->ptr, "view_align", true); + } + + /* Note: We use 'Y' here (not 'Z'), as */ + WM_operator_view3d_unit_defaults(C, op); + if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &layer, NULL)) + return OPERATOR_CANCELLED; + + /* add new object if not currently editing a GP object, + * or if "empty" was chosen (i.e. user wants a blank GP canvas) + */ + if ((gpd == NULL) || (GPENCIL_ANY_MODE(gpd) == false) || (type == GP_EMPTY)) { + const char *ob_name = (type == GP_MONKEY) ? "Suzanne" : NULL; + float radius = RNA_float_get(op->ptr, "radius"); + + ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true, layer); + gpd = ob->data; + newob = true; + + BKE_object_obdata_size_init(ob, GP_OBGPENCIL_DEFAULT_SIZE * radius); + } + else { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_ADDED, NULL); + } + + /* create relevant geometry */ + switch (type) { + case GP_MONKEY: + { + float radius = RNA_float_get(op->ptr, "radius"); + float mat[4][4]; + + ED_object_new_primitive_matrix(C, ob, loc, rot, mat); + mul_v3_fl(mat[0], radius); + mul_v3_fl(mat[1], radius); + mul_v3_fl(mat[2], radius); + + ED_gpencil_create_monkey(C, mat); + break; + } + + case GP_EMPTY: + /* do nothing */ + break; + + default: + BKE_report(op->reports, RPT_WARNING, "Not implemented"); + break; + } + + /* if this is a new object, initialise default stuff (colors, etc.) */ + if (newob) { + ED_gpencil_add_defaults(C); + } + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_gpencil_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add GPencil"; + ot->description = "Add a grease pencil object to the scene"; + ot->idname = "OBJECT_OT_gpencil_add"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = object_gpencil_add_exec; + ot->poll = ED_operator_scene_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ED_object_add_unit_props(ot); + ED_object_add_generic_props(ot, false); + + ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", ""); +} + /********************* Add Light Operator ********************/ static const char *get_light_defname(int type) @@ -1781,6 +1883,10 @@ static int convert_exec(bContext *C, wmOperator *op) if (ob->type == OB_MESH) { BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ } + if (ob->type == OB_GPENCIL) { + BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ + BKE_object_free_shaderfx(ob, 0); + } } } else if (ob->type == OB_MESH && target == OB_CURVE) { @@ -2122,6 +2228,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer ID_NEW_REMAP_US(obn->mat[a]) else { obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); + /* duplicate grease pencil settings */ + if (ob->mat[a]->gp_style) { + obn->mat[a]->gp_style = MEM_dupallocN(ob->mat[a]->gp_style); + } } id_us_min(id); @@ -2258,6 +2368,16 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer id_us_min(id); } break; + case OB_GPENCIL: + if (dupflag != 0) { + ID_NEW_REMAP_US2(obn->data) + else { + obn->data = ID_NEW_SET(obn->data, BKE_gpencil_copy(bmain, obn->data)); + didit = 1; + } + id_us_min(id); + } + break; } /* check if obdata is copied */ @@ -2482,7 +2602,7 @@ static bool join_poll(bContext *C) if (!ob || ID_IS_LINKED(ob)) return 0; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE, OB_GPENCIL)) return ED_operator_screenactive(C); else return 0; @@ -2500,6 +2620,13 @@ static int join_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata"); return OPERATOR_CANCELLED; } + else if (ob->type == OB_GPENCIL) { + bGPdata *gpd = (bGPdata *)ob->data; + if ((!gpd) || GPENCIL_ANY_MODE(gpd)) { + BKE_report(op->reports, RPT_ERROR, "This data does not support joining in this mode"); + return OPERATOR_CANCELLED; + } + } if (ob->type == OB_MESH) return join_mesh_exec(C, op); @@ -2507,6 +2634,8 @@ static int join_exec(bContext *C, wmOperator *op) return join_curve_exec(C, op); else if (ob->type == OB_ARMATURE) return join_armature_exec(C, op); + else if (ob->type == OB_GPENCIL) + return ED_gpencil_join_objects_exec(C, op); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index a6c3c86922d..48048319cb7 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -100,6 +100,7 @@ #include "ED_screen.h" #include "ED_undo.h" #include "ED_image.h" +#include "ED_gpencil.h" #include "RNA_access.h" #include "RNA_define.h" @@ -1539,7 +1540,6 @@ static const EnumPropertyItem *object_mode_set_itemsf( const EnumPropertyItem *input = rna_enum_object_mode_items; EnumPropertyItem *item = NULL; Object *ob; - bGPdata *gpd; int totitem = 0; if (!C) /* needed for docs */ @@ -1555,7 +1555,9 @@ static const EnumPropertyItem *object_mode_set_itemsf( (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) || (input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) || (ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, - OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) || + OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) || + (ELEM(input->value, OB_MODE_GPENCIL_EDIT, OB_MODE_GPENCIL_PAINT, + OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT) && (ob->type == OB_GPENCIL)) || (input->value == OB_MODE_OBJECT)) { RNA_enum_item_add(&item, &totitem, input); @@ -1568,14 +1570,6 @@ static const EnumPropertyItem *object_mode_set_itemsf( RNA_enum_items_add_value(&item, &totitem, input, OB_MODE_OBJECT); } - /* On top of all the rest, GPencil Stroke Edit Mode - * is available if there's a valid gp datablock... - */ - gpd = CTX_data_gpencil_data(C); - if (gpd) { - RNA_enum_items_add_value(&item, &totitem, rna_enum_object_mode_items, OB_MODE_GPENCIL); - } - RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -1600,7 +1594,6 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) { bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_or_submode"); Object *ob = CTX_data_active_object(C); - bGPdata *gpd = CTX_data_gpencil_data(C); eObjectMode mode = RNA_enum_get(op->ptr, "mode"); eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT; const bool toggle = RNA_boolean_get(op->ptr, "toggle"); @@ -1620,22 +1613,9 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) } } - if (gpd) { - /* GP Mode is not bound to a specific object. Therefore, - * we don't want it to be actually saved on any objects, - * as weirdness can happen if you select other objects, - * or load old files. - * - * Instead, we use the following 2 rules to ensure that - * the mode selector works as expected: - * 1) If there's no object, we want to enter editmode. - * (i.e. with no object, we're in object mode) - * 2) Otherwise, exit stroke editmode, so that we can - * enter another mode... - */ - if (!ob || (gpd->flag & GP_DATA_STROKE_EDITMODE)) { - WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL); - } + /* by default the operator assume is a mesh, but if gp object change mode */ + if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) { + mode = OB_MODE_GPENCIL_EDIT; } if (!ob || !ED_object_mode_compat_test(ob, mode)) @@ -1666,6 +1646,14 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) } } + /* if type is OB_GPENCIL, set cursor mode */ + if ((ob) && (ob->type == OB_GPENCIL)) { + if (ob->data) { + bGPdata *gpd = (bGPdata *)ob->data; + ED_gpencil_setup_modes(C, gpd, ob->mode); + } + } + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c new file mode 100644 index 00000000000..175fb1706fb --- /dev/null +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -0,0 +1,637 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2018 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_gpencil_modifier.c + * \ingroup edobj + */ + + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_report.h" +#include "BKE_object.h" +#include "BKE_gpencil.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "ED_object.h" +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "object_intern.h" + +/******************************** API ****************************/ + +GpencilModifierData *ED_object_gpencil_modifier_add( + ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) +{ + GpencilModifierData *new_md = NULL; + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type); + + if (ob->type != OB_GPENCIL) { + BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); + return NULL; + } + + if (mti->flags & eGpencilModifierTypeFlag_Single) { + if (BKE_gpencil_modifiers_findByType(ob, type)) { + BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); + return NULL; + } + } + + /* get new modifier data to add */ + new_md = BKE_gpencil_modifier_new(type); + + BLI_addtail(&ob->greasepencil_modifiers, new_md); + + if (name) { + BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name)); + } + + /* make sure modifier data has unique name */ + BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md); + + + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + + return new_md; +} + +/* Return true if the object has a modifier of type 'type' other than + * the modifier pointed to be 'exclude', otherwise returns false. */ +static bool UNUSED_FUNCTION(gpencil_object_has_modifier)( + const Object *ob, const GpencilModifierData *exclude, + GpencilModifierType type) +{ + GpencilModifierData *md; + + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + if ((md != exclude) && (md->type == type)) + return true; + } + + return false; +} + +static bool gpencil_object_modifier_remove( + Main *bmain, Object *ob, GpencilModifierData *md, + bool *UNUSED(r_sort_depsgraph)) +{ + /* It seems on rapid delete it is possible to + * get called twice on same modifier, so make + * sure it is in list. */ + if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) { + return 0; + } + + DEG_relations_tag_update(bmain); + + BLI_remlink(&ob->greasepencil_modifiers, md); + BKE_gpencil_modifier_free(md); + BKE_object_free_derived_caches(ob); + + return 1; +} + +bool ED_object_gpencil_modifier_remove(ReportList *reports, Main *bmain, Object *ob, GpencilModifierData *md) +{ + bool sort_depsgraph = false; + bool ok; + + ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph); + + if (!ok) { + BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name); + return 0; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + + return 1; +} + +void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob) +{ + GpencilModifierData *md = ob->greasepencil_modifiers.first; + bool sort_depsgraph = false; + + if (!md) + return; + + while (md) { + GpencilModifierData *next_md; + + next_md = md->next; + + gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph); + + md = next_md; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); +} + +int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md) +{ + if (md->prev) { + BLI_remlink(&ob->greasepencil_modifiers, md); + BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md); + } + + return 1; +} + +int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md) +{ + if (md->next) { + BLI_remlink(&ob->greasepencil_modifiers, md); + BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md); + } + + return 1; +} + +static int gpencil_modifier_apply_obdata( + ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md) +{ + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + + if (mti->isDisabled && mti->isDisabled(md, 0)) { + BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); + return 0; + } + + if (ob->type == OB_GPENCIL) { + if (ELEM(NULL, ob, ob->data)) { + return 0; + } + else if (mti->bakeModifier == NULL) { + BKE_report(reports, RPT_ERROR, "Not implemented"); + return 0; + } + mti->bakeModifier(bmain, depsgraph, md, ob); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + else { + BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type"); + return 0; + } + + return 1; +} + +int ED_object_gpencil_modifier_apply( + Main *bmain, ReportList *reports, Depsgraph *depsgraph, + Object *ob, GpencilModifierData *md, int UNUSED(mode)) +{ + + if (ob->type == OB_GPENCIL) { + if (ob->mode != OB_MODE_OBJECT) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode"); + return 0; + } + + if (((ID *)ob->data)->us > 1) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); + return 0; + } + } + else if (((ID *)ob->data)->us > 1) { + BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data"); + return 0; + } + + if (md != ob->greasepencil_modifiers.first) + BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected"); + + if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) { + return 0; + } + + BLI_remlink(&ob->greasepencil_modifiers, md); + BKE_gpencil_modifier_free(md); + + return 1; +} + +int ED_object_gpencil_modifier_copy(ReportList *UNUSED(reports), Object *ob, GpencilModifierData *md) +{ + GpencilModifierData *nmd; + + nmd = BKE_gpencil_modifier_new(md->type); + BKE_gpencil_modifier_copyData(md, nmd); + BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd); + BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd); + + return 1; +} + +/************************ add modifier operator *********************/ + +static int gpencil_modifier_add_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + int type = RNA_enum_get(op->ptr, "type"); + + if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static const EnumPropertyItem *gpencil_modifier_add_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + Object *ob = ED_object_active_context(C); + EnumPropertyItem *item = NULL; + const EnumPropertyItem *md_item, *group_item = NULL; + const GpencilModifierTypeInfo *mti; + int totitem = 0, a; + + if (!ob) + return rna_enum_object_greasepencil_modifier_type_items; + + for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) { + md_item = &rna_enum_object_greasepencil_modifier_type_items[a]; + if (md_item->identifier[0]) { + mti = BKE_gpencil_modifierType_getInfo(md_item->value); + + if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) + continue; + } + else { + group_item = md_item; + md_item = NULL; + + continue; + } + + if (group_item) { + RNA_enum_item_add(&item, &totitem, group_item); + group_item = NULL; + } + + RNA_enum_item_add(&item, &totitem, md_item); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Add Grease Pencil Modifier"; + ot->description = "Add a procedural operation/effect to the active grease pencil object"; + ot->idname = "OBJECT_OT_gpencil_modifier_add"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = gpencil_modifier_add_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "type", rna_enum_object_modifier_type_items, eGpencilModifierType_Thick, "Type", ""); + RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf); + ot->prop = prop; +} + +/************************ generic functions for operators using mod names and data context *********************/ + +static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) +{ + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); + Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); + + if (!ptr.data) { + CTX_wm_operator_poll_msg_set(C, "Context missing 'modifier'"); + return 0; + } + + if (!ob || ID_IS_LINKED(ob)) return 0; + if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0; + if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0; + + if (ID_IS_STATIC_OVERRIDE(ob)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers comming from static override"); + return (((GpencilModifierData *)ptr.data)->flag & eGpencilModifierFlag_StaticOverride_Local) != 0; + } + + return 1; +} + +static bool gpencil_edit_modifier_poll(bContext *C) +{ + return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0); +} + +static void gpencil_edit_modifier_properties(wmOperatorType *ot) +{ + RNA_def_string(ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit"); +} + +static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op) +{ + GpencilModifierData *md; + + if (RNA_struct_property_is_set(op->ptr, "modifier")) { + return true; + } + else { + PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier); + if (ptr.data) { + md = ptr.data; + RNA_string_set(op->ptr, "modifier", md->name); + return true; + } + } + + return false; +} + +static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, Object *ob, int type) +{ + char modifier_name[MAX_NAME]; + GpencilModifierData *md; + RNA_string_get(op->ptr, "modifier", modifier_name); + + md = BKE_gpencil_modifiers_findByName(ob, modifier_name); + + if (md && type != 0 && md->type != type) + md = NULL; + + return md; +} + +/************************ remove modifier operator *********************/ + +static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + + if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int gpencil_modifier_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_remove_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot) +{ + ot->name = "Remove Grease Pencil Modifier"; + ot->description = "Remove a modifier from the active grease pencil object"; + ot->idname = "OBJECT_OT_gpencil_modifier_remove"; + + ot->invoke = gpencil_modifier_remove_invoke; + ot->exec = gpencil_modifier_remove_exec; + ot->poll = gpencil_edit_modifier_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); +} + +/************************ move up modifier operator *********************/ + +static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + + if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int gpencil_modifier_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_move_up_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_gpencil_modifier_move_up(wmOperatorType *ot) +{ + ot->name = "Move Up Modifier"; + ot->description = "Move modifier up in the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_move_up"; + + ot->invoke = gpencil_modifier_move_up_invoke; + ot->exec = gpencil_modifier_move_up_exec; + ot->poll = gpencil_edit_modifier_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); +} + +/************************ move down modifier operator *********************/ + +static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + + if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int gpencil_modifier_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_move_down_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot) +{ + ot->name = "Move Down Modifier"; + ot->description = "Move modifier down in the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_move_down"; + + ot->invoke = gpencil_modifier_move_down_invoke; + ot->exec = gpencil_modifier_move_down_exec; + ot->poll = gpencil_edit_modifier_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); +} + +/************************ apply modifier operator *********************/ + +static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + int apply_as = RNA_enum_get(op->ptr, "apply_as"); + + if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) { + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_apply_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +static const EnumPropertyItem gpencil_modifier_apply_as_items[] = { + {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"}, + {MODIFIER_APPLY_SHAPE, "SHAPE", 0, "New Shape", "Apply deform-only modifier to a new shape on this object"}, + {0, NULL, 0, NULL, NULL} +}; + +void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot) +{ + ot->name = "Apply Modifier"; + ot->description = "Apply modifier and remove from the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_apply"; + + ot->invoke = gpencil_modifier_apply_invoke; + ot->exec = gpencil_modifier_apply_exec; + ot->poll = gpencil_edit_modifier_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + + RNA_def_enum(ot->srna, "apply_as", gpencil_modifier_apply_as_items, MODIFIER_APPLY_DATA, "Apply as", "How to apply the modifier to the geometry"); + gpencil_edit_modifier_properties(ot); +} + +/************************ copy modifier operator *********************/ + +static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0); + + if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (gpencil_edit_modifier_invoke_properties(C, op)) + return gpencil_modifier_copy_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot) +{ + ot->name = "Copy Modifier"; + ot->description = "Duplicate modifier at the same position in the stack"; + ot->idname = "OBJECT_OT_gpencil_modifier_copy"; + + ot->invoke = gpencil_modifier_copy_invoke; + ot->exec = gpencil_modifier_copy_exec; + ot->poll = gpencil_edit_modifier_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + gpencil_edit_modifier_properties(ot); +} diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 1b5c6df2632..ef8653541f0 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -115,6 +115,7 @@ void OBJECT_OT_armature_add(struct wmOperatorType *ot); void OBJECT_OT_empty_add(struct wmOperatorType *ot); void OBJECT_OT_lightprobe_add(struct wmOperatorType *ot); void OBJECT_OT_drop_named_image(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_add(struct wmOperatorType *ot); void OBJECT_OT_light_add(struct wmOperatorType *ot); void OBJECT_OT_effector_add(struct wmOperatorType *ot); void OBJECT_OT_camera_add(struct wmOperatorType *ot); @@ -175,6 +176,20 @@ void OBJECT_OT_skin_armature_create(struct wmOperatorType *ot); void OBJECT_OT_laplaciandeform_bind(struct wmOperatorType *ot); void OBJECT_OT_surfacedeform_bind(struct wmOperatorType *ot); +/* grease pencil modifiers */ +void OBJECT_OT_gpencil_modifier_add(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_remove(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_move_up(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_move_down(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot); +void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot); + +/* shader fx */ +void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_remove(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_move_up(struct wmOperatorType *ot); +void OBJECT_OT_shaderfx_move_down(struct wmOperatorType *ot); + /* object_constraint.c */ void OBJECT_OT_constraint_add(struct wmOperatorType *ot); void OBJECT_OT_constraint_add_with_targets(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index e9bd6fbce8f..261f7f42bc0 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -27,6 +27,7 @@ * actual mode switching logic is per-object type. */ +#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_workspace_types.h" @@ -71,8 +72,14 @@ static const char *object_mode_op_string(eObjectMode mode) return "PARTICLE_OT_particle_edit_toggle"; if (mode == OB_MODE_POSE) return "OBJECT_OT_posemode_toggle"; - if (mode == OB_MODE_GPENCIL) + if (mode == OB_MODE_GPENCIL_EDIT) return "GPENCIL_OT_editmode_toggle"; + if (mode == OB_MODE_GPENCIL_PAINT) + return "GPENCIL_OT_paintmode_toggle"; + if (mode == OB_MODE_GPENCIL_SCULPT) + return "GPENCIL_OT_sculptmode_toggle"; + if (mode == OB_MODE_GPENCIL_WEIGHT) + return "GPENCIL_OT_weightmode_toggle"; return NULL; } @@ -85,8 +92,6 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) if (ob) { if (mode == OB_MODE_OBJECT) return true; - else if (mode == OB_MODE_GPENCIL) - return true; /* XXX: assume this is the case for now... */ switch (ob->type) { case OB_MESH: @@ -111,6 +116,13 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) return true; break; + case OB_GPENCIL: + if (mode & (OB_MODE_EDIT | OB_MODE_GPENCIL_EDIT | OB_MODE_GPENCIL_PAINT | + OB_MODE_GPENCIL_SCULPT | OB_MODE_GPENCIL_WEIGHT)) + { + return true; + } + break; } } diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 11d0fd9f9d5..f83c6af08ee 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1,31 +1,31 @@ /* - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * Contributor(s): Blender Foundation, 2009 - * - * ***** END GPL LICENSE BLOCK ***** - */ +* ***** BEGIN GPL LICENSE BLOCK ***** +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. +* All rights reserved. +* +* Contributor(s): Blender Foundation, 2009 +* +* ***** END GPL LICENSE BLOCK ***** +*/ /** \file blender/editors/object/object_modifier.c - * \ingroup edobj - */ +* \ingroup edobj +*/ #include @@ -117,8 +117,8 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc if (type == eModifierType_ParticleSystem) { /* don't need to worry about the new modifier's name, since that is set to the number - * of particle systems which shouldn't have too many duplicates - */ + * of particle systems which shouldn't have too many duplicates + */ new_md = object_add_particle_system(bmain, scene, ob, name); } else { @@ -182,9 +182,9 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc } /* Return true if the object has a modifier of type 'type' other than - * the modifier pointed to be 'exclude', otherwise returns false. */ +* the modifier pointed to be 'exclude', otherwise returns false. */ static bool object_has_modifier(const Object *ob, const ModifierData *exclude, - ModifierType type) + ModifierType type) { ModifierData *md; @@ -197,16 +197,16 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude, } /* If the object data of 'orig_ob' has other users, run 'callback' on - * each of them. - * - * If include_orig is true, the callback will run on 'orig_ob' too. - * - * If the callback ever returns true, iteration will stop and the - * function value will be true. Otherwise the function returns false. - */ +* each of them. +* +* If include_orig is true, the callback will run on 'orig_ob' too. +* +* If the callback ever returns true, iteration will stop and the +* function value will be true. Otherwise the function returns false. +*/ bool ED_object_iter_other(Main *bmain, Object *orig_ob, const bool include_orig, - bool (*callback)(Object *ob, void *callback_data), - void *callback_data) + bool (*callback)(Object *ob, void *callback_data), + void *callback_data) { ID *ob_data_id = orig_ob->data; int users = ob_data_id->us; @@ -220,10 +220,10 @@ bool ED_object_iter_other(Main *bmain, Object *orig_ob, const bool include_orig, int totfound = include_orig ? 0 : 1; for (ob = bmain->object.first; ob && totfound < users; - ob = ob->id.next) + ob = ob->id.next) { if (((ob != orig_ob) || include_orig) && - (ob->data == orig_ob->data)) + (ob->data == orig_ob->data)) { if (callback(ob, callback_data)) return true; @@ -247,8 +247,8 @@ static bool object_has_modifier_cb(Object *ob, void *data) } /* Use with ED_object_iter_other(). Sets the total number of levels - * for any multires modifiers on the object to the int pointed to by - * callback_data. */ +* for any multires modifiers on the object to the int pointed to by +* callback_data. */ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) { ModifierData *md; @@ -265,20 +265,20 @@ bool ED_object_multires_update_totlevels_cb(Object *ob, void *totlevel_v) /* Return true if no modifier of type 'type' other than 'exclude' */ static bool object_modifier_safe_to_delete(Main *bmain, Object *ob, - ModifierData *exclude, - ModifierType type) + ModifierData *exclude, + ModifierType type) { return (!object_has_modifier(ob, exclude, type) && - !ED_object_iter_other(bmain, ob, false, - object_has_modifier_cb, &type)); + !ED_object_iter_other(bmain, ob, false, + object_has_modifier_cb, &type)); } static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md, - bool *r_sort_depsgraph) + bool *r_sort_depsgraph) { /* It seems on rapid delete it is possible to - * get called twice on same modifier, so make - * sure it is in list. */ + * get called twice on same modifier, so make + * sure it is in list. */ if (BLI_findindex(&ob->modifiers, md) == -1) { return 0; } @@ -318,7 +318,7 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md, } if (ELEM(md->type, eModifierType_Softbody, eModifierType_Cloth) && - BLI_listbase_is_empty(&ob->particlesystem)) + BLI_listbase_is_empty(&ob->particlesystem)) { ob->mode &= ~OB_MODE_PARTICLE_EDIT; } @@ -522,7 +522,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene * } static int modifier_apply_shape( - Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md) + Main *bmain, ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); @@ -532,15 +532,15 @@ static int modifier_apply_shape( } /* - * It should be ridiculously easy to extract the original verts that we want - * and form the shape data. We can probably use the CD KEYINDEX layer (or - * whatever I ended up calling it, too tired to check now), though this would - * by necessity have to make some potentially ugly assumptions about the order - * of the mesh data :-/ you can probably assume in 99% of cases that the first - * element of a given index is the original, and any subsequent duplicates are - * copies/interpolates, but that's an assumption that would need to be tested - * and then predominantly stated in comments in a half dozen headers. - */ + * It should be ridiculously easy to extract the original verts that we want + * and form the shape data. We can probably use the CD KEYINDEX layer (or + * whatever I ended up calling it, too tired to check now), though this would + * by necessity have to make some potentially ugly assumptions about the order + * of the mesh data :-/ you can probably assume in 99% of cases that the first + * element of a given index is the original, and any subsequent duplicates are + * copies/interpolates, but that's an assumption that would need to be tested + * and then predominantly stated in comments in a half dozen headers. + */ if (ob->type == OB_MESH) { Mesh *mesh_applied; @@ -563,7 +563,7 @@ static int modifier_apply_shape( key = me->key = BKE_key_add(bmain, (ID *)me); key->type = KEY_RELATIVE; /* if that was the first key block added, then it was the basis. - * Initialize it with the mesh, and add another for the modifier */ + * Initialize it with the mesh, and add another for the modifier */ kb = BKE_keyblock_add(key, NULL); BKE_keyblock_convert_from_mesh(me, key, kb); } @@ -667,8 +667,8 @@ static int modifier_apply_obdata(ReportList *reports, Depsgraph *depsgraph, Scen } int ED_object_modifier_apply( - Main *bmain, ReportList *reports, Depsgraph *depsgraph, - Scene *scene, Object *ob, ModifierData *md, int mode) + Main *bmain, ReportList *reports, Depsgraph *depsgraph, + Scene *scene, Object *ob, ModifierData *md, int mode) { int prev_mode; @@ -681,8 +681,8 @@ int ED_object_modifier_apply( return 0; } else if ((ob->mode & OB_MODE_SCULPT) && - (find_multires_modifier_before(scene, md)) && - (modifier_isSameTopology(md) == false)) + (find_multires_modifier_before(scene, md)) && + (modifier_isSameTopology(md) == false)) { BKE_report(reports, RPT_ERROR, "Constructive modifier cannot be applied to multi-res data in sculpt mode"); return 0; @@ -692,7 +692,7 @@ int ED_object_modifier_apply( BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected"); /* Get evaluated modifier, so object links pointer to evaluated data, - * but still use original object it is applied to the original mesh. */ + * but still use original object it is applied to the original mesh. */ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md; @@ -752,7 +752,7 @@ static int modifier_add_exec(bContext *C, wmOperator *op) } static const EnumPropertyItem *modifier_add_itemf( - bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { Object *ob = ED_object_active_context(C); EnumPropertyItem *item = NULL; @@ -1165,8 +1165,8 @@ static int multires_higher_levels_delete_exec(bContext *C, wmOperator *op) multiresModifier_del_levels(mmd, scene, ob, 1); ED_object_iter_other(CTX_data_main(C), ob, true, - ED_object_multires_update_totlevels_cb, - &mmd->totlvl); + ED_object_multires_update_totlevels_cb, + &mmd->totlvl); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); @@ -1210,8 +1210,8 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) multiresModifier_subdivide(mmd, scene, ob, 0, mmd->simple); ED_object_iter_other(CTX_data_main(C), ob, true, - ED_object_multires_update_totlevels_cb, - &mmd->totlvl); + ED_object_multires_update_totlevels_cb, + &mmd->totlvl); DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); @@ -1387,8 +1387,8 @@ void OBJECT_OT_multires_external_save(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; WM_operator_properties_filesel( - ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); + ot, FILE_TYPE_FOLDER | FILE_TYPE_BTX, FILE_SPECIAL, FILE_SAVE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); edit_modifier_properties(ot); } @@ -1480,13 +1480,13 @@ static void modifier_skin_customdata_delete(Object *ob) static bool skin_poll(bContext *C) { return (!CTX_data_edit_object(C) && - edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); + edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); } static bool skin_edit_poll(bContext *C) { return (CTX_data_edit_object(C) && - edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); + edit_modifier_poll_generic(C, &RNA_SkinModifier, (1 << OB_MESH))); } static void skin_root_clear(BMVert *bm_vert, GSet *visited, const int cd_vert_skin_offset) @@ -1525,7 +1525,7 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op)) BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) && - BLI_gset_add(visited, bm_vert)) + BLI_gset_add(visited, bm_vert)) { MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(bm_vert, cd_vert_skin_offset); @@ -1579,8 +1579,8 @@ static int skin_loose_mark_clear_exec(bContext *C, wmOperator *op) BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) { MVertSkin *vs = CustomData_bmesh_get(&bm->vdata, - bm_vert->head.data, - CD_MVERT_SKIN); + bm_vert->head.data, + CD_MVERT_SKIN); switch (action) { @@ -1636,8 +1636,8 @@ static int skin_radii_equalize_exec(bContext *C, wmOperator *UNUSED(op)) BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT)) { MVertSkin *vs = CustomData_bmesh_get(&bm->vdata, - bm_vert->head.data, - CD_MVERT_SKIN); + bm_vert->head.data, + CD_MVERT_SKIN); float avg = (vs->radius[0] + vs->radius[1]) * 0.5f; vs->radius[0] = vs->radius[1] = avg; @@ -1664,12 +1664,12 @@ void OBJECT_OT_skin_radii_equalize(wmOperatorType *ot) } static void skin_armature_bone_create(Object *skin_ob, - MVert *mvert, MEdge *medge, - bArmature *arm, - BLI_bitmap *edges_visited, - const MeshElemMap *emap, - EditBone *parent_bone, - int parent_v) + MVert *mvert, MEdge *medge, + bArmature *arm, + BLI_bitmap *edges_visited, + const MeshElemMap *emap, + EditBone *parent_bone, + int parent_v) { int i; @@ -1704,12 +1704,12 @@ static void skin_armature_bone_create(Object *skin_ob, } skin_armature_bone_create(skin_ob, - mvert, medge, - arm, - edges_visited, - emap, - bone, - v); + mvert, medge, + arm, + edges_visited, + emap, + bone, + v); } } @@ -1731,10 +1731,10 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, /* add vertex weights to original mesh */ CustomData_add_layer(&me->vdata, - CD_MDEFORMVERT, - CD_CALLOC, - NULL, - me->totvert); + CD_MDEFORMVERT, + CD_CALLOC, + NULL, + me->totvert); ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); arm_ob = BKE_object_add(bmain, scene, view_layer, OB_ARMATURE, NULL); @@ -1747,19 +1747,19 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, mvert_skin = CustomData_get_layer(&me->vdata, CD_MVERT_SKIN); BKE_mesh_vert_edge_map_create(&emap, &emap_mem, - me->medge, me->totvert, me->totedge); + me->medge, me->totvert, me->totedge); edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited"); /* note: we use EditBones here, easier to set them up and use - * edit-armature functions to convert back to regular bones */ + * edit-armature functions to convert back to regular bones */ for (v = 0; v < me->totvert; v++) { if (mvert_skin[v].flag & MVERT_SKIN_ROOT) { EditBone *bone = NULL; /* Unless the skin root has just one adjacent edge, create - * a fake root bone (have it going off in the Y direction - * (arbitrary) */ + * a fake root bone (have it going off in the Y direction + * (arbitrary) */ if (emap[v].count > 1) { bone = ED_armature_ebone_add(arm, "Bone"); @@ -1772,12 +1772,12 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, if (emap[v].count >= 1) { skin_armature_bone_create(skin_ob, - mvert, me->medge, - arm, - edges_visited, - emap, - bone, - v); + mvert, me->medge, + arm, + edges_visited, + emap, + bone, + v); } } } @@ -2092,7 +2092,7 @@ static int oceanbake_breakjob(void *UNUSED(customdata)) //return *(ob->stop); /* this is not nice yet, need to make the jobs list template better - * for identifying/acting upon various different jobs */ + * for identifying/acting upon various different jobs */ /* but for now we'll reuse the render break... */ return (G.is_break); } @@ -2166,8 +2166,8 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) } och = BKE_ocean_init_cache(omd->cachepath, modifier_path_relbase(bmain, ob), - omd->bakestart, omd->bakeend, omd->wave_scale, - omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); + omd->bakestart, omd->bakeend, omd->wave_scale, + omd->chop_amount, omd->foam_coverage, omd->foam_fade, omd->resolution); och->time = MEM_mallocN(och->duration * sizeof(float), "foam bake time"); @@ -2176,22 +2176,22 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) /* precalculate time variable before baking */ for (f = omd->bakestart; f <= omd->bakeend; f++) { /* from physics_fluid.c: - * - * XXX: This can't be used due to an anim sys optimization that ignores recalc object animation, - * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) - * --> BKE_animsys_evaluate_all_animation(bmain, eval_time); - * This doesn't work with drivers: - * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); - */ + * + * XXX: This can't be used due to an anim sys optimization that ignores recalc object animation, + * leaving it for the depgraph (this ignores object animation such as modifier properties though... :/ ) + * --> BKE_animsys_evaluate_all_animation(bmain, eval_time); + * This doesn't work with drivers: + * --> BKE_animsys_evaluate_animdata(&fsDomain->id, fsDomain->adt, eval_time, ADT_RECALC_ALL); + */ /* Modifying the global scene isn't nice, but we can do it in - * this part of the process before a threaded job is created */ + * this part of the process before a threaded job is created */ //scene->r.cfra = f; //ED_update_for_newframe(bmain, scene); /* ok, this doesn't work with drivers, but is way faster. - * let's use this for now and hope nobody wants to drive the time value... */ + * let's use this for now and hope nobody wants to drive the time value... */ BKE_animsys_evaluate_animdata(CTX_data_depsgraph(C), scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM); och->time[i] = omd->time; @@ -2220,7 +2220,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) /* setup job */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Ocean Simulation", - WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_OCEAN); + WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_OCEAN); oj = MEM_callocN(sizeof(OceanBakeJob), "ocean bake job"); oj->owner = ob; oj->ocean = ocean; diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 7b6c1156874..ac2eb60456f 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -115,6 +115,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_empty_add); WM_operatortype_append(OBJECT_OT_lightprobe_add); WM_operatortype_append(OBJECT_OT_drop_named_image); + WM_operatortype_append(OBJECT_OT_gpencil_add); WM_operatortype_append(OBJECT_OT_light_add); WM_operatortype_append(OBJECT_OT_camera_add); WM_operatortype_append(OBJECT_OT_speaker_add); @@ -147,6 +148,20 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_skin_radii_equalize); WM_operatortype_append(OBJECT_OT_skin_armature_create); + /* grease pencil modifiers */ + WM_operatortype_append(OBJECT_OT_gpencil_modifier_add); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_remove); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_up); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_move_down); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_apply); + WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy); + + /* shader fx */ + WM_operatortype_append(OBJECT_OT_shaderfx_add); + WM_operatortype_append(OBJECT_OT_shaderfx_remove); + WM_operatortype_append(OBJECT_OT_shaderfx_move_up); + WM_operatortype_append(OBJECT_OT_shaderfx_move_down); + WM_operatortype_append(OBJECT_OT_correctivesmooth_bind); WM_operatortype_append(OBJECT_OT_meshdeform_bind); WM_operatortype_append(OBJECT_OT_explode_refresh); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 331b4af077d..a6751ee12a4 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -70,6 +70,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_displist.h" #include "BKE_global.h" +#include "BKE_gpencil.h" #include "BKE_fcurve.h" #include "BKE_idprop.h" #include "BKE_lamp.h" @@ -1609,21 +1610,11 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ -static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob) +static Object *single_object_users_object(Main *bmain, Object *ob) { /* base gets copy of object */ Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - /* remap gpencil parenting */ - - if (scene->gpd) { - bGPdata *gpd = scene->gpd; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->parent == ob) { - gpl->parent = obn; - } - } - } id_us_plus(&obn->id); id_us_min(&ob->id); @@ -1648,7 +1639,7 @@ static void single_object_users_collection(Main *bmain, Scene *scene, Collection /* an object may be in more than one collection */ if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { if (!ID_IS_LINKED(ob) && ob->id.us > 1) { - cob->ob = single_object_users_object(bmain, scene, cob->ob); + cob->ob = single_object_users_object(bmain, cob->ob); } } } @@ -1702,6 +1693,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* collection pointers in scene */ BKE_scene_groups_relink(scene); + /* active camera */ ID_NEW_REMAP(scene->camera); if (v3d) ID_NEW_REMAP(v3d->camera); @@ -1805,6 +1797,9 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer case OB_LIGHTPROBE: ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data)); break; + case OB_GPENCIL: + ob->data = ID_NEW_SET(ob->data, BKE_gpencil_copy(bmain, ob->data)); + break; default: printf("ERROR %s: can't copy %s\n", __func__, id->name); BLI_assert(!"This should never happen."); @@ -1940,10 +1935,6 @@ void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bo } } - if (scene->gpd) { - IDP_RelinkProperty(scene->gpd->id.properties); - } - if (scene->world) { IDP_RelinkProperty(scene->world->id.properties); } diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index d5f7a93cc6e..c23a1d64ee8 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -41,6 +41,7 @@ #include "DNA_armature_types.h" #include "DNA_lamp_types.h" #include "DNA_workspace_types.h" +#include "DNA_gpencil_types.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -88,8 +89,8 @@ * this takes into account the 'restrict selection in 3d view' flag. * deselect works always, the restriction just prevents selection */ -/* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or - * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */ + /* Note: send a NC_SCENE|ND_OB_SELECT notifier yourself! (or + * or a NC_SCENE|ND_OB_VISIBLE in case of visibility toggling */ void ED_object_base_select(Base *base, eObjectSelect_Mode mode) { diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c new file mode 100644 index 00000000000..681851850a5 --- /dev/null +++ b/source/blender/editors/object/object_shader_fx.c @@ -0,0 +1,469 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2018 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/object/object_shader_fx.c + * \ingroup edobj + */ + + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_gpencil_types.h" +#include "DNA_shader_fx_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_math.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_shader_fx.h" +#include "BKE_report.h" +#include "BKE_object.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "ED_object.h" +#include "ED_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "object_intern.h" + +/******************************** API ****************************/ + +ShaderFxData *ED_object_shaderfx_add(ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) +{ + ShaderFxData *new_fx = NULL; + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type); + + if (ob->type != OB_GPENCIL) { + BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2); + return NULL; + } + + if (fxi->flags & eShaderFxTypeFlag_Single) { + if (BKE_shaderfx_findByType(ob, type)) { + BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed"); + return NULL; + } + } + + /* get new effect data to add */ + new_fx = BKE_shaderfx_new(type); + + BLI_addtail(&ob->shader_fx, new_fx); + + if (name) { + BLI_strncpy_utf8(new_fx->name, name, sizeof(new_fx->name)); + } + + /* make sure effect data has unique name */ + BKE_shaderfx_unique_name(&ob->shader_fx, new_fx); + + bGPdata *gpd = ob->data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + + return new_fx; +} + +/* Return true if the object has a effect of type 'type' other than + * the shaderfx pointed to be 'exclude', otherwise returns false. */ +static bool UNUSED_FUNCTION(object_has_shaderfx)( + const Object *ob, const ShaderFxData *exclude, + ShaderFxType type) +{ + ShaderFxData *fx; + + for (fx = ob->shader_fx.first; fx; fx = fx->next) { + if ((fx != exclude) && (fx->type == type)) + return true; + } + + return false; +} + +static bool object_shaderfx_remove( + Main *bmain, Object *ob, ShaderFxData *fx, + bool *UNUSED(r_sort_depsgraph)) +{ + /* It seems on rapid delete it is possible to + * get called twice on same effect, so make + * sure it is in list. */ + if (BLI_findindex(&ob->shader_fx, fx) == -1) { + return 0; + } + + DEG_relations_tag_update(bmain); + + BLI_remlink(&ob->shader_fx, fx); + BKE_shaderfx_free(fx); + BKE_object_free_derived_caches(ob); + + return 1; +} + +bool ED_object_shaderfx_remove(ReportList *reports, Main *bmain, Object *ob, ShaderFxData *fx) +{ + bool sort_depsgraph = false; + bool ok; + + ok = object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph); + + if (!ok) { + BKE_reportf(reports, RPT_ERROR, "Effect '%s' not in object '%s'", fx->name, ob->id.name); + return 0; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); + + return 1; +} + +void ED_object_shaderfx_clear(Main *bmain, Object *ob) +{ + ShaderFxData *fx = ob->shader_fx.first; + bool sort_depsgraph = false; + + if (!fx) + return; + + while (fx) { + ShaderFxData *next_fx; + + next_fx = fx->next; + + object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph); + + fx = next_fx; + } + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_relations_tag_update(bmain); +} + +int ED_object_shaderfx_move_up(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx) +{ + if (fx->prev) { + BLI_remlink(&ob->shader_fx, fx); + BLI_insertlinkbefore(&ob->shader_fx, fx->prev, fx); + } + + return 1; +} + +int ED_object_shaderfx_move_down(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx) +{ + if (fx->next) { + BLI_remlink(&ob->shader_fx, fx); + BLI_insertlinkafter(&ob->shader_fx, fx->next, fx); + } + + return 1; +} + +/************************ add effect operator *********************/ + +static int shaderfx_add_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Object *ob = ED_object_active_context(C); + int type = RNA_enum_get(op->ptr, "type"); + + if (!ED_object_shaderfx_add(op->reports, bmain, scene, ob, NULL, type)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static const EnumPropertyItem *shaderfx_add_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + Object *ob = ED_object_active_context(C); + EnumPropertyItem *item = NULL; + const EnumPropertyItem *fx_item, *group_item = NULL; + const ShaderFxTypeInfo *mti; + int totitem = 0, a; + + if (!ob) + return rna_enum_object_shaderfx_type_items; + + for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) { + fx_item = &rna_enum_object_shaderfx_type_items[a]; + if (fx_item->identifier[0]) { + mti = BKE_shaderfxType_getInfo(fx_item->value); + + if (mti->flags & eShaderFxTypeFlag_NoUserAdd) + continue; + } + else { + group_item = fx_item; + fx_item = NULL; + + continue; + } + + if (group_item) { + RNA_enum_item_add(&item, &totitem, group_item); + group_item = NULL; + } + + RNA_enum_item_add(&item, &totitem, fx_item); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +void OBJECT_OT_shaderfx_add(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Add Effect"; + ot->description = "Add a visual effect to the active object"; + ot->idname = "OBJECT_OT_shaderfx_add"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = shaderfx_add_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_enum(ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", ""); + RNA_def_enum_funcs(prop, shaderfx_add_itemf); + ot->prop = prop; +} + +/************************ generic functions for operators using names and data context *********************/ + +static bool edit_shaderfx_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag) +{ + PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type); + Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); + + if (!ptr.data) { + CTX_wm_operator_poll_msg_set(C, "Context missing 'shaderfx'"); + return 0; + } + + if (!ob || ID_IS_LINKED(ob)) return 0; + if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0; + if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0; + + if (ID_IS_STATIC_OVERRIDE(ob)) { + CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs comming from static override"); + return (((ShaderFxData *)ptr.data)->flag & eShaderFxFlag_StaticOverride_Local) != 0; + } + + return 1; +} + +static bool edit_shaderfx_poll(bContext *C) +{ + return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0); +} + +static void edit_shaderfx_properties(wmOperatorType *ot) +{ + RNA_def_string(ot->srna, "shaderfx", NULL, MAX_NAME, "Shader", "Name of the shaderfx to edit"); +} + +static int edit_shaderfx_invoke_properties(bContext *C, wmOperator *op) +{ + ShaderFxData *fx; + + if (RNA_struct_property_is_set(op->ptr, "shaderfx")) { + return true; + } + else { + PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx); + if (ptr.data) { + fx = ptr.data; + RNA_string_set(op->ptr, "shaderfx", fx->name); + return true; + } + } + + return false; +} + +static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int type) +{ + char shaderfx_name[MAX_NAME]; + ShaderFxData *fx; + RNA_string_get(op->ptr, "shaderfx", shaderfx_name); + + fx = BKE_shaderfx_findByName(ob, shaderfx_name); + + if (fx && type != 0 && fx->type != type) + fx = NULL; + + return fx; +} + +/************************ remove shaderfx operator *********************/ + +static int shaderfx_remove_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + + if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (edit_shaderfx_invoke_properties(C, op)) + return shaderfx_remove_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_shaderfx_remove(wmOperatorType *ot) +{ + ot->name = "Remove Grease Pencil Modifier"; + ot->description = "Remove a shaderfx from the active grease pencil object"; + ot->idname = "OBJECT_OT_shaderfx_remove"; + + ot->invoke = shaderfx_remove_invoke; + ot->exec = shaderfx_remove_exec; + ot->poll = edit_shaderfx_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); +} + +/************************ move up shaderfx operator *********************/ + +static int shaderfx_move_up_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + + if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (edit_shaderfx_invoke_properties(C, op)) + return shaderfx_move_up_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot) +{ + ot->name = "Move Up Modifier"; + ot->description = "Move shaderfx up in the stack"; + ot->idname = "OBJECT_OT_shaderfx_move_up"; + + ot->invoke = shaderfx_move_up_invoke; + ot->exec = shaderfx_move_up_exec; + ot->poll = edit_shaderfx_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); +} + +/************************ move down shaderfx operator *********************/ + +static int shaderfx_move_down_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_active_context(C); + ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0); + + if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx)) + return OPERATOR_CANCELLED; + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (edit_shaderfx_invoke_properties(C, op)) + return shaderfx_move_down_exec(C, op); + else + return OPERATOR_CANCELLED; +} + +void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot) +{ + ot->name = "Move Down Modifier"; + ot->description = "Move shaderfx down in the stack"; + ot->idname = "OBJECT_OT_shaderfx_move_down"; + + ot->invoke = shaderfx_move_down_invoke; + ot->exec = shaderfx_move_down_exec; + ot->poll = edit_shaderfx_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_shaderfx_properties(ot); +} diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index d2a0879464b..96b540251b4 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -38,6 +38,7 @@ #include "DNA_lamp_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_gpencil_types.h" #include "DNA_group_types.h" #include "DNA_lattice_types.h" @@ -59,6 +60,7 @@ #include "BKE_armature.h" #include "BKE_lattice.h" #include "BKE_tracking.h" +#include "BKE_gpencil.h" #include "DEG_depsgraph.h" @@ -73,6 +75,7 @@ #include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" +#include "ED_gpencil.h" #include "MEM_guardedalloc.h" @@ -434,7 +437,7 @@ static int apply_objects_internal( /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) { + if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, @@ -480,6 +483,37 @@ static int apply_objects_internal( } } + if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + if (gpd) { + if (gpd->layers.first) { + /* Unsupported configuration */ + bool has_unparented_layers = false; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* Parented layers aren't supported as we can't easily re-evaluate the scene to sample parent movement */ + if (gpl->parent == NULL) { + has_unparented_layers = true; + break; + } + } + + if (has_unparented_layers == false) { + BKE_reportf(reports, RPT_ERROR, + "Can't apply to a GP datablock where all layers are parented: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2); + changed = false; + } + } + else { + /* No layers/data */ + BKE_reportf(reports, RPT_ERROR, + "Can't apply to GP datablock with no layers: Object \"%s\", %s \"%s\", aborting", + ob->id.name + 2, BKE_idcode_to_name(ID_GD), gpd->id.name + 2); + } + } + } + if (ob->type == OB_LAMP) { Lamp *la = ob->data; if (la->type == LA_AREA) { @@ -587,6 +621,10 @@ static int apply_objects_internal( cu->fsize *= scale; } } + else if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + BKE_gpencil_transform(gpd, mat); + } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); @@ -1056,6 +1094,69 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) lt->id.tag |= LIB_TAG_DOIT; do_inverse_offset = true; } + else if (ob->type == OB_GPENCIL) { + bGPdata *gpd = ob->data; + float gpcenter[3]; + if (gpd) { + if (centermode == ORIGIN_TO_GEOMETRY) { + zero_v3(gpcenter); + BKE_gpencil_centroid_3D(gpd, gpcenter); + add_v3_v3(gpcenter, ob->obmat[3]); + } + if (centermode == ORIGIN_TO_CURSOR) { + copy_v3_v3(gpcenter, cursor); + } + if ((centermode == ORIGIN_TO_GEOMETRY) || (centermode == ORIGIN_TO_CURSOR)) { + bGPDspoint *pt; + float imat[3][3], bmat[3][3]; + float offset_global[3]; + float offset_local[3]; + int i; + + sub_v3_v3v3(offset_global, gpcenter, ob->obmat[3]); + copy_m3_m4(bmat, obact->obmat); + invert_m3_m3(imat, bmat); + mul_m3_v3(imat, offset_global); + mul_v3_m3v3(offset_local, imat, offset_global); + + float diff_mat[4][4]; + float inverse_diff_mat[4][4]; + + /* recalculate all strokes (all layers are considered without evaluating lock attributtes) */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* calculate difference matrix */ + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + /* undo matrix */ + invert_m4_m4(inverse_diff_mat, diff_mat); + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + float mpt[3]; + mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x); + sub_v3_v3(mpt, offset_local); + mul_v3_m4v3(&pt->x, diff_mat, mpt); + } + } + } + } + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + + tot_change++; + if (centermode == ORIGIN_TO_GEOMETRY) { + copy_v3_v3(ob->loc, gpcenter); + } + ob->id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } + else { + BKE_report(op->reports, RPT_WARNING, "Grease Pencil Object does not support this set origin option"); + } + } + } /* offset other selected objects */ if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) { diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 22000bd2a03..ed7950f3993 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -329,7 +329,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R GPU_matrix_translate_2f(sizex / 2, sizey / 2); G.f |= G_RENDER_OGL; - ED_gpencil_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); + ED_gpencil_draw_ex(rv3d, scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); G.f &= ~G_RENDER_OGL; gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect"); @@ -417,7 +417,7 @@ static void screen_opengl_render_write(OGLRender *oglrender) else printf("OpenGL Render failed to write '%s'\n", name); } -static void addAlphaOverFloat(float dest[4], const float source[4]) +static void UNUSED_FUNCTION(addAlphaOverFloat)(float dest[4], const float source[4]) { /* d = s + (1-alpha_s)d*/ float mul; @@ -431,91 +431,6 @@ static void addAlphaOverFloat(float dest[4], const float source[4]) } -/* add renderlayer and renderpass for each grease pencil layer for using in composition */ -static void add_gpencil_renderpass(const bContext *C, OGLRender *oglrender, RenderResult *rr, RenderView *rv) -{ - bGPdata *gpd = oglrender->scene->gpd; - Scene *scene = oglrender->scene; - - /* sanity checks */ - if (gpd == NULL) { - return; - } - if (scene == NULL) { - return; - } - if (BLI_listbase_is_empty(&gpd->layers)) { - return; - } - if (oglrender->v3d != NULL && (oglrender->v3d->flag2 & V3D_SHOW_GPENCIL) == 0) { - return; - } - - /* save old alpha mode */ - short oldalphamode = scene->r.alphamode; - /* set alpha transparent for gp */ - scene->r.alphamode = R_ALPHAPREMUL; - - /* saves layer status */ - short *oldsts = MEM_mallocN(BLI_listbase_count(&gpd->layers) * sizeof(short), "temp_gplayers_flag"); - int i = 0; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - oldsts[i] = gpl->flag; - ++i; - } - /* loop all layers to create separate render */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* dont draw layer if hidden */ - if (gpl->flag & GP_LAYER_HIDE) - continue; - /* hide all layer except current */ - for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) { - if (gpl != gph) { - gph->flag |= GP_LAYER_HIDE; - } - } - - /* render this gp layer */ - screen_opengl_render_doit(C, oglrender, rr); - - /* add RendePass composite */ - RenderPass *rp = RE_create_gp_pass(rr, gpl->info, rv->name); - - /* copy image data from rectf */ - // XXX: Needs conversion. - unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32; - if (src != NULL) { - float *dest = rp->rect; - - int x, y, rectx, recty; - rectx = rr->rectx; - recty = rr->recty; - for (y = 0; y < recty; y++) { - for (x = 0; x < rectx; x++) { - unsigned char *pixSrc = src + 4 * (rectx * y + x); - if (pixSrc[3] > 0) { - float *pixDest = dest + 4 * (rectx * y + x); - float float_src[4]; - srgb_to_linearrgb_uchar4(float_src, pixSrc); - addAlphaOverFloat(pixDest, float_src); - } - } - } - } - /* back layer status */ - i = 0; - for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) { - gph->flag = oldsts[i]; - ++i; - } - } - /* free memory */ - MEM_freeN(oldsts); - - /* back default alpha mode */ - scene->r.alphamode = oldalphamode; -} - static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) { RenderResult *rr; @@ -550,11 +465,6 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) BLI_assert(view_id < oglrender->views_len); RE_SetActiveRenderView(oglrender->re, rv->name); oglrender->view_id = view_id; - /* add grease pencil passes. For sequencer, the render does not include renderpasses - * TODO: The sequencer render of grease pencil should be rethought */ - if (!oglrender->is_sequencer) { - add_gpencil_renderpass(C, oglrender, rr, rv); - } /* render composite */ screen_opengl_render_doit(C, oglrender, rr); } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 3423eedf7ca..069611be35d 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -198,6 +198,7 @@ typedef struct IconPreview { static Main *G_pr_main = NULL; static Main *G_pr_main_cycles = NULL; +static Main *G_pr_main_grease_pencil = NULL; #ifndef WITH_HEADLESS static Main *load_main_from_memory(const void *blend, int blend_size) @@ -227,6 +228,7 @@ void ED_preview_ensure_dbase(void) if (!base_initialized) { G_pr_main = load_main_from_memory(datatoc_preview_blend, datatoc_preview_blend_size); G_pr_main_cycles = load_main_from_memory(datatoc_preview_cycles_blend, datatoc_preview_cycles_blend_size); + G_pr_main_grease_pencil = load_main_from_memory(datatoc_preview_grease_pencil_blend, datatoc_preview_grease_pencil_blend_size); base_initialized = true; } #endif @@ -245,6 +247,9 @@ void ED_preview_free_dbase(void) if (G_pr_main_cycles) BKE_main_free(G_pr_main_cycles); + + if (G_pr_main_grease_pencil) + BKE_main_free(G_pr_main_grease_pencil); } static Scene *preview_get_scene(Main *pr_main) @@ -1102,6 +1107,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short sp->id_copy = ip->id_copy; sp->bmain = ip->bmain; sp->own_id_copy = false; + Material *ma = NULL; if (is_render) { BLI_assert(ip->id); @@ -1109,10 +1115,22 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short * so don't even think of using cycle's bmain for * texture icons */ - if (GS(ip->id->name) != ID_TE) - sp->pr_main = G_pr_main_cycles; - else + if (GS(ip->id->name) != ID_TE) { + /* grease pencil use its own preview file */ + if (GS(ip->id->name) == ID_MA) { + ma = (Material *)ip->id; + } + + if ((ma == NULL) || (ma->gp_style == NULL)) { + sp->pr_main = G_pr_main_cycles; + } + else { + sp->pr_main = G_pr_main_grease_pencil; + } + } + else { sp->pr_main = G_pr_main; + } } common_preview_startjob(sp, stop, do_update, progress); @@ -1274,11 +1292,23 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M sp->parent = parent; sp->slot = slot; sp->bmain = CTX_data_main(C); + Material *ma = NULL; /* hardcoded preview .blend for Eevee + Cycles, this should be solved * once with custom preview .blend path for external engines */ if ((method != PR_NODE_RENDER) && id_type != ID_TE) { - sp->pr_main = G_pr_main_cycles; + /* grease pencil use its own preview file */ + if (GS(id->name) == ID_MA) { + ma = (Material *)id; + } + + if ((ma == NULL) || (ma->gp_style == NULL)) { + sp->pr_main = G_pr_main_cycles; + } + else { + sp->pr_main = G_pr_main_grease_pencil; + } + } else { sp->pr_main = G_pr_main; diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 8077079a9b5..2dd4f328d06 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -469,6 +469,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) { Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); PointerRNA ptr, idptr; PropertyRNA *prop; @@ -477,7 +478,12 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) ma = BKE_material_copy(bmain, ma); } else { - ma = BKE_material_add(bmain, DATA_("Material")); + if ((!ob) || (ob->type != OB_GPENCIL)) { + ma = BKE_material_add(bmain, DATA_("Material")); + } + else { + ma = BKE_material_add_gpencil(bmain, DATA_("Material")); + } ED_node_shader_default(C, &ma->id); ma->use_nodes = true; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 1a63bc1cd53..18bacee98b9 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1428,18 +1428,32 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand } if (flag & ED_KEYMAP_GPENCIL) { /* grease pencil */ - /* NOTE: This is now 2 keymaps - One for basic functionality, - * and one that only applies when "Edit Mode" is enabled - * for strokes. + /* NOTE: This is now 4 keymaps - One for basic functionality, + * and others for special stroke modes (edit, paint and sculpt). * - * For now, it's easier to just include both, - * since you hardly want one without the other. + * For now, it's easier to just include all, + * since you hardly want one without the others. */ wmKeyMap *keymap_general = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0); - wmKeyMap *keymap_edit = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0); - WM_event_add_keymap_handler(handlers, keymap_general); + + wmKeyMap *keymap_edit = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0); WM_event_add_keymap_handler(handlers, keymap_edit); + + wmKeyMap *keymap_paint = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint Mode", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_paint); + + wmKeyMap *keymap_paint_draw = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint (Draw brush)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_paint_draw); + + wmKeyMap *keymap_paint_erase = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint (Erase)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_paint_erase); + + wmKeyMap *keymap_paint_fill = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Paint (Fill)", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_paint_fill); + + wmKeyMap *keymap_sculpt = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Sculpt Mode", 0, 0); + WM_event_add_keymap_handler(handlers, keymap_sculpt); } if (flag & ED_KEYMAP_HEADER) { /* standard keymap for headers regions */ diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 17b1af29010..ecfc9f2cca0 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -34,6 +34,7 @@ #include "DNA_object_types.h" #include "DNA_armature_types.h" +#include "DNA_brush_types.h" #include "DNA_gpencil_types.h" #include "DNA_sequence_types.h" #include "DNA_scene_types.h" @@ -44,10 +45,13 @@ #include "BLI_utildefines.h" +#include "BKE_brush.h" #include "BKE_context.h" #include "BKE_object.h" #include "BKE_action.h" #include "BKE_armature.h" +#include "BKE_paint.h" +#include "BKE_main.h" #include "BKE_gpencil.h" #include "BKE_layer.h" #include "BKE_screen.h" @@ -80,8 +84,7 @@ const char *screen_context_dir[] = { "sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */ "gpencil_data", "gpencil_data_owner", /* grease pencil data */ "visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes", - "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_palette", - "active_gpencil_palettecolor", "active_gpencil_brush", + "active_gpencil_layer", "active_gpencil_frame", "active_gpencil_brush", "active_operator", "selected_editable_fcurves", NULL}; @@ -467,7 +470,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult * (as outlined above - see Campbell's #ifdefs). That causes the get_active function to fail when * called from context. For that reason, we end up using an alternative where we pass everything in! */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact); if (gpd) { CTX_data_id_pointer_set(result, &gpd->id); @@ -482,7 +485,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult PointerRNA ptr; /* get pointer to Grease Pencil Data */ - gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, scene, sa, obact, &ptr); + gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, sa, scene, obact, &ptr); if (gpd_ptr) { CTX_data_pointer_set(result, ptr.id.data, ptr.type, ptr.data); @@ -491,7 +494,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } else if (CTX_data_equals(member, "active_gpencil_layer")) { /* XXX: see comment for gpencil_data case... */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact); if (gpd) { bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); @@ -502,47 +505,17 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } } } - else if (CTX_data_equals(member, "active_gpencil_palette")) { - /* XXX: see comment for gpencil_data case... */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); - - if (gpd) { - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - - if (palette) { - CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPalette, palette); - return 1; - } - } - } - else if (CTX_data_equals(member, "active_gpencil_palettecolor")) { - /* XXX: see comment for gpencil_data case... */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); - - if (gpd) { - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - - if (palette) { - bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette); - if (palcolor) { - CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilPaletteColor, palcolor); - return 1; - } - } - } - } else if (CTX_data_equals(member, "active_gpencil_brush")) { - /* XXX: see comment for gpencil_data case... */ - bGPDbrush *brush = BKE_gpencil_brush_getactive(scene->toolsettings); + Brush *brush = BKE_brush_getactive_gpencil(scene->toolsettings); if (brush) { - CTX_data_pointer_set(result, &scene->id, &RNA_GPencilBrush, brush); + CTX_data_pointer_set(result, &scene->id, &RNA_Brush, brush); return 1; } } else if (CTX_data_equals(member, "active_gpencil_frame")) { /* XXX: see comment for gpencil_data case... */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact); if (gpd) { bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); @@ -555,7 +528,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } else if (CTX_data_equals(member, "visible_gpencil_layers")) { /* XXX: see comment for gpencil_data case... */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact); if (gpd) { bGPDlayer *gpl; @@ -571,7 +544,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } else if (CTX_data_equals(member, "editable_gpencil_layers")) { /* XXX: see comment for gpencil_data case... */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact); if (gpd) { bGPDlayer *gpl; @@ -587,24 +560,37 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } else if (CTX_data_equals(member, "editable_gpencil_strokes")) { /* XXX: see comment for gpencil_data case... */ - bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact); + bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, sa, scene, obact); + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); if (gpd) { bGPDlayer *gpl; for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { if (gpencil_layer_is_editable(gpl) && (gpl->actframe)) { - bGPDframe *gpf = gpl->actframe; + bGPDframe *gpf; bGPDstroke *gps; + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } - for (gps = gpf->strokes.first; gps; gps = gps->next) { - if (ED_gpencil_stroke_can_use_direct(sa, gps)) { - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { - continue; + for (gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + for (gps = gpf->strokes.first; gps; gps = gps->next) { + if (ED_gpencil_stroke_can_use_direct(sa, gps)) { + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { + continue; + } + + CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps); + } } - - CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps); + } + /* if not multiedit out of loop */ + if (!is_multiedit) { + break; } } } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a837b32b0bb..df909794353 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2608,11 +2608,14 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op) /* populate tree with keyframe nodes */ scene_to_keylist(&ads, scene, &keys, NULL); - gpencil_to_keylist(&ads, scene->gpd, &keys); if (ob) { ob_to_keylist(&ads, ob, &keys, NULL); - gpencil_to_keylist(&ads, ob->gpd, &keys); + + if (ob->type == OB_GPENCIL) { + const bool active = !(scene->flag & SCE_KEYS_NO_SELONLY); + gpencil_to_keylist(&ads, ob->data, &keys, active); + } } { diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 0f796020d9e..86d36ade477 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -29,20 +29,27 @@ #include "BLI_string.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_math_color.h" #include "DNA_customdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" +#include "DNA_gpencil_types.h" #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_paint.h" +#include "BKE_gpencil.h" #include "BKE_main.h" +#include "BKE_report.h" + +#include "DEG_depsgraph.h" #include "ED_paint.h" #include "ED_screen.h" #include "ED_image.h" +#include "ED_gpencil.h" #include "UI_resources.h" #include "WM_api.h" @@ -96,6 +103,43 @@ static void BRUSH_OT_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op)) +{ + /*int type = RNA_enum_get(op->ptr, "type");*/ + ToolSettings *ts = CTX_data_tool_settings(C); + Paint *paint = &ts->gp_paint->paint; + Brush *br = BKE_paint_brush(paint); + Main *bmain = CTX_data_main(C); + // ePaintMode mode = ePaintGpencil; + + if (br) { + br = BKE_brush_copy(bmain, br); + } + else { + br = BKE_brush_add(bmain, "Brush", OB_MODE_GPENCIL_PAINT); + id_us_min(&br->id); /* fake user only */ + } + + BKE_paint_brush_set(paint, br); + + /* TODO init grease pencil specific data */ + + return OPERATOR_FINISHED; +} + +static void BRUSH_OT_add_gpencil(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Drawing Brush"; + ot->description = "Add brush for grease pencil"; + ot->idname = "BRUSH_OT_add_gpencil"; + + /* api callbacks */ + ot->exec = brush_add_gpencil_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} static int brush_scale_size_exec(bContext *C, wmOperator *op) { @@ -232,7 +276,6 @@ static void PALETTE_OT_color_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Paint *paint = BKE_paint_get_active_from_context(C); @@ -1031,6 +1074,7 @@ void ED_operatortypes_paint(void) /* brush */ WM_operatortype_append(BRUSH_OT_add); + WM_operatortype_append(BRUSH_OT_add_gpencil); WM_operatortype_append(BRUSH_OT_scale_size); WM_operatortype_append(BRUSH_OT_curve_preset); WM_operatortype_append(BRUSH_OT_reset); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index c46d0fdb035..831c461538a 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -51,6 +51,7 @@ #include "BKE_fcurve.h" #include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_gpencil.h" #include "UI_view2d.h" @@ -134,15 +135,20 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel) /* Now set the flags */ for (ale = anim_data.first; ale; ale = ale->next) { - if (ale->type == ANIMTYPE_GPLAYER) + if (ale->type == ANIMTYPE_GPLAYER) { ED_gplayer_frame_select_set(ale->data, sel); - else if (ale->type == ANIMTYPE_MASKLAYER) + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { ED_masklayer_frame_select_set(ale->data, sel); - else + } + else { ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL); + } } /* Cleanup */ + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } @@ -283,12 +289,16 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { ED_gplayer_frames_select_border(gpl, rectf.xmin, rectf.xmax, selectmode); } + ale->update |= ANIM_UPDATE_DEPS; break; } #endif case ANIMTYPE_GPLAYER: + { ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode); + ale->update |= ANIM_UPDATE_DEPS; break; + } case ANIMTYPE_MASKDATABLOCK: { Mask *mask = ale->data; @@ -312,6 +322,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s } /* cleanup */ + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } @@ -493,6 +504,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, case ANIMTYPE_GPLAYER: { ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + ale->update |= ANIM_UPDATE_DEPS; break; } case ANIMTYPE_MASKDATABLOCK: @@ -520,6 +532,7 @@ static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, } /* cleanup */ + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } @@ -707,6 +720,7 @@ static void markers_selectkeys_between(bAnimContext *ac) } else if (ale->type == ANIMTYPE_GPLAYER) { ED_gplayer_frames_select_border(ale->data, min, max, SELECT_ADD); + ale->update |= ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_masklayer_frames_select_border(ale->data, min, max, SELECT_ADD); @@ -717,6 +731,7 @@ static void markers_selectkeys_between(bAnimContext *ac) } /* Cleanup */ + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } @@ -796,17 +811,23 @@ static void columnselect_action_keys(bAnimContext *ac, short mode) ked.f1 = ce->cfra; /* select elements with frame number matching cfraelem */ - if (ale->type == ANIMTYPE_GPLAYER) + if (ale->type == ANIMTYPE_GPLAYER) { ED_gpencil_select_frame(ale->data, ce->cfra, SELECT_ADD); - else if (ale->type == ANIMTYPE_MASKLAYER) + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { ED_mask_select_frame(ale->data, ce->cfra, SELECT_ADD); - else + } + else { ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + } } } /* free elements */ BLI_freelistN(&ked.list); + + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } @@ -1081,12 +1102,16 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); } - else if (ale->type == ANIMTYPE_GPLAYER) + else if (ale->type == ANIMTYPE_GPLAYER) { ED_gplayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode); - else if (ale->type == ANIMTYPE_MASKLAYER) + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { ED_masklayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode); - else + } + else { ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + } } /* Sync marker support */ @@ -1111,6 +1136,7 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se } /* Cleanup */ + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } @@ -1227,6 +1253,7 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s /* select the nominated keyframe on the given frame */ if (ale->type == ANIMTYPE_GPLAYER) { ED_gpencil_select_frame(ale->data, selx, select_mode); + ale->update |= ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_mask_select_frame(ale->data, selx, select_mode); @@ -1244,12 +1271,14 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s for (ale = anim_data.first; ale; ale = ale->next) { if (ale->type == ANIMTYPE_GPLAYER) { ED_gpencil_select_frame(ale->data, selx, select_mode); + ale->update |= ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_mask_select_frame(ale->data, selx, select_mode); } } + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } else { @@ -1294,16 +1323,22 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se ked.f1 = selx; /* select elements with frame number matching cfra */ - if (ale->type == ANIMTYPE_GPLAYER) + if (ale->type == ANIMTYPE_GPLAYER) { ED_gpencil_select_frame(ale->key_data, selx, select_mode); - else if (ale->type == ANIMTYPE_MASKLAYER) + ale->update |= ANIM_UPDATE_DEPS; + } + else if (ale->type == ANIMTYPE_MASKLAYER) { ED_mask_select_frame(ale->key_data, selx, select_mode); - else + } + else { ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); + } } /* free elements */ BLI_freelistN(&ked.list); + + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } @@ -1318,6 +1353,7 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s /* select all keyframes in this channel */ if (ale->type == ANIMTYPE_GPLAYER) { ED_gpencil_select_frames(ale->data, select_mode); + ale->update = ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_mask_select_frames(ale->data, select_mode); @@ -1335,12 +1371,14 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s for (ale = anim_data.first; ale; ale = ale->next) { if (ale->type == ANIMTYPE_GPLAYER) { ED_gpencil_select_frames(ale->data, select_mode); + ale->update |= ANIM_UPDATE_DEPS; } else if (ale->type == ANIMTYPE_MASKLAYER) { ED_mask_select_frames(ale->data, select_mode); } } + ANIM_animdata_update(ac, &anim_data); ANIM_animdata_freelist(&anim_data); } else { @@ -1473,6 +1511,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ /* remove active channel from list of channels for separate treatment (since it's needed later on) */ BLI_remlink(&anim_data, ale); + ale->next = ale->prev = NULL; /* cleanup temporary lists */ BLI_dlrbTree_free(&anim_keys); @@ -1557,6 +1596,12 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ } } + /* flush tagged updates + * NOTE: We temporarily add this channel back to the list so that this can happen + */ + anim_data.first = anim_data.last = ale; + ANIM_animdata_update(ac, &anim_data); + /* free this channel */ MEM_freeN(ale); } diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index faee9c2b7ac..67632f6a53a 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -237,6 +237,7 @@ static int buttons_context_path_data(ButsContextPath *path, int type) else if (RNA_struct_is_a(ptr->type, &RNA_Light) && (type == -1 || type == OB_LAMP)) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_Speaker) && (type == -1 || type == OB_SPEAKER)) return 1; else if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && (type == -1 || type == OB_LIGHTPROBE)) return 1; + else if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (type == -1 || type == OB_GPENCIL)) return 1; /* try to get an object in the path, no pinning supported here */ else if (buttons_context_path_object(path)) { ob = path->ptr[path->len - 1].data; @@ -260,7 +261,21 @@ static int buttons_context_path_modifier(ButsContextPath *path) if (buttons_context_path_object(path)) { ob = path->ptr[path->len - 1].data; - if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE)) + if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE, OB_GPENCIL)) + return 1; + } + + return 0; +} + +static int buttons_context_path_shaderfx(ButsContextPath *path) +{ + Object *ob; + + if (buttons_context_path_object(path)) { + ob = path->ptr[path->len - 1].data; + + if (ob && ELEM(ob->type, OB_GPENCIL)) return 1; } @@ -485,6 +500,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma WorkSpace *workspace = CTX_wm_workspace(C); ID *id; int found; + Object *ob = CTX_data_active_object(C); memset(path, 0, sizeof(*path)); path->flag = flag; @@ -546,6 +562,9 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma case BCONTEXT_MODIFIER: found = buttons_context_path_modifier(path); break; + case BCONTEXT_SHADERFX: + found = buttons_context_path_shaderfx(path); + break; case BCONTEXT_DATA: found = buttons_context_path_data(path, -1); break; @@ -553,7 +572,14 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma found = buttons_context_path_particle(path); break; case BCONTEXT_MATERIAL: - found = buttons_context_path_material(path); + /* NOTE: Grease Pencil materials use different panels... */ + if (ob && ob->type == OB_GPENCIL) { + /* XXX: Why path_data? */ + found = buttons_context_path_data(path, -1); + } + else { + found = buttons_context_path_material(path); + } break; case BCONTEXT_TEXTURE: found = buttons_context_path_texture(C, path, sbuts->texuser); @@ -626,10 +652,18 @@ void buttons_context_compute(const bContext *C, SpaceButs *sbuts) if (a == BCONTEXT_DATA) { ptr = &path->ptr[path->len - 1]; - if (ptr->type) + if (ptr->type) { sbuts->dataicon = RNA_struct_ui_icon(ptr->type); - else - sbuts->dataicon = ICON_EMPTY_DATA; + } + else { + Object *ob = CTX_data_active_object(C); + if (ob->type == OB_GPENCIL) { + sbuts->dataicon = ICON_GREASEPENCIL; + } + else { + sbuts->dataicon = ICON_EMPTY_DATA; + } + } } } } diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 66684de18ac..de422565abd 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -55,6 +55,7 @@ #include "BKE_layer.h" #include "BKE_linestyle.h" #include "BKE_modifier.h" +#include "BKE_gpencil_modifier.h" #include "BKE_node.h" #include "BKE_paint.h" #include "BKE_particle.h" @@ -152,6 +153,19 @@ static void buttons_texture_modifier_foreach(void *userData, Object *ob, Modifie N_("Modifiers"), RNA_struct_ui_icon(ptr.type), md->name); } +static void buttons_texture_modifier_gpencil_foreach(void *userData, Object *ob, GpencilModifierData *md, const char *propname) +{ + PointerRNA ptr; + PropertyRNA *prop; + ListBase *users = userData; + + RNA_pointer_create(&ob->id, &RNA_GpencilModifier, md, &ptr); + prop = RNA_struct_find_property(&ptr, propname); + + buttons_texture_user_property_add(users, &ob->id, ptr, prop, + N_("Grease Pencil Modifiers"), RNA_struct_ui_icon(ptr.type), md->name); +} + static void buttons_texture_users_from_context(ListBase *users, const bContext *C, SpaceButs *sbuts) { Scene *scene = NULL; @@ -203,6 +217,9 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext * /* modifiers */ modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users); + /* grease pencil modifiers */ + BKE_gpencil_modifiers_foreachTexLink(ob, buttons_texture_modifier_gpencil_foreach, users); + /* particle systems */ if (psys && !limited_mode) { for (a = 0; a < MAX_MTEX; a++) { diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 6f7a4ca971a..62115aea11d 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -180,6 +180,9 @@ static void buttons_main_region_layout_properties(const bContext *C, SpaceButs * case BCONTEXT_MODIFIER: contexts[0] = "modifier"; break; + case BCONTEXT_SHADERFX: + contexts[0] = "shaderfx"; + break; case BCONTEXT_CONSTRAINT: contexts[0] = "constraint"; break; @@ -200,8 +203,9 @@ static void buttons_main_region_layout_tool(const bContext *C, ARegion *ar) const char *contexts[3] = {NULL}; const WorkSpace *workspace = CTX_wm_workspace(C); + const int mode = CTX_data_mode_enum(C); + if (workspace->tools_space_type == SPACE_VIEW3D) { - const int mode = CTX_data_mode_enum(C); switch (mode) { case CTX_MODE_EDIT_MESH: ARRAY_SET_ITEMS(contexts, ".mesh_edit"); @@ -245,12 +249,39 @@ static void buttons_main_region_layout_tool(const bContext *C, ARegion *ar) case CTX_MODE_OBJECT: ARRAY_SET_ITEMS(contexts, ".objectmode"); break; + case CTX_MODE_GPENCIL_PAINT: + ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); + break; + case CTX_MODE_GPENCIL_SCULPT: + ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); + break; + case CTX_MODE_GPENCIL_WEIGHT: + ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); + break; } } else if (workspace->tools_space_type == SPACE_IMAGE) { /* TODO */ } + /* for grease pencil we don't use tool system yet, so we need check outside + * workspace->tools_space_type because this value is not available + */ + switch (mode) { + case CTX_MODE_GPENCIL_PAINT: + ARRAY_SET_ITEMS(contexts, ".greasepencil_paint"); + break; + case CTX_MODE_GPENCIL_SCULPT: + ARRAY_SET_ITEMS(contexts, ".greasepencil_sculpt"); + break; + case CTX_MODE_GPENCIL_WEIGHT: + ARRAY_SET_ITEMS(contexts, ".greasepencil_weight"); + break; + case CTX_MODE_GPENCIL_EDIT: + ARRAY_SET_ITEMS(contexts, ".greasepencil_edit"); + break; + } + const bool vertical = true; ED_region_panels_layout_ex(C, ar, contexts, -1, vertical); } @@ -495,6 +526,14 @@ static void buttons_area_listener( break; } break; + case NC_GPENCIL: + switch(wmn->data) { + case ND_DATA: + if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) + ED_area_tag_redraw(sa); + break; + } + break; case NC_NODE: if (wmn->action == NA_SELECTED) { ED_area_tag_redraw(sa); diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c index db5f6c2451c..6953b7cfb71 100644 --- a/source/blender/editors/space_clip/clip_buttons.c +++ b/source/blender/editors/space_clip/clip_buttons.c @@ -107,7 +107,7 @@ void uiTemplateMovieClip(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiLayoutSetContextPointer(layout, "edit_movieclip", &clipptr); if (!compact) - uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, propname, NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (clip) { uiLayout *col; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 2b98ff43c5f..725c2b7fa6d 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -236,7 +236,7 @@ static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene) sc = MEM_callocN(sizeof(SpaceClip), "initclip"); sc->spacetype = SPACE_CLIP; sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | - SC_SHOW_GRAPH_TRACKS_MOTION | SC_SHOW_GRAPH_FRAMES | SC_SHOW_GPENCIL; + SC_SHOW_GRAPH_TRACKS_MOTION | SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION; sc->zoom = 1.0f; sc->path_length = 20; sc->scopes.track_preview_height = 120; @@ -1196,7 +1196,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar) clip_draw_cache_and_notes(C, sc, ar); - if (sc->flag & SC_SHOW_GPENCIL) { + if (sc->flag & SC_SHOW_ANNOTATION) { /* Grease Pencil */ clip_draw_grease_pencil((bContext *)C, true); } @@ -1204,7 +1204,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *ar) /* reset view matrix */ UI_view2d_view_restore(C); - if (sc->flag & SC_SHOW_GPENCIL) { + if (sc->flag & SC_SHOW_ANNOTATION) { /* draw Grease Pencil - screen space only */ clip_draw_grease_pencil((bContext *)C, false); } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 1d8c6721b64..afcae7a27ab 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -876,7 +876,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char if (!compact) { uiTemplateID( layout, C, ptr, propname, - ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); } if (ima) { diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 8aa37bb5e16..fdf9d6df374 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -32,6 +32,7 @@ #include "DNA_armature_types.h" #include "DNA_curve_types.h" +#include "DNA_gpencil_types.h" #include "DNA_group_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" @@ -55,6 +56,7 @@ #include "BKE_particle.h" #include "BKE_editmesh.h" #include "BKE_object.h" +#include "BKE_gpencil.h" #include "ED_info.h" #include "ED_armature.h" @@ -72,6 +74,7 @@ typedef struct SceneStats { int totobj, totobjsel; int totlamp, totlampsel; int tottri; + int totgplayer, totgpframe, totgpstroke, totgppoint; char infostr[MAX_INFO_LEN]; } SceneStats; @@ -85,6 +88,8 @@ typedef struct SceneStatsFmt { char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN]; char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN]; char tottri[MAX_INFO_NUM_LEN]; + char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN]; + char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN]; } SceneStatsFmt; static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) @@ -144,6 +149,20 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) } break; } + case OB_GPENCIL: + { + bGPdata *gpd = (bGPdata *)ob->data; + /* GPXX Review if we can move to other place when object change + * maybe to depsgraph evaluation + */ + BKE_gpencil_stats_update(gpd); + + stats->totgplayer = gpd->totlayer; + stats->totgpframe = gpd->totframe; + stats->totgpstroke = gpd->totstroke; + stats->totgppoint = gpd->totpoint; + break; + } } } @@ -442,6 +461,11 @@ static void stats_string(ViewLayer *view_layer) SCENE_STATS_FMT_INT(tottri); + SCENE_STATS_FMT_INT(totgplayer); + SCENE_STATS_FMT_INT(totgpframe); + SCENE_STATS_FMT_INT(totgpstroke); + SCENE_STATS_FMT_INT(totgppoint); + #undef SCENE_STATS_FMT_INT @@ -501,6 +525,14 @@ static void stats_string(ViewLayer *view_layer) ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s%s"), stats_fmt.totbonesel, stats_fmt.totbone, memstr, gpumemstr); } + else if ((ob) && (ob->type == OB_GPENCIL)) { + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, + IFACE_("Layers:%s | Frames:%s | Strokes:%s | Points:%s"), + stats_fmt.totgplayer, stats_fmt.totgpframe, stats_fmt.totgpstroke, stats_fmt.totgppoint); + + ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs); + ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs); + } else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) { ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s%s"), stats_fmt.totvert, stats_fmt.tottri, gpumemstr); diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 57464cbf092..40caf919848 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -145,6 +145,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_PALETTE: { /* for these channels, we only do AnimData */ if (ale->adt && adt_ptr) { @@ -287,7 +288,7 @@ static void nla_panel_animdata(const bContext *C, Panel *pa) row = uiLayoutRow(layout, true); uiTemplateID( row, (bContext *)C, &adt_ptr, "action", - "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL); + "ACTION_OT_new", NULL, "NLA_OT_action_unlink", UI_TEMPLATE_ID_FILTER_ALL, false); /* extrapolation */ row = uiLayoutRow(layout, true); diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 3368ad4fe8d..51177a77f0d 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -182,6 +182,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channe case ANIMTYPE_DSLINESTYLE: case ANIMTYPE_DSSPK: case ANIMTYPE_DSGPENCIL: + case ANIMTYPE_PALETTE: { /* sanity checking... */ if (ale->adt) { diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index d1ad8cb396c..f284fa015b8 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -744,7 +744,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); @@ -775,7 +775,7 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID( layout, C, ptr, "image", - "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); @@ -793,7 +793,7 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID( layout, C, ptr, "image", - "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (!ima) return; @@ -1274,7 +1274,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA * uiLayoutSetContextPointer(layout, "image_user", &iuserptr); uiTemplateID( layout, C, ptr, "image", - "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (!node->id) return; imaptr = RNA_pointer_get(ptr, "image"); @@ -1304,7 +1304,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer const char *layer_name; char scene_name[MAX_ID_NAME - 2]; - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (!node->id) return; @@ -1418,7 +1418,7 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE); - uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false); col = uiLayoutColumn(layout, false); uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE); @@ -1985,7 +1985,7 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); } static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1993,7 +1993,7 @@ static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, Point bNode *node = ptr->data; PointerRNA clipptr; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (!node->id) return; @@ -2007,7 +2007,7 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (!node->id) return; @@ -2031,7 +2031,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (!node->id) return; @@ -2339,7 +2339,7 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false); uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE); @@ -2361,7 +2361,7 @@ static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, Point { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "clip", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2397,7 +2397,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN { bNode *node = ptr->data; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2437,7 +2437,7 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P bNode *node = ptr->data; NodePlaneTrackDeformData *data = node->storage; - uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); if (node->id) { MovieClip *clip = (MovieClip *) node->id; @@ -2838,7 +2838,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL); + uiTemplateID(layout, C, ptr, "image", "IMAGE_OT_new", "IMAGE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL, false); } static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 435e0018ac0..feab82a59c8 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -32,6 +32,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" #include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_lightprobe_types.h" @@ -50,6 +51,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_fcurve.h" +#include "BKE_gpencil.h" #include "BKE_global.h" #include "BKE_idcode.h" #include "BKE_layer.h" @@ -438,12 +440,16 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) } case TSE_GP_LAYER: { - bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock + bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */ bGPDlayer *gpl = te->directdata; + /* always make layer active */ + BKE_gpencil_layer_setactive(gpd, gpl); + // XXX: name needs translation stuff BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd); break; } @@ -872,39 +878,6 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon) } -static void UNUSED_FUNCTION(tselem_draw_gp_icon_uibut)(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl) -{ - /* restrict column clip - skip it for now... */ - if (arg->x >= arg->xmax) { - /* pass */ - } - else { - PointerRNA ptr; - const float eps = 0.001f; - const bool is_stroke_visible = (gpl->color[3] > eps); - const bool is_fill_visible = (gpl->fill[3] > eps); - float w = 0.5f * UI_UNIT_X; - float h = 0.85f * UI_UNIT_Y; - - RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr); - - UI_block_align_begin(arg->block); - - UI_block_emboss_set(arg->block, is_stroke_visible ? UI_EMBOSS : UI_EMBOSS_NONE); - uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h, - &ptr, "color", -1, - 0, 0, 0, 0, NULL); - - UI_block_emboss_set(arg->block, is_fill_visible ? UI_EMBOSS : UI_EMBOSS_NONE); - uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb + w, arg->yb, w, h, - &ptr, "fill_color", -1, - 0, 0, 0, 0, NULL); - - UI_block_emboss_set(arg->block, UI_EMBOSS_NONE); - UI_block_align_end(arg->block); - } -} - static void tselem_draw_icon( uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, float alpha, const bool is_clickable) @@ -969,156 +942,212 @@ static void tselem_draw_icon( case TSE_MODIFIER: { Object *ob = (Object *)tselem->id; - ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); - switch ((ModifierType)md->type) { - case eModifierType_Subsurf: - ICON_DRAW(ICON_MOD_SUBSURF); - break; - case eModifierType_Armature: - ICON_DRAW(ICON_MOD_ARMATURE); - break; - case eModifierType_Lattice: - ICON_DRAW(ICON_MOD_LATTICE); - break; - case eModifierType_Curve: - ICON_DRAW(ICON_MOD_CURVE); - break; - case eModifierType_Build: - ICON_DRAW(ICON_MOD_BUILD); - break; - case eModifierType_Mirror: - ICON_DRAW(ICON_MOD_MIRROR); - break; - case eModifierType_Decimate: - ICON_DRAW(ICON_MOD_DECIM); - break; - case eModifierType_Wave: - ICON_DRAW(ICON_MOD_WAVE); - break; - case eModifierType_Hook: - ICON_DRAW(ICON_HOOK); - break; - case eModifierType_Softbody: - ICON_DRAW(ICON_MOD_SOFT); - break; - case eModifierType_Boolean: - ICON_DRAW(ICON_MOD_BOOLEAN); - break; - case eModifierType_ParticleSystem: - ICON_DRAW(ICON_MOD_PARTICLES); - break; - case eModifierType_ParticleInstance: - ICON_DRAW(ICON_MOD_PARTICLES); - break; - case eModifierType_EdgeSplit: - ICON_DRAW(ICON_MOD_EDGESPLIT); - break; - case eModifierType_Array: - ICON_DRAW(ICON_MOD_ARRAY); - break; - case eModifierType_UVProject: - case eModifierType_UVWarp: /* TODO, get own icon */ - ICON_DRAW(ICON_MOD_UVPROJECT); - break; - case eModifierType_Displace: - ICON_DRAW(ICON_MOD_DISPLACE); - break; - case eModifierType_Shrinkwrap: - ICON_DRAW(ICON_MOD_SHRINKWRAP); - break; - case eModifierType_Cast: - ICON_DRAW(ICON_MOD_CAST); - break; - case eModifierType_MeshDeform: - case eModifierType_SurfaceDeform: - ICON_DRAW(ICON_MOD_MESHDEFORM); - break; - case eModifierType_Bevel: - ICON_DRAW(ICON_MOD_BEVEL); - break; - case eModifierType_Smooth: - case eModifierType_LaplacianSmooth: - case eModifierType_CorrectiveSmooth: - ICON_DRAW(ICON_MOD_SMOOTH); - break; - case eModifierType_SimpleDeform: - ICON_DRAW(ICON_MOD_SIMPLEDEFORM); - break; - case eModifierType_Mask: - ICON_DRAW(ICON_MOD_MASK); - break; - case eModifierType_Cloth: - ICON_DRAW(ICON_MOD_CLOTH); - break; - case eModifierType_Explode: - ICON_DRAW(ICON_MOD_EXPLODE); - break; - case eModifierType_Collision: - case eModifierType_Surface: - ICON_DRAW(ICON_MOD_PHYSICS); - break; - case eModifierType_Fluidsim: - ICON_DRAW(ICON_MOD_FLUIDSIM); - break; - case eModifierType_Multires: - ICON_DRAW(ICON_MOD_MULTIRES); - break; - case eModifierType_Smoke: - ICON_DRAW(ICON_MOD_SMOKE); - break; - case eModifierType_Solidify: - ICON_DRAW(ICON_MOD_SOLIDIFY); - break; - case eModifierType_Screw: - ICON_DRAW(ICON_MOD_SCREW); - break; - case eModifierType_Remesh: - ICON_DRAW(ICON_MOD_REMESH); - break; - case eModifierType_WeightVGEdit: - case eModifierType_WeightVGMix: - case eModifierType_WeightVGProximity: - ICON_DRAW(ICON_MOD_VERTEX_WEIGHT); - break; - case eModifierType_DynamicPaint: - ICON_DRAW(ICON_MOD_DYNAMICPAINT); - break; - case eModifierType_Ocean: - ICON_DRAW(ICON_MOD_OCEAN); - break; - case eModifierType_Warp: - ICON_DRAW(ICON_MOD_WARP); - break; - case eModifierType_Skin: - ICON_DRAW(ICON_MOD_SKIN); - break; - case eModifierType_Triangulate: - ICON_DRAW(ICON_MOD_TRIANGULATE); - break; - case eModifierType_MeshCache: - ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ - break; - case eModifierType_MeshSequenceCache: - ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ - break; - case eModifierType_Wireframe: - ICON_DRAW(ICON_MOD_WIREFRAME); - break; - case eModifierType_LaplacianDeform: - ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ - break; - case eModifierType_DataTransfer: - ICON_DRAW(ICON_MOD_DATA_TRANSFER); - break; - case eModifierType_NormalEdit: - ICON_DRAW(ICON_MOD_NORMALEDIT); - break; - /* Default */ - case eModifierType_None: - case eModifierType_ShapeKey: - case NUM_MODIFIER_TYPES: - ICON_DRAW(ICON_DOT); - break; + if (ob->type != OB_GPENCIL) { + ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); + switch ((ModifierType)md->type) { + case eModifierType_Subsurf: + ICON_DRAW(ICON_MOD_SUBSURF); + break; + case eModifierType_Armature: + ICON_DRAW(ICON_MOD_ARMATURE); + break; + case eModifierType_Lattice: + ICON_DRAW(ICON_MOD_LATTICE); + break; + case eModifierType_Curve: + ICON_DRAW(ICON_MOD_CURVE); + break; + case eModifierType_Build: + ICON_DRAW(ICON_MOD_BUILD); + break; + case eModifierType_Mirror: + ICON_DRAW(ICON_MOD_MIRROR); + break; + case eModifierType_Decimate: + ICON_DRAW(ICON_MOD_DECIM); + break; + case eModifierType_Wave: + ICON_DRAW(ICON_MOD_WAVE); + break; + case eModifierType_Hook: + ICON_DRAW(ICON_HOOK); + break; + case eModifierType_Softbody: + ICON_DRAW(ICON_MOD_SOFT); + break; + case eModifierType_Boolean: + ICON_DRAW(ICON_MOD_BOOLEAN); + break; + case eModifierType_ParticleSystem: + ICON_DRAW(ICON_MOD_PARTICLES); + break; + case eModifierType_ParticleInstance: + ICON_DRAW(ICON_MOD_PARTICLES); + break; + case eModifierType_EdgeSplit: + ICON_DRAW(ICON_MOD_EDGESPLIT); + break; + case eModifierType_Array: + ICON_DRAW(ICON_MOD_ARRAY); + break; + case eModifierType_UVProject: + case eModifierType_UVWarp: /* TODO, get own icon */ + ICON_DRAW(ICON_MOD_UVPROJECT); + break; + case eModifierType_Displace: + ICON_DRAW(ICON_MOD_DISPLACE); + break; + case eModifierType_Shrinkwrap: + ICON_DRAW(ICON_MOD_SHRINKWRAP); + break; + case eModifierType_Cast: + ICON_DRAW(ICON_MOD_CAST); + break; + case eModifierType_MeshDeform: + case eModifierType_SurfaceDeform: + ICON_DRAW(ICON_MOD_MESHDEFORM); + break; + case eModifierType_Bevel: + ICON_DRAW(ICON_MOD_BEVEL); + break; + case eModifierType_Smooth: + case eModifierType_LaplacianSmooth: + case eModifierType_CorrectiveSmooth: + ICON_DRAW(ICON_MOD_SMOOTH); + break; + case eModifierType_SimpleDeform: + ICON_DRAW(ICON_MOD_SIMPLEDEFORM); + break; + case eModifierType_Mask: + ICON_DRAW(ICON_MOD_MASK); + break; + case eModifierType_Cloth: + ICON_DRAW(ICON_MOD_CLOTH); + break; + case eModifierType_Explode: + ICON_DRAW(ICON_MOD_EXPLODE); + break; + case eModifierType_Collision: + case eModifierType_Surface: + ICON_DRAW(ICON_MOD_PHYSICS); + break; + case eModifierType_Fluidsim: + ICON_DRAW(ICON_MOD_FLUIDSIM); + break; + case eModifierType_Multires: + ICON_DRAW(ICON_MOD_MULTIRES); + break; + case eModifierType_Smoke: + ICON_DRAW(ICON_MOD_SMOKE); + break; + case eModifierType_Solidify: + ICON_DRAW(ICON_MOD_SOLIDIFY); + break; + case eModifierType_Screw: + ICON_DRAW(ICON_MOD_SCREW); + break; + case eModifierType_Remesh: + ICON_DRAW(ICON_MOD_REMESH); + break; + case eModifierType_WeightVGEdit: + case eModifierType_WeightVGMix: + case eModifierType_WeightVGProximity: + ICON_DRAW(ICON_MOD_VERTEX_WEIGHT); + break; + case eModifierType_DynamicPaint: + ICON_DRAW(ICON_MOD_DYNAMICPAINT); + break; + case eModifierType_Ocean: + ICON_DRAW(ICON_MOD_OCEAN); + break; + case eModifierType_Warp: + ICON_DRAW(ICON_MOD_WARP); + break; + case eModifierType_Skin: + ICON_DRAW(ICON_MOD_SKIN); + break; + case eModifierType_Triangulate: + ICON_DRAW(ICON_MOD_TRIANGULATE); + break; + case eModifierType_MeshCache: + ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + break; + case eModifierType_MeshSequenceCache: + ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + break; + case eModifierType_Wireframe: + ICON_DRAW(ICON_MOD_WIREFRAME); + break; + case eModifierType_LaplacianDeform: + ICON_DRAW(ICON_MOD_MESHDEFORM); /* XXX, needs own icon */ + break; + case eModifierType_DataTransfer: + ICON_DRAW(ICON_MOD_DATA_TRANSFER); + break; + case eModifierType_NormalEdit: + ICON_DRAW(ICON_MOD_NORMALEDIT); + break; + /* Default */ + case eModifierType_None: + case eModifierType_ShapeKey: + + case NUM_MODIFIER_TYPES: + ICON_DRAW(ICON_DOT); + break; + } + } + else { + /* grease pencil modifiers */ + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr); + switch ((GpencilModifierType)md->type) { + case eGpencilModifierType_Noise: + ICON_DRAW(ICON_RNDCURVE); + break; + case eGpencilModifierType_Subdiv: + ICON_DRAW(ICON_MOD_SUBSURF); + break; + case eGpencilModifierType_Thick: + ICON_DRAW(ICON_MAN_ROT); + break; + case eGpencilModifierType_Tint: + ICON_DRAW(ICON_COLOR); + break; + case eGpencilModifierType_Instance: + ICON_DRAW(ICON_MOD_ARRAY); + break; + case eGpencilModifierType_Build: + ICON_DRAW(ICON_MOD_BUILD); + break; + case eGpencilModifierType_Opacity: + ICON_DRAW(ICON_MOD_MASK); + break; + case eGpencilModifierType_Color: + ICON_DRAW(ICON_GROUP_VCOL); + break; + case eGpencilModifierType_Lattice: + ICON_DRAW(ICON_MOD_LATTICE); + break; + case eGpencilModifierType_Mirror: + ICON_DRAW(ICON_MOD_MIRROR); + break; + case eGpencilModifierType_Simplify: + ICON_DRAW(ICON_MOD_DECIM); + break; + case eGpencilModifierType_Smooth: + ICON_DRAW(ICON_MOD_SMOOTH); + break; + case eGpencilModifierType_Hook: + ICON_DRAW(ICON_HOOK); + break; + case eGpencilModifierType_Offset: + ICON_DRAW(ICON_MOD_DISPLACE); + break; + + /* Default */ + default: + ICON_DRAW(ICON_DOT); + break; + } } break; } @@ -1185,11 +1214,18 @@ static void tselem_draw_icon( ICON_DRAW(ICON_GROUP); break; /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ -#if 0 case TSE_GP_LAYER: - tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata); + { + /* indicate whether layer is active */ + bGPDlayer *gpl = te->directdata; + if (gpl->flag & GP_LAYER_ACTIVE) { + ICON_DRAW(ICON_GREASEPENCIL); + } + else { + ICON_DRAW(ICON_DOT); + } break; -#endif + } default: ICON_DRAW(ICON_DOT); break; @@ -1229,6 +1265,9 @@ static void tselem_draw_icon( ICON_CLICK_DRAW(ICON_OUTLINER_OB_EMPTY); } break; + case OB_GPENCIL: + ICON_CLICK_DRAW(ICON_OUTLINER_OB_GREASEPENCIL); break; + break; } } else { @@ -1304,7 +1343,7 @@ static void tselem_draw_icon( case ID_LS: tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; case ID_GD: - tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_GREASEPENCIL); break; case ID_LP: { LightProbe * lp = (LightProbe *)tselem->id; diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 7ab13f36953..ec5e11520a6 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -39,6 +39,7 @@ #include "DNA_scene_types.h" #include "DNA_sequence_types.h" #include "DNA_world_types.h" +#include "DNA_gpencil_types.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" @@ -46,9 +47,11 @@ #include "BKE_armature.h" #include "BKE_collection.h" #include "BKE_context.h" +#include "BKE_gpencil.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_object.h" +#include "BKE_paint.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_workspace.h" @@ -60,6 +63,7 @@ #include "ED_screen.h" #include "ED_sequencer.h" #include "ED_undo.h" +#include "ED_gpencil.h" #include "WM_api.h" #include "WM_types.h" @@ -470,6 +474,28 @@ static eOLDrawState tree_element_active_defgroup( return OL_DRAWSEL_NONE; } +static eOLDrawState UNUSED_FUNCTION(tree_element_active_gplayer)( + bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) +{ + bGPdata *gpd = (bGPdata *)tselem->id; + bGPDlayer *gpl = te->directdata; + + /* We can only have a single "active" layer at a time + * and there must always be an active layer... + */ + if (set != OL_SETSEL_NONE) { + if (gpl) { + BKE_gpencil_layer_setactive(gpd, gpl); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd); + } + } + else { + return OL_DRAWSEL_NORMAL; + } + + return OL_DRAWSEL_NONE; +} + static eOLDrawState tree_element_active_posegroup( bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) { @@ -1006,6 +1032,10 @@ static void do_outliner_item_activate_tree_element( } } } + else if (ELEM(te->idcode, ID_GD)) { + /* set grease pencil to object mode */ + WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } else { // rest of types tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false); } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 28890e42139..539df3aa085 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -319,8 +319,6 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s if (outliner_animdata_test(sce->adt)) outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); - /* Grease Pencil */ - outliner_add_element(soops, lb, sce->gpd, te, 0, 0); } TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index e45159124e8..6113922c02e 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -168,6 +168,10 @@ static void topbar_main_region_listener(wmWindow *UNUSED(win), ScrArea *UNUSED(s if (wmn->data == ND_SPACE_VIEW3D) ED_region_tag_redraw(ar); break; + case NC_GPENCIL: + if (wmn->data == ND_DATA) + ED_region_tag_redraw(ar); + break; } } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c0abbe636c3..3649c6f6dbb 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -80,6 +80,7 @@ #include "BKE_subsurf.h" #include "BKE_unit.h" #include "BKE_tracking.h" +#include "BKE_gpencil.h" #include "BKE_editmesh.h" diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 2577077002e..c1776ef18e7 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -36,6 +36,7 @@ #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_gpencil_types.h" #include "MEM_guardedalloc.h" @@ -335,12 +336,18 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene) v3d->gridflag = V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_FLOOR; v3d->flag = V3D_SELECT_OUTLINE; - v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_GPENCIL; + v3d->flag2 = V3D_SHOW_RECONSTRUCTION | V3D_SHOW_ANNOTATION; v3d->lens = 50.0f; v3d->near = 0.01f; v3d->far = 1000.0f; + v3d->overlay.gpencil_grid_scale = 1.0; // Scales + v3d->overlay.gpencil_grid_lines = GP_DEFAULT_GRID_LINES; // NUmber of Lines + v3d->overlay.gpencil_paper_opacity = 0.5f; + v3d->overlay.gpencil_grid_axis = V3D_GP_GRID_AXIS_Y; + v3d->overlay.gpencil_grid_opacity = 0.9f; + v3d->bundle_size = 0.2f; v3d->bundle_drawtype = OB_PLAINAXES; @@ -350,6 +357,10 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene) v3d->stereo3d_convergence_alpha = 0.15f; v3d->stereo3d_volume_alpha = 0.05f; + /* grease pencil settings */ + v3d->vertex_opacity = 1.0f; + v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES; + /* header */ ar = MEM_callocN(sizeof(ARegion), "header for view3d"); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 941f9262694..0157bc567ca 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1593,7 +1593,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( v3d.flag2 = V3D_RENDER_OVERRIDE; if (draw_flags & V3D_OFSDRAW_USE_GPENCIL) { - v3d.flag2 |= V3D_SHOW_GPENCIL; + v3d.flag2 |= V3D_SHOW_ANNOTATION; } if (draw_flags & V3D_OFSDRAW_USE_SOLID_TEX) { v3d.flag2 |= V3D_SOLID_TEX; diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index 94cd4dfc73d..45e4c4b4676 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -881,7 +881,7 @@ void ED_view3d_draw_depth_gpencil( GPU_depth_test(true); - if (v3d->flag2 & V3D_SHOW_GPENCIL) { + if (v3d->flag2 & V3D_SHOW_ANNOTATION) { ED_gpencil_draw_view3d(NULL, scene, view_layer, depsgraph, v3d, ar, true); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index e94d3a13225..468b33ea9a6 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -52,6 +52,7 @@ #include "BKE_camera.h" #include "BKE_context.h" #include "BKE_font.h" +#include "BKE_gpencil.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_main.h" @@ -77,7 +78,6 @@ #include "ED_screen.h" #include "ED_transform.h" #include "ED_mesh.h" -#include "ED_gpencil.h" #include "ED_view3d.h" #include "ED_transform_snap_object_context.h" @@ -2811,7 +2811,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) Depsgraph *depsgraph = CTX_data_depsgraph(C); ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph); bGPdata *gpd = CTX_data_gpencil_data(C); - const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); + const bool is_gp_edit = GPENCIL_ANY_MODE(gpd); const bool is_face_map = ((is_gp_edit == false) && ar->gizmo_map && WM_gizmomap_is_any_selected(ar->gizmo_map)); Object *ob_eval = OBACT(view_layer_eval); @@ -2850,9 +2850,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) { /* we're only interested in selected points here... */ if ((gps->flag & GP_STROKE_SELECT) && (gps->flag & GP_STROKE_3DSPACE)) { - if (ED_gpencil_stroke_minmax(gps, true, min, max)) { - ok = true; - } + ok |= BKE_gpencil_stroke_minmax(gps, true, min, max); } } CTX_DATA_END; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index c716692eb9b..d5ef7cdf441 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -36,13 +36,17 @@ #include "BKE_object.h" #include "BKE_unit.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_gpencil_types.h" #include "DNA_view3d_types.h" #include "BIF_gl.h" +#include "ED_gpencil.h" #include "ED_screen.h" #include "ED_transform_snap_object_context.h" #include "ED_view3d.h" @@ -385,37 +389,28 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) // RulerInfo *ruler_info = gzgroup->customdata; Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + + bGPdata *gpd; bGPDlayer *gpl; bGPDframe *gpf; bGPDstroke *gps; - bGPDpalette *palette; - bGPDpalettecolor *palcolor; RulerItem *ruler_item; const char *ruler_name = RULER_ID; bool changed = false; if (scene->gpd == NULL) { - scene->gpd = BKE_gpencil_data_addnew(bmain, "GPencil"); + scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations"); } + gpd = scene->gpd; - gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info)); if (gpl == NULL) { - gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false); + gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false); + copy_v4_v4(gpl->color, U.gpencil_new_layer_col); gpl->thickness = 1; gpl->flag |= GP_LAYER_HIDE; } - /* try to get active palette or create a new one */ - palette = BKE_gpencil_palette_getactive(scene->gpd); - if (palette == NULL) { - palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true); - } - /* try to get color with the ruler name or create a new one */ - palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name); - if (palcolor == NULL) { - palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true); - } - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); BKE_gpencil_free_strokes(gpf); @@ -428,6 +423,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) if (ruler_item->flag & RULERITEM_USE_ANGLE) { gps->totpoints = 3; pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); for (j = 0; j < 3; j++) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -438,6 +434,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) else { gps->totpoints = 2; pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); for (j = 0; j < 3; j += 2) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -447,9 +444,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) } gps->flag = GP_STROKE_3DSPACE; gps->thickness = 3; - /* assign color to stroke */ - BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); - gps->palcolor = palcolor; + BLI_addtail(&gpf->strokes, gps); changed = true; } diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 690fc5e3bdb..0475159712b 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -26,9 +26,11 @@ /* defines VIEW3D_OT_ruler modal operator */ +#include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_gpencil_types.h" +#include "DNA_brush_types.h" #include "MEM_guardedalloc.h" @@ -40,6 +42,7 @@ #include "BKE_context.h" #include "BKE_gpencil.h" #include "BKE_main.h" +#include "BKE_material.h" #include "BKE_unit.h" #include "BIF_gl.h" @@ -51,6 +54,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_gpencil.h" #include "ED_screen.h" #include "ED_view3d.h" #include "ED_transform_snap_object_context.h" @@ -300,37 +304,28 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + bGPDlayer *gpl; bGPDframe *gpf; bGPDstroke *gps; - bGPDpalette *palette; - bGPDpalettecolor *palcolor; RulerItem *ruler_item; const char *ruler_name = RULER_ID; bool changed = false; + /* FIXME: This needs to be reviewed. Should it keep being done like this? */ if (scene->gpd == NULL) { - scene->gpd = BKE_gpencil_data_addnew(bmain, "GPencil"); + scene->gpd = BKE_gpencil_data_addnew(bmain, "Annotations"); } + bGPdata *gpd = scene->gpd; - gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info)); + gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info)); if (gpl == NULL) { - gpl = BKE_gpencil_layer_addnew(scene->gpd, ruler_name, false); + gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false); + copy_v4_v4(gpl->color, U.gpencil_new_layer_col); gpl->thickness = 1; gpl->flag |= GP_LAYER_HIDE; } - /* try to get active palette or create a new one */ - palette = BKE_gpencil_palette_getactive(scene->gpd); - if (palette == NULL) { - palette = BKE_gpencil_palette_addnew(scene->gpd, DATA_("GP_Palette"), true); - } - /* try to get color with the ruler name or create a new one */ - palcolor = BKE_gpencil_palettecolor_getbyname(palette, (char *)ruler_name); - if (palcolor == NULL) { - palcolor = BKE_gpencil_palettecolor_addnew(palette, (char *)ruler_name, true); - } - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true); BKE_gpencil_free_strokes(gpf); @@ -343,6 +338,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) if (ruler_item->flag & RULERITEM_USE_ANGLE) { gps->totpoints = 3; pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); for (j = 0; j < 3; j++) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -353,6 +349,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) else { gps->totpoints = 2; pt = gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); + gps->dvert = MEM_callocN(sizeof(MDeformVert) * gps->totpoints, "gp_stroke_weights"); for (j = 0; j < 3; j += 2) { copy_v3_v3(&pt->x, ruler_item->co[j]); pt->pressure = 1.0f; @@ -362,9 +359,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) } gps->flag = GP_STROKE_3DSPACE; gps->thickness = 3; - /* assign color to stroke */ - BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname)); - gps->palcolor = palcolor; + BLI_addtail(&gpf->strokes, gps); changed = true; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 7da69c5b2d5..afff5eb7f66 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -44,6 +44,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_tracking_types.h" +#include "DNA_gpencil_types.h" #include "MEM_guardedalloc.h" @@ -76,6 +77,7 @@ #include "BKE_editmesh.h" #include "BKE_scene.h" #include "BKE_tracking.h" +#include "BKE_workspace.h" #include "DEG_depsgraph.h" @@ -95,6 +97,7 @@ #include "ED_screen.h" #include "ED_sculpt.h" #include "ED_mball.h" +#include "ED_gpencil.h" #include "UI_interface.h" @@ -1675,6 +1678,27 @@ static bool ed_object_select_pick( if ((oldbasact != basact) && (is_obedit == false)) { ED_object_base_activate(C, basact); /* adds notifier */ } + + /* Set special modes for grease pencil + The grease pencil modes are not real modes, but a hack to make the interface + consistent, so need some tricks to keep UI synchronized */ + // XXX: This stuff neeeds reviewing (Aligorith) +#if 0 + if (((oldbasact) && oldbasact->object->type == OB_GPENCIL) || (basact->object->type == OB_GPENCIL)) { + /* set cursor */ + if (ELEM(basact->object->mode == OB_MODE_GPENCIL_PAINT, + OB_MODE_GPENCIL_SCULPT, + OB_MODE_GPENCIL_WEIGHT)) { + ED_gpencil_toggle_brush_cursor(C, true, NULL); + } + else { + /* TODO: maybe is better use restore */ + ED_gpencil_toggle_brush_cursor(C, false, NULL); + } + /* set workspace mode */ + BKE_workspace_object_mode_set(CTX_wm_workspace(C), scene, basact->object->mode); + } +#endif } DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 07ef6b9a819..9ad80f2ab12 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -44,6 +44,7 @@ #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" /* PET modes */ #include "DNA_workspace_types.h" +#include "DNA_gpencil_types.h" #include "BLI_alloca.h" #include "BLI_utildefines.h" @@ -85,6 +86,7 @@ #include "ED_mesh.h" #include "ED_clip.h" #include "ED_node.h" +#include "ED_gpencil.h" #include "WM_types.h" #include "WM_api.h" @@ -101,6 +103,8 @@ #include "transform.h" +#include "DEG_depsgraph.h" + /* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */ // #define USE_NUM_NO_ZERO @@ -571,6 +575,10 @@ void removeAspectRatio(TransInfo *t, float vec[2]) static void viewRedrawForce(const bContext *C, TransInfo *t) { if (t->options & CTX_GPENCIL_STROKES) { + bGPdata *gpd = ED_gpencil_data_get_active(C); + if (gpd) { + DEG_id_tag_update(&gpd->id, OB_RECALC_DATA); + } WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } else if (t->spacetype == SPACE_VIEW3D) { @@ -1800,7 +1808,23 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) (float)t->mval[1], }; + +#if 0 /* XXX: Fix from 1c9690e7607bc990cc4a3e6ba839949bb83a78af cannot be used anymore */ + if ((t->flag & T_POINTS) && (t->options & CTX_GPENCIL_STROKES)) { + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + Object *ob = tc->obedit; + float vecrot[3]; + copy_v3_v3(vecrot, t->center); + mul_m4_v3(ob->obmat, vecrot); + projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO); + } + } + else { + projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO); + } +#else projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO); +#endif /* Offset the values for the area region. */ const float offset[2] = { @@ -3551,7 +3575,25 @@ static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, f else sub_v3_v3(vec, td->center); - mul_v3_fl(vec, td->factor); + /* grease pencil falloff */ + if (t->options & CTX_GPENCIL_STROKES) { + bGPDstroke *gps = (bGPDstroke *)td->extra; + mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff); + + /* scale stroke thickness */ + if (td->val) { + snapGridIncrement(t, t->values); + applyNumInput(&t->num, t->values); + + float ratio = t->values[0]; + *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff; + CLAMP_MIN(*td->val, 0.001f); + } + + } + else { + mul_v3_fl(vec, td->factor); + } if (t->flag & (T_OBJECT | T_POSE)) { mul_m3_v3(td->smtx, vec); @@ -3905,6 +3947,20 @@ static void ElementRotation_ex(TransInfo *t, TransDataContainer *tc, TransData * mul_m3_m3m3(totmat, mat, td->mtx); mul_m3_m3m3(smat, td->smtx, totmat); + /* apply gpencil falloff */ + if (t->options & CTX_GPENCIL_STROKES) { + bGPDstroke *gps = (bGPDstroke *)td->extra; + float sx = smat[0][0]; + float sy = smat[1][1]; + float sz = smat[2][2]; + + mul_m3_fl(smat, gps->runtime.multi_frame_falloff); + /* fix scale */ + smat[0][0] = sx; + smat[1][1] = sy; + smat[2][2] = sz; + } + sub_v3_v3v3(vec, td->iloc, center); mul_m3_v3(smat, vec); @@ -4578,7 +4634,16 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) } mul_m3_v3(td->smtx, tvec); - mul_v3_fl(tvec, td->factor); + + if (t->options & CTX_GPENCIL_STROKES) { + /* grease pencil multiframe falloff */ + bGPDstroke *gps = (bGPDstroke *)td->extra; + mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); + } + else { + /* proportional editing falloff */ + mul_v3_fl(tvec, td->factor); + } protectedTransBits(td->protectflag, tvec); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 675441189b0..d3b7417c4dd 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -90,6 +90,7 @@ #include "BKE_editmesh.h" #include "BKE_tracking.h" #include "BKE_mask.h" +#include "BKE_colortools.h" #include "BIK_api.h" @@ -3609,6 +3610,8 @@ static void posttrans_gpd_clean(bGPdata *gpd) } #endif } + /* set cache flag to dirty */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); } static void posttrans_mask_clean(Mask *mask) @@ -8086,7 +8089,14 @@ void flushTransPaintCurve(TransInfo *t) static void createTransGPencil(bContext *C, TransInfo *t) { + Depsgraph *depsgraph = CTX_data_depsgraph(C); \ bGPdata *gpd = ED_gpencil_data_get_active(C); + ToolSettings *ts = CTX_data_tool_settings(C); + + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_FRAME_FALLOFF) != 0; + + Object *obact = CTX_data_active_object(C); bGPDlayer *gpl; TransData *td = NULL; float mtx[3][3], smtx[3][3]; @@ -8110,50 +8120,67 @@ static void createTransGPencil(bContext *C, TransInfo *t) if (gpd == NULL) return; + /* initialize falloff curve */ + if (is_multiedit) { + curvemapping_initialize(ts->gp_sculpt.cur_falloff); + } + /* First Pass: Count the number of datapoints required for the strokes, * (and additional info about the configuration - e.g. 2D/3D?) */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { - bGPDframe *gpf = gpl->actframe; + bGPDframe *gpf; bGPDstroke *gps; + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; + } - for (gps = gpf->strokes.first; gps; gps = gps->next) { - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { - continue; - } + for (gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { + continue; + } - if (is_prop_edit) { - /* Proportional Editing... */ - if (is_prop_edit_connected) { - /* connected only - so only if selected */ - if (gps->flag & GP_STROKE_SELECT) - tc->data_len += gps->totpoints; - } - else { - /* everything goes - connection status doesn't matter */ - tc->data_len += gps->totpoints; - } - } - else { - /* only selected stroke points are considered */ - if (gps->flag & GP_STROKE_SELECT) { - bGPDspoint *pt; - int i; - - // TODO: 2D vs 3D? - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->flag & GP_SPOINT_SELECT) - tc->data_len++; + if (is_prop_edit) { + /* Proportional Editing... */ + if (is_prop_edit_connected) { + /* connected only - so only if selected */ + if (gps->flag & GP_STROKE_SELECT) + tc->data_len += gps->totpoints; + } + else { + /* everything goes - connection status doesn't matter */ + tc->data_len += gps->totpoints; + } + } + else { + /* only selected stroke points are considered */ + if (gps->flag & GP_STROKE_SELECT) { + bGPDspoint *pt; + int i; + + // TODO: 2D vs 3D? + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + if (pt->flag & GP_SPOINT_SELECT) + tc->data_len++; + } + } } } } + /* if not multiedit out of loop */ + if (!is_multiedit) { + break; + } } } } @@ -8180,153 +8207,166 @@ static void createTransGPencil(bContext *C, TransInfo *t) float diff_mat[4][4]; float inverse_diff_mat[4][4]; - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - /* undo matrix */ - invert_m4_m4(inverse_diff_mat, diff_mat); + bGPDframe *init_gpf = gpl->actframe; + if (is_multiedit) { + init_gpf = gpl->frames.first; } + /* init multiframe falloff options */ + int f_init = 0; + int f_end = 0; + + if (use_multiframe_falloff) { + BKE_gpencil_get_range_selected(gpl, &f_init, &f_end); + } + + /* calculate difference matrix */ + ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + /* undo matrix */ + invert_m4_m4(inverse_diff_mat, diff_mat); /* Make a new frame to work on if the layer's frame and the current scene frame don't match up * - This is useful when animating as it saves that "uh-oh" moment when you realize you've * spent too much time editing the wrong frame... */ - if (gpf->framenum != cfra) { + // XXX: should this be allowed when framelock is enabled? + if ((gpf->framenum != cfra) && (!is_multiedit)) { gpf = BKE_gpencil_frame_addcopy(gpl, cfra); /* in some weird situations (framelock enabled) return NULL */ if (gpf == NULL) { continue; } + if (!is_multiedit) { + init_gpf = gpf; + } } /* Loop over strokes, adding TransData for points as needed... */ - for (gps = gpf->strokes.first; gps; gps = gps->next) { - TransData *head = td; - TransData *tail = td; - bool stroke_ok; - - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps) == false) { - continue; - } - /* What we need to include depends on proportional editing settings... */ - if (is_prop_edit) { - if (is_prop_edit_connected) { - /* A) "Connected" - Only those in selected strokes */ - stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; - } - else { - /* B) All points, always */ - stroke_ok = true; - } - } - else { - /* C) Only selected points in selected strokes */ - stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; - } - - /* Do stroke... */ - if (stroke_ok && gps->totpoints) { - bGPDspoint *pt; - int i; - -#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or is_prop_edit breaks */ - const float ninv = 1.0f / gps->totpoints; - float center[3] = {0.0f}; - - /* compute midpoint of stroke */ - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - madd_v3_v3v3fl(center, center, &pt->x, ninv); + for (gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { + + /* if multiframe and falloff, recalculate and save value */ + float falloff = 1.0f; /* by default no falloff */ + if ((is_multiedit) && (use_multiframe_falloff)) { + /* Faloff depends on distance to active frame (relative to the overall frame range) */ + falloff = BKE_gpencil_multiframe_falloff_calc(gpf, gpl->actframe->framenum, + f_init, f_end, ts->gp_sculpt.cur_falloff); } -#endif - /* add all necessary points... */ - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - bool point_ok; + for (gps = gpf->strokes.first; gps; gps = gps->next) { + TransData *head = td; + TransData *tail = td; + bool stroke_ok; - /* include point? */ + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) { + continue; + } + /* What we need to include depends on proportional editing settings... */ if (is_prop_edit) { - /* Always all points in strokes that get included */ - point_ok = true; + if (is_prop_edit_connected) { + /* A) "Connected" - Only those in selected strokes */ + stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; + } + else { + /* B) All points, always */ + stroke_ok = true; + } } else { - /* Only selected points in selected strokes */ - point_ok = (pt->flag & GP_SPOINT_SELECT) != 0; + /* C) Only selected points in selected strokes */ + stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0; } - /* do point... */ - if (point_ok) { - copy_v3_v3(td->iloc, &pt->x); - copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local? - - td->loc = &pt->x; - - td->flag = 0; + /* Do stroke... */ + if (stroke_ok && gps->totpoints) { + bGPDspoint *pt; + int i; - if (pt->flag & GP_SPOINT_SELECT) - td->flag |= TD_SELECTED; - - /* for other transform modes (e.g. shrink-fatten), need to additional data */ - if (t->mode == TFM_GPENCIL_SHRINKFATTEN) { - td->val = &pt->pressure; - td->ival = pt->pressure; - } + /* save falloff factor */ + gps->runtime.multi_frame_falloff = falloff; - /* screenspace needs special matrices... */ - if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) { - /* screenspace */ - td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; + /* add all necessary points... */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + bool point_ok; - /* apply parent transformations */ - if (gpl->parent == NULL) { - copy_m3_m4(td->smtx, t->persmat); - copy_m3_m4(td->mtx, t->persinv); - unit_m3(td->axismtx); + /* include point? */ + if (is_prop_edit) { + /* Always all points in strokes that get included */ + point_ok = true; } else { - /* apply matrix transformation relative to parent */ - copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ - copy_m3_m4(td->mtx, diff_mat); /* display position */ - copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ - } - } - else { - /* configure 2D dataspace points so that they don't play up... */ - if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) { - td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; - // XXX: matrices may need to be different? + /* Only selected points in selected strokes */ + point_ok = (pt->flag & GP_SPOINT_SELECT) != 0; } - /* apply parent transformations */ - if (gpl->parent == NULL) { - copy_m3_m3(td->smtx, smtx); - copy_m3_m3(td->mtx, mtx); - unit_m3(td->axismtx); // XXX? - } - else { - /* apply matrix transformation relative to parent */ - copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ - copy_m3_m4(td->mtx, diff_mat); /* display position */ - copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ + /* do point... */ + if (point_ok) { + copy_v3_v3(td->iloc, &pt->x); + copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local? + + td->loc = &pt->x; + + td->flag = 0; + + if (pt->flag & GP_SPOINT_SELECT) + td->flag |= TD_SELECTED; + + /* for other transform modes (e.g. shrink-fatten), need to additional data + * but never for scale or mirror + */ + if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) { + td->val = &pt->pressure; + td->ival = pt->pressure; + } + + /* screenspace needs special matrices... */ + if ((gps->flag & (GP_STROKE_3DSPACE | GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) == 0) { + /* screenspace */ + td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; + + /* apply matrix transformation relative to parent */ + copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ + copy_m3_m4(td->mtx, diff_mat); /* display position */ + copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ + } + else { + /* configure 2D dataspace points so that they don't play up... */ + if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) { + td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ; + // XXX: matrices may need to be different? + } + + /* apply parent transformations */ + copy_m3_m4(td->smtx, inverse_diff_mat); /* final position */ + copy_m3_m4(td->mtx, diff_mat); /* display position */ + copy_m3_m4(td->axismtx, diff_mat); /* axis orientation */ + } + /* Triangulation must be calculated again, so save the stroke for recalc function */ + td->extra = gps; + + /* save pointer to object */ + td->ob = obact; + + td++; + tail++; } } - /* Triangulation must be calculated again, so save the stroke for recalc function */ - td->extra = gps; - td++; - tail++; + /* March over these points, and calculate the proportional editing distances */ + if (is_prop_edit && (head != tail)) { + /* XXX: for now, we are similar enough that this works... */ + calc_distanceCurveVerts(head, tail - 1); + } } } - - /* March over these points, and calculate the proportional editing distances */ - if (is_prop_edit && (head != tail)) { - /* XXX: for now, we are similar enough that this works... */ - calc_distanceCurveVerts(head, tail - 1); - } + } + /* if not multiedit out of loop */ + if (!is_multiedit) { + break; } } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 3618d57b3ed..a2377166dff 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -74,6 +74,7 @@ #include "BKE_armature.h" #include "BKE_curve.h" #include "BKE_fcurve.h" +#include "BKE_gpencil.h" #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_main.h" @@ -105,6 +106,7 @@ #include "ED_curve.h" /* for curve_editnurbs */ #include "ED_clip.h" #include "ED_screen.h" +#include "ED_gpencil.h" #include "WM_types.h" #include "WM_api.h" @@ -379,7 +381,8 @@ static void recalcData_actedit(TransInfo *t) /* flush transform values back to actual coordinates */ flushTransIntFrameActionData(t); } - else { + + if (ac.datatype != ANIMCONT_MASK) { /* get animdata blocks visible in editor, assuming that these will be the ones where things changed */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA); ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); @@ -1311,7 +1314,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* GPencil editing context */ - if ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) { + if (GPENCIL_ANY_MODE(gpd)) { t->options |= CTX_GPENCIL_STROKES; } @@ -1823,6 +1826,21 @@ void calculateCenterCursor(TransInfo *t, float r_center[3]) } r_center[2] = 0.0f; } + else if (t->options & CTX_GPENCIL_STROKES) { + /* move cursor in local space */ + TransData *td = NULL; + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + float mat[3][3], imat[3][3]; + + td = tc->data; + Object *ob = td->ob; + + sub_v3_v3v3(r_center, r_center, ob->obmat[3]); + copy_m3_m4(mat, ob->obmat); + invert_m3_m3(imat, mat); + mul_m3_v3(imat, r_center); + } + } } void calculateCenterCursor2D(TransInfo *t, float r_center[2]) diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index cbc2b312512..3b5d7d5871a 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -604,6 +604,7 @@ int ED_transform_calc_gizmo_stats( ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); ViewLayer *view_layer = CTX_data_view_layer(C); Object *obedit = CTX_data_edit_object(C); View3D *v3d = sa->spacedata.first; @@ -611,7 +612,7 @@ int ED_transform_calc_gizmo_stats( Base *base; Object *ob = OBACT(view_layer); bGPdata *gpd = CTX_data_gpencil_data(C); - const bool is_gp_edit = ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); + const bool is_gp_edit = GPENCIL_ANY_MODE(gpd); int a, totsel = 0; const int pivot_point = scene->toolsettings->transform_pivot_point; @@ -728,10 +729,8 @@ int ED_transform_calc_gizmo_stats( /* only editable and visible layers are considered */ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { - /* calculate difference matrix if parent object */ - if (gpl->parent != NULL) { - ED_gpencil_parent_location(gpl, diff_mat); - } + /* calculate difference matrix */ + ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat); for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) { /* skip strokes that are invalid for current view */ diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index a6e857c4a60..bc35e6e6b89 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -2280,7 +2280,12 @@ static short snapObject( dist_px, r_loc, r_no, r_index); break; - + case OB_GPENCIL: + retval = snapEmpty( + snapdata, ob, obmat, + dist_px, + r_loc, r_no, r_index); + break; case OB_CAMERA: retval = snapCamera( sctx, snapdata, ob, obmat, diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 14592149579..7c1dc148dde 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -51,9 +51,12 @@ #include "BKE_screen.h" #include "BKE_layer.h" #include "BKE_undo_system.h" +#include "BKE_workspace.h" +#include "BKE_paint.h" #include "ED_gpencil.h" #include "ED_render.h" +#include "ED_object.h" #include "ED_screen.h" #include "ED_undo.h" @@ -110,6 +113,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); + ScrArea *sa = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ @@ -122,6 +126,12 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } + if (sa && (sa->spacetype == SPACE_VIEW3D)) { + Object *obact = CTX_data_active_object(C); + if (obact && (obact->type == OB_GPENCIL)) { + ED_gpencil_toggle_brush_cursor(C, false, NULL); + } + } UndoStep *step_data_from_name = NULL; int step_for_callback = step; @@ -156,6 +166,23 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) else { BKE_undosys_step_undo_compat_only(wm->undo_stack, C, step); } + + /* Set special modes for grease pencil */ + if (sa && (sa->spacetype == SPACE_VIEW3D)) { + Object *obact = CTX_data_active_object(C); + if (obact && (obact->type == OB_GPENCIL)) { + /* set cursor */ + if (ELEM(obact->mode, OB_MODE_GPENCIL_PAINT, OB_MODE_GPENCIL_SCULPT, OB_MODE_GPENCIL_WEIGHT)) { + ED_gpencil_toggle_brush_cursor(C, true, NULL); + } + else { + ED_gpencil_toggle_brush_cursor(C, false, NULL); + } + /* set workspace mode */ + Base *basact = CTX_data_active_base(C); + ED_object_base_activate(C, basact); + } + } } /* App-Handlers (post). */ diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt new file mode 100644 index 00000000000..5ad91d4e01b --- /dev/null +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -0,0 +1,70 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2018, Blender Foundation +# All rights reserved. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + intern + ../blenkernel + ../blenlib + ../blenfont + ../depsgraph + ../makesdna + ../makesrna + ../bmesh + ../render/extern/include + ../../../intern/elbeem/extern + ../../../intern/guardedalloc + ../../../intern/eigen +) + +set(INC_SYS + ${ZLIB_INCLUDE_DIRS} +) + +set(SRC + intern/MOD_gpencil_util.h + + intern/MOD_gpencil_util.c + intern/MOD_gpencilnoise.c + intern/MOD_gpencilsubdiv.c + intern/MOD_gpencilsimplify.c + intern/MOD_gpencilthick.c + intern/MOD_gpenciltint.c + intern/MOD_gpencilcolor.c + intern/MOD_gpencilinstance.c + intern/MOD_gpencilbuild.c + intern/MOD_gpencilopacity.c + intern/MOD_gpencillattice.c + intern/MOD_gpencilmirror.c + intern/MOD_gpencilsmooth.c + intern/MOD_gpencilhook.c + intern/MOD_gpenciloffset.c + + MOD_gpencil_modifiertypes.h +) + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +add_definitions(${GL_DEFINITIONS}) + +blender_add_lib(bf_gpencil_modifiers "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h new file mode 100644 index 00000000000..ca941017ff9 --- /dev/null +++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h @@ -0,0 +1,53 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ben Batt + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file MOD_modifiertypes.h + * \ingroup modifiers + */ + +#ifndef __MOD_GP_MODIFIERTYPES_H__ +#define __MOD_GP_MODIFIERTYPES_H__ + +#include "BKE_gpencil_modifier.h" + +/* ****************** Type structures for all modifiers ****************** */ + +extern GpencilModifierTypeInfo modifierType_Gpencil_None; +extern GpencilModifierTypeInfo modifierType_Gpencil_Noise; +extern GpencilModifierTypeInfo modifierType_Gpencil_Subdiv; +extern GpencilModifierTypeInfo modifierType_Gpencil_Simplify; +extern GpencilModifierTypeInfo modifierType_Gpencil_Thick; +extern GpencilModifierTypeInfo modifierType_Gpencil_Tint; +extern GpencilModifierTypeInfo modifierType_Gpencil_Color; +extern GpencilModifierTypeInfo modifierType_Gpencil_Instance; +extern GpencilModifierTypeInfo modifierType_Gpencil_Build; +extern GpencilModifierTypeInfo modifierType_Gpencil_Opacity; +extern GpencilModifierTypeInfo modifierType_Gpencil_Lattice; +extern GpencilModifierTypeInfo modifierType_Gpencil_Mirror; +extern GpencilModifierTypeInfo modifierType_Gpencil_Smooth; +extern GpencilModifierTypeInfo modifierType_Gpencil_Hook; +extern GpencilModifierTypeInfo modifierType_Gpencil_Offset; + +/* MOD_gpencil_util.c */ +void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]); + +#endif /* __MOD_GP_MODIFIERTYPES_H__ */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c new file mode 100644 index 00000000000..97d28863095 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -0,0 +1,142 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/modifiers/intern/MOD_gpencil_util.c + * \ingroup bke + */ + + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_math_color.h" +#include "BLI_rand.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_lattice.h" +#include "BKE_material.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_colortools.h" + +#include "MOD_gpencil_modifiertypes.h" +#include "MOD_gpencil_util.h" + +void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]) +{ +#define INIT_GP_TYPE(typeName) (types[eGpencilModifierType_##typeName] = &modifierType_Gpencil_##typeName) + INIT_GP_TYPE(Noise); + INIT_GP_TYPE(Subdiv); + INIT_GP_TYPE(Simplify); + INIT_GP_TYPE(Thick); + INIT_GP_TYPE(Tint); + INIT_GP_TYPE(Color); + INIT_GP_TYPE(Instance); + INIT_GP_TYPE(Build); + INIT_GP_TYPE(Opacity); + INIT_GP_TYPE(Lattice); + INIT_GP_TYPE(Mirror); + INIT_GP_TYPE(Smooth); + INIT_GP_TYPE(Hook); + INIT_GP_TYPE(Offset); +#undef INIT_GP_TYPE +} + +/* verify if valid layer and pass index */ +bool is_stroke_affected_by_modifier( + Object *ob, char *mlayername, int mpassindex, int minpoints, + bGPDlayer *gpl, bGPDstroke *gps, bool inv1, bool inv2) +{ + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + + /* omit if filter by layer */ + if (mlayername[0] != '\0') { + if (inv1 == false) { + if (!STREQ(mlayername, gpl->info)) { + return false; + } + } + else { + if (STREQ(mlayername, gpl->info)) { + return false; + } + } + } + /* verify pass */ + if (mpassindex > 0) { + if (inv2 == false) { + if (gp_style->index != mpassindex) { + return false; + } + } + else { + if (gp_style->index == mpassindex) { + return false; + } + } + } + /* need to have a minimum number of points */ + if ((minpoints > 0) && (gps->totpoints < minpoints)) { + return false; + } + + return true; +} + +/* verify if valid vertex group *and return weight */ +float get_modifier_point_weight(MDeformVert *dvert, int inverse, int vindex) +{ + float weight = 1.0f; + + if (vindex >= 0) { + weight = BKE_gpencil_vgroup_use_index(dvert, vindex); + if ((weight >= 0.0f) && (inverse == 1)) { + return -1.0f; + } + + if ((weight < 0.0f) && (inverse == 0)) { + return -1.0f; + } + + /* if inverse, weight is always 1 */ + if ((weight < 0.0f) && (inverse == 1)) { + return 1.0f; + } + + } + + return weight; +} diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h new file mode 100644 index 00000000000..50ac557042d --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -0,0 +1,47 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/modifiers/intern/MOD_gpencil_util.h + * \ingroup modifiers + */ + + +#ifndef __MOD_GPENCIL_UTIL_H__ +#define __MOD_GPENCIL_UTIL_H__ + +struct Object; +struct bGPDlayer; +struct bGPDstroke; +struct MDeformVert; + +bool is_stroke_affected_by_modifier( + struct Object *ob, char *mlayername, int mpassindex, int minpoints, + bGPDlayer *gpl, bGPDstroke *gps, bool inv1, bool inv2); + +float get_modifier_point_weight(struct MDeformVert *dvert, int inverse, int vindex); + +#endif /* __MOD_GPENCIL_UTIL_H__ */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c new file mode 100644 index 00000000000..6b959659a60 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -0,0 +1,558 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilbuild.c + * \ingroup modifiers + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + BuildGpencilModifierData *gpmd = (BuildGpencilModifierData *)md; + + /* We deliberately set this range to the half the default + * frame-range to have an immediate effect ot suggest use-cases + */ + gpmd->start_frame = 1; + gpmd->end_frame = 125; + + /* Init default length of each build effect - Nothing special */ + gpmd->start_delay = 0.0f; + gpmd->length = 100.0f; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +static bool dependsOnTime(GpencilModifierData *UNUSED(md)) +{ + return true; +} + +/* ******************************************** */ +/* Build Modifier - Stroke generation logic + * + * There are two modes for how the strokes are sequenced (at a macro-level): + * - Sequential Mode - Strokes appear/disappear one after the other. Only a single one changes at a time. + * - Concurrent Mode - Multiple strokes appear/disappear at once. + * + * Assumptions: + * - Stroke points are generally equally spaced. This implies that we can just add/remove points, + * without worrying about distances between them / adding extra interpolated points between + * an visible point and one about to be added/removed (or any similar tapering effects). + + * - All strokes present are fully visible (i.e. we don't have to ignore any) + */ + +/* Remove a particular stroke */ +static void clear_stroke(bGPDframe *gpf, bGPDstroke *gps) +{ + BLI_remlink(&gpf->strokes, gps); + BKE_gpencil_free_stroke(gps); +} + +/* Clear all strokes in frame */ +static void gpf_clear_all_strokes(bGPDframe *gpf) +{ + bGPDstroke *gps, *gps_next; + for (gps = gpf->strokes.first; gps; gps = gps_next) { + gps_next = gps->next; + clear_stroke(gpf, gps); + } + BLI_listbase_clear(&gpf->strokes); +} + +/* Reduce the number of points in the stroke + * + * Note: This won't be called if all points are present/removed + * TODO: Allow blending of growing/shrinking tip (e.g. for more gradual transitions) + */ +static void reduce_stroke_points(bGPDstroke *gps, const int num_points, const eBuildGpencil_Transition transition) +{ + bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * num_points, __func__); + MDeformVert *new_dvert = MEM_callocN(sizeof(MDeformVert) * num_points, __func__); + + /* Which end should points be removed from */ + // TODO: free stroke weights + switch (transition) { + case GP_BUILD_TRANSITION_GROW: /* Show in forward order = Remove ungrown-points from end of stroke */ + case GP_BUILD_TRANSITION_SHRINK: /* Hide in reverse order = Remove dead-points from end of stroke */ + { + /* copy over point data */ + memcpy(new_points, gps->points, sizeof(bGPDspoint) * num_points); + memcpy(new_dvert, gps->dvert, sizeof(MDeformVert) * num_points); + + /* free unused point weights */ + for (int i = num_points; i < gps->totpoints; i++) { + MDeformVert *dvert = &gps->dvert[i]; + BKE_gpencil_free_point_weights(dvert); + } + + break; + } + + /* Hide in forward order = Remove points from start of stroke */ + case GP_BUILD_TRANSITION_FADE: + { + /* num_points is the number of points left after reducing. + * We need to know how many to remove + */ + const int offset = gps->totpoints - num_points; + + /* copy over point data */ + memcpy(new_points, gps->points + offset, sizeof(bGPDspoint) * num_points); + memcpy(new_dvert, gps->dvert + offset, sizeof(MDeformVert) * num_points); + + /* free unused weights */ + for (int i = 0; i < offset; i++) { + MDeformVert *dvert = &gps->dvert[i]; + BKE_gpencil_free_point_weights(dvert); + } + + break; + } + + default: + printf("ERROR: Unknown transition %d in %s()\n", (int)transition, __func__); + break; + } + + /* replace stroke geometry */ + MEM_SAFE_FREE(gps->points); + MEM_SAFE_FREE(gps->dvert); + gps->points = new_points; + gps->dvert = new_dvert; + gps->totpoints = num_points; + + /* mark stroke as needing to have its geometry caches rebuilt */ + gps->flag |= GP_STROKE_RECALC_CACHES; + gps->tot_triangles = 0; + MEM_SAFE_FREE(gps->triangles); +} + +/* --------------------------------------------- */ + +/* Stroke Data Table Entry - This represents one stroke being generated */ +typedef struct tStrokeBuildDetails { + bGPDstroke *gps; + + /* Indices - first/last indices for the stroke's points (overall) */ + size_t start_idx, end_idx; + + /* Number of points - Cache for more convenient access */ + int totpoints; +} tStrokeBuildDetails; + + +/* Sequential - Show strokes one after the other */ +static void build_sequential(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac) +{ + const size_t tot_strokes = BLI_listbase_count(&gpf->strokes); + bGPDstroke *gps; + size_t i; + + /* 1) Compute proportion of time each stroke should occupy */ + /* NOTE: This assumes that the total number of points won't overflow! */ + tStrokeBuildDetails *table = MEM_callocN(sizeof(tStrokeBuildDetails) * tot_strokes, __func__); + size_t totpoints = 0; + + /* 1.1) First pass - Tally up points */ + for (gps = gpf->strokes.first, i = 0; gps; gps = gps->next, i++) { + tStrokeBuildDetails *cell = &table[i]; + + cell->gps = gps; + cell->totpoints = gps->totpoints; + + totpoints += cell->totpoints; + } + + /* 1.2) Second pass - Compute the overall indices for points */ + for (i = 0; i < tot_strokes; i++) { + tStrokeBuildDetails *cell = &table[i]; + + if (i == 0) { + cell->start_idx = 0; + } + else { + cell->start_idx = (cell - 1)->end_idx; + } + cell->end_idx = cell->start_idx + cell->totpoints - 1; + } + + + /* 2) Determine the global indices for points that should be visible */ + size_t first_visible = 0; + size_t last_visible = 0; + + switch (mmd->transition) { + /* Show in forward order + * - As fac increases, the number of visible points increases + */ + case GP_BUILD_TRANSITION_GROW: + first_visible = 0; /* always visible */ + last_visible = (size_t)roundf(totpoints * fac); + break; + + /* Hide in reverse order + * - As fac increases, the number of points visible at the end decreases + */ + case GP_BUILD_TRANSITION_SHRINK: + first_visible = 0; /* always visible (until last point removed) */ + last_visible = (size_t)(totpoints * (1.0f - fac)); + break; + + /* Hide in forward order + * - As fac increases, the early points start getting hidden + */ + case GP_BUILD_TRANSITION_FADE: + first_visible = (size_t)(totpoints * fac); + last_visible = totpoints; /* i.e. visible until the end, unless first overlaps this */ + break; + } + + + /* 3) Go through all strokes, deciding which to keep, and/or how much of each to keep */ + for (i = 0; i < tot_strokes; i++) { + tStrokeBuildDetails *cell = &table[i]; + + /* Determine what portion of the stroke is visible */ + if ((cell->end_idx < first_visible) || (cell->start_idx > last_visible)) { + /* Not visible at all - Either ended before */ + clear_stroke(gpf, cell->gps); + } + else { + /* Some proportion of stroke is visible */ + /* XXX: Will the transition settings still be valid now? */ + if ((first_visible <= cell->start_idx) && (last_visible >= cell->end_idx)) { + /* Do nothing - whole stroke is visible */ + } + else if (first_visible > cell->start_idx) { + /* Starts partway through this stroke */ + int num_points = cell->end_idx - first_visible; + reduce_stroke_points(cell->gps, num_points, mmd->transition); + } + else { + /* Ends partway through this stroke */ + int num_points = last_visible - cell->start_idx; + reduce_stroke_points(cell->gps, num_points, mmd->transition); + } + } + } + + /* Free table */ + MEM_freeN(table); +} + +/* --------------------------------------------- */ + +/* Concurrent - Show multiple strokes at once */ +// TODO: Allow random offsets to start times +// TODO: Allow varying speeds? Scaling of progress? +static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, float fac) +{ + bGPDstroke *gps, *gps_next; + int max_points = 0; + + const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW); + + /* 1) Determine the longest stroke, to figure out when short strokes should start */ + /* FIXME: A *really* long stroke here could dwarf everything else, causing bad timings */ + for (gps = gpf->strokes.first; gps; gps = gps->next) { + if (gps->totpoints > max_points) { + max_points = gps->totpoints; + } + } + if (max_points == 0) { + printf("ERROR: Strokes are all empty (GP Build Modifier: %s)\n", __func__); + return; + } + + /* 2) For each stroke, determine how it should be handled */ + for (gps = gpf->strokes.first; gps; gps = gps_next) { + gps_next = gps->next; + + /* Relative Length of Stroke - Relative to the longest stroke, + * what proportion of the available time should this stroke use + */ + const float relative_len = (float)gps->totpoints / (float)max_points; + + /* Determine how many points should be left in the stroke */ + int num_points = 0; + + switch (mmd->time_alignment) { + case GP_BUILD_TIMEALIGN_START: /* all start on frame 1 */ + { + /* Build effect occurs over when fac = 0, to fac = relative_len */ + if (fac <= relative_len) { + /* Scale fac to fit relative_len */ + /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */ + const float scaled_fac = fac / relative_len; + + if (reverse) { + num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints); + } + else { + num_points = (int)roundf(scaled_fac * gps->totpoints); + } + } + else { + /* Build effect has ended */ + if (reverse) { + num_points = 0; + } + else { + num_points = gps->totpoints; + } + } + + break; + } + case GP_BUILD_TIMEALIGN_END: /* all end on same frame */ + { + /* Build effect occurs over 1.0 - relative_len, to 1.0 (i.e. over the end of the range) */ + const float start_fac = 1.0f - relative_len; + + if (fac >= start_fac) { + /* FIXME: prevent potential div by zero (e.g. very short stroke vs one very long one) */ + const float scaled_fac = (fac - start_fac) / relative_len; + + if (reverse) { + num_points = (int)roundf((1.0f - scaled_fac) * gps->totpoints); + } + else { + num_points = (int)roundf(scaled_fac * gps->totpoints); + } + } + else { + /* Build effect hasn't started */ + if (reverse) { + num_points = gps->totpoints; + } + else { + num_points = 0; + } + } + + break; + } + + /* TODO... */ + } + + /* Modify the stroke geometry */ + if (num_points <= 0) { + /* Nothing Left - Delete the stroke */ + clear_stroke(gpf, gps); + } + else if (num_points < gps->totpoints) { + /* Remove some points */ + reduce_stroke_points(gps, num_points, mmd->transition); + } + } +} + +/* --------------------------------------------- */ + +/* Entry-point for Build Modifier */ +static void generateStrokes( + GpencilModifierData *md, Depsgraph *depsgraph, + Object *UNUSED(ob), bGPDlayer *gpl, bGPDframe *gpf) +{ + BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md; + const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW); + + const float ctime = DEG_get_ctime(depsgraph); + //printf("GP Build Modifier - %f\n", ctime); + + /* Early exit if it's an empty frame */ + if (gpf->strokes.first == NULL) { + return; + } + + /* Omit layer if filter by layer */ + if (mmd->layername[0] != '\0') { + if ((mmd->flag & GP_BUILD_INVERT_LAYER) == 0) { + if (!STREQ(mmd->layername, gpl->info)) { + return; + } + } + else { + if (STREQ(mmd->layername, gpl->info)) { + return; + } + } + } + + /* Early exit if outside of the frame range for this modifier + * (e.g. to have one forward, and one backwards modifier) + */ + if (mmd->flag & GP_BUILD_RESTRICT_TIME) { + if ((ctime < mmd->start_frame) || (ctime > mmd->end_frame)) { + return; + } + } + + /* Compute start and end frames for the animation effect + * By default, the upper bound is given by the "maximum length" setting + */ + float start_frame = gpf->framenum + mmd->start_delay; + float end_frame = gpf->framenum + mmd->length; + + if (gpf->next) { + /* Use the next frame or upper bound as end frame, whichever is lower/closer */ + end_frame = MIN2(end_frame, gpf->next->framenum); + } + + + /* Early exit if current frame is outside start/end bounds */ + /* NOTE: If we're beyond the next/prev frames (if existent), then we wouldn't have this problem anyway... */ + if (ctime < start_frame) { + /* Before Start - Animation hasn't started. Display initial state. */ + if (reverse) { + /* 1) Reverse = Start with all, end with nothing. + * ==> Do nothing (everything already present) + */ + } + else { + /* 2) Forward Order = Start with nothing, end with the full frame. + * ==> Free all strokes, and return an empty frame + */ + gpf_clear_all_strokes(gpf); + } + + /* Early exit */ + return; + } + else if (ctime >= end_frame) { + /* Past End - Animation finished. Display final result. */ + if (reverse) { + /* 1) Reverse = Start with all, end with nothing. + * ==> Free all strokes, and return an empty frame + */ + gpf_clear_all_strokes(gpf); + } + else { + /* 2) Forward Order = Start with nothing, end with the full frame. + * ==> Do Nothing (everything already present) + */ + } + + /* Early exit */ + return; + } + + + /* Determine how far along we are between the keyframes */ + float fac = (ctime - start_frame) / (end_frame - start_frame); + //printf(" Progress on %d = %f (%f - %f)\n", gpf->framenum, fac, start_frame, end_frame); + + /* Time management mode */ + switch (mmd->mode) { + case GP_BUILD_MODE_SEQUENTIAL: + build_sequential(mmd, gpf, fac); + break; + + case GP_BUILD_MODE_CONCURRENT: + build_concurrent(mmd, gpf, fac); + break; + + default: + printf("Unsupported build mode (%d) for GP Build Modifier: '%s'\n", mmd->mode, mmd->modifier.name); + break; + } +} + +/* ******************************************** */ + +/* FIXME: Baking the Build Modifier is currently unsupported. + * Adding support for this is more complicated than for other + * modifiers, as to implement this, we'd have to add more frames, + * which would in turn break how the modifier functions. + */ +#if 0 +static void bakeModifier( + Main *bmain, const Depsgraph *UNUSED(depsgraph), + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + + } + } +} +#endif + +/* ******************************************** */ + +GpencilModifierTypeInfo modifierType_Gpencil_Build = { + /* name */ "Build", + /* structName */ "BuildGpencilModifierData", + /* structSize */ sizeof(BuildGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ 0, + + /* copyData */ copyData, + + /* deformStroke */ NULL, + /* generateStrokes */ generateStrokes, + /* bakeModifier */ NULL, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ dependsOnTime, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c new file mode 100644 index 00000000000..af00b24715f --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -0,0 +1,178 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilcolor.c + * \ingroup modifiers + */ + +#include + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_math_color.h" +#include "BLI_math_vector.h" +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_main.h" +#include "BKE_material.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; + gpmd->pass_index = 0; + ARRAY_SET_ITEMS(gpmd->hsv, 1.0f, 1.0f, 1.0f); + gpmd->layername[0] = '\0'; + gpmd->flag |= GP_COLOR_CREATE_COLORS; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +/* color correction strokes */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + + ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md; + float hsv[3], factor[3]; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 1, gpl, gps, + mmd->flag & GP_COLOR_INVERT_LAYER, mmd->flag & GP_COLOR_INVERT_PASS)) + { + return; + } + + copy_v3_v3(factor, mmd->hsv); + add_v3_fl(factor, -1.0f); + + rgb_to_hsv_v(gps->runtime.tmp_stroke_rgba, hsv); + add_v3_v3(hsv, factor); + CLAMP3(hsv, 0.0f, 1.0f); + hsv_to_rgb_v(hsv, gps->runtime.tmp_stroke_rgba); + + rgb_to_hsv_v(gps->runtime.tmp_fill_rgba, hsv); + add_v3_v3(hsv, factor); + CLAMP3(hsv, 0.0f, 1.0f); + hsv_to_rgb_v(hsv, gps->runtime.tmp_fill_rgba); +} + +static void bakeModifier( + Main *bmain, Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md; + bGPdata *gpd = ob->data; + + GHash *gh_color = BLI_ghash_str_new("GP_Color modifier"); + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + + Material *mat = give_current_material(ob, gps->mat_nr + 1); + if (mat == NULL) + continue; + MaterialGPencilStyle *gp_style = mat->gp_style; + /* skip stroke if it doesn't have color info */ + if (ELEM(NULL, gp_style)) + continue; + + copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); + copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); + + /* look for color */ + if (mmd->flag & GP_TINT_CREATE_COLORS) { + Material *newmat = BLI_ghash_lookup(gh_color, mat->id.name); + if (newmat == NULL) { + BKE_object_material_slot_add(bmain, ob); + newmat = BKE_material_copy(bmain, mat); + assign_material(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_EXISTING); + + copy_v4_v4(newmat->gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba); + copy_v4_v4(newmat->gp_style->fill_rgba, gps->runtime.tmp_fill_rgba); + + BLI_ghash_insert(gh_color, mat->id.name, newmat); + } + /* reasign color index */ + int idx = BKE_object_material_slot_find_index(ob, newmat); + gps->mat_nr = idx - 1; + } + else { + /* reuse existing color */ + copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba); + copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba); + } + + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } + /* free hash buffers */ + if (gh_color) { + BLI_ghash_free(gh_color, NULL, NULL); + gh_color = NULL; + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Color = { + /* name */ "Hue/Saturation", + /* structName */ "ColorGpencilModifierData", + /* structSize */ sizeof(ColorGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c new file mode 100644 index 00000000000..e036b6b78be --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -0,0 +1,355 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilhook.c + * \ingroup modifiers + */ + +#include + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_modifier_types.h" +#include "BLI_math.h" + +#include "BLI_utildefines.h" + +#include "BKE_action.h" +#include "BKE_context.h" +#include "BKE_colortools.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_modifier.h" +#include "BKE_library_query.h" +#include "BKE_scene.h" +#include "BKE_main.h" +#include "BKE_layer.h" + +#include "MEM_guardedalloc.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +/* temp struct to hold data */ +struct GPHookData_cb { + struct CurveMapping *curfalloff; + + char falloff_type; + float falloff; + float falloff_sq; + float fac_orig; + + unsigned int use_falloff : 1; + unsigned int use_uniform : 1; + + float cent[3]; + + float mat_uniform[3][3]; + float mat[4][4]; +}; + +static void initData(GpencilModifierData *md) +{ + HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->layername[0] = '\0'; + gpmd->vgname[0] = '\0'; + gpmd->object = NULL; + gpmd->force = 0.5f; + gpmd->falloff_type = eGPHook_Falloff_Smooth; + gpmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curfalloff) { + curvemapping_initialize(gpmd->curfalloff); + } +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + HookGpencilModifierData *gmd = (HookGpencilModifierData *)md; + HookGpencilModifierData *tgmd = (HookGpencilModifierData *)target; + + if (tgmd->curfalloff != NULL) { + curvemapping_free(tgmd->curfalloff); + tgmd->curfalloff = NULL; + } + + BKE_gpencil_modifier_copyData_generic(md, target); + + tgmd->curfalloff = curvemapping_copy(gmd->curfalloff); +} + +/* calculate factor of fallof */ +static float gp_hook_falloff(const struct GPHookData_cb *tData, const float len_sq) +{ + BLI_assert(tData->falloff_sq); + if (len_sq > tData->falloff_sq) { + return 0.0f; + } + else if (len_sq > 0.0f) { + float fac; + + if (tData->falloff_type == eGPHook_Falloff_Const) { + fac = 1.0f; + goto finally; + } + else if (tData->falloff_type == eGPHook_Falloff_InvSquare) { + /* avoid sqrt below */ + fac = 1.0f - (len_sq / tData->falloff_sq); + goto finally; + } + + fac = 1.0f - (sqrtf(len_sq) / tData->falloff); + + switch (tData->falloff_type) { + case eGPHook_Falloff_Curve: + fac = curvemapping_evaluateF(tData->curfalloff, 0, fac); + break; + case eGPHook_Falloff_Sharp: + fac = fac * fac; + break; + case eGPHook_Falloff_Smooth: + fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; + break; + case eGPHook_Falloff_Root: + fac = sqrtf(fac); + break; + case eGPHook_Falloff_Linear: + /* pass */ + break; + case eGPHook_Falloff_Sphere: + fac = sqrtf(2 * fac - fac * fac); + break; + default: + fac = fac; + break; + } + + finally: + return fac * tData->fac_orig; + } + else { + return tData->fac_orig; + } +} + +/* apply point deformation */ +static void gp_hook_co_apply(struct GPHookData_cb *tData, float weight, bGPDspoint *pt) +{ + float fac; + + if (tData->use_falloff) { + float len_sq; + + if (tData->use_uniform) { + float co_uniform[3]; + mul_v3_m3v3(co_uniform, tData->mat_uniform, &pt->x); + len_sq = len_squared_v3v3(tData->cent, co_uniform); + } + else { + len_sq = len_squared_v3v3(tData->cent, &pt->x); + } + + fac = gp_hook_falloff(tData, len_sq); + } + else { + fac = tData->fac_orig; + } + + if (fac) { + float co_tmp[3]; + mul_v3_m4v3(co_tmp, tData->mat, &pt->x); + interp_v3_v3v3(&pt->x, &pt->x, co_tmp, fac * weight); + } +} + +/* deform stroke */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + HookGpencilModifierData *mmd = (HookGpencilModifierData *)md; + if (!mmd->object) { + return; + } + + int vindex = defgroup_name_index(ob, mmd->vgname); + float weight = 1.0f; + + bPoseChannel *pchan = BKE_pose_channel_find_name(mmd->object->pose, mmd->subtarget); + float dmat[4][4]; + struct GPHookData_cb tData; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 3, gpl, gps, + mmd->flag & GP_HOOK_INVERT_LAYER, mmd->flag & GP_HOOK_INVERT_PASS)) + { + return; + } + + /* init struct */ + tData.curfalloff = mmd->curfalloff; + tData.falloff_type = mmd->falloff_type; + tData.falloff = (mmd->falloff_type == eHook_Falloff_None) ? 0.0f : mmd->falloff; + tData.falloff_sq = SQUARE(tData.falloff); + tData.fac_orig = mmd->force; + tData.use_falloff = (tData.falloff_sq != 0.0f); + tData.use_uniform = (mmd->flag & GP_HOOK_UNIFORM_SPACE) != 0; + + if (tData.use_uniform) { + copy_m3_m4(tData.mat_uniform, mmd->parentinv); + mul_v3_m3v3(tData.cent, tData.mat_uniform, mmd->cent); + } + else { + unit_m3(tData.mat_uniform); + copy_v3_v3(tData.cent, mmd->cent); + } + + /* get world-space matrix of target, corrected for the space the verts are in */ + if (mmd->subtarget[0] && pchan) { + /* bone target if there's a matching pose-channel */ + mul_m4_m4m4(dmat, mmd->object->obmat, pchan->pose_mat); + } + else { + /* just object target */ + copy_m4_m4(dmat, mmd->object->obmat); + } + invert_m4_m4(ob->imat, ob->obmat); + mul_m4_series(tData.mat, ob->imat, dmat, mmd->parentinv); + + /* loop points and apply deform */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + /* verify vertex group */ + weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_HOOK_INVERT_VGROUP) == 0), vindex); + if (weight < 0) { + continue; + } + gp_hook_co_apply(&tData, weight, pt); + } +} + +/* FIXME: Ideally we be doing this on a copy of the main depsgraph + * (i.e. one where we don't have to worry about restoring state) + */ +static void bakeModifier( + Main *bmain, Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + HookGpencilModifierData *mmd = (HookGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = ob->data; + int oldframe = (int)DEG_get_ctime(depsgraph); + + if (mmd->object == NULL) + return; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* apply hook effects on this frame + * NOTE: this assumes that we don't want hook animation on non-keyframed frames + */ + CFRA = gpf->framenum; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* compute hook effects on this frame */ + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } + + /* return frame state and DB to original state */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); +} + +static void freeData(GpencilModifierData *md) +{ + HookGpencilModifierData *mmd = (HookGpencilModifierData *)md; + + if (mmd->curfalloff) { + curvemapping_free(mmd->curfalloff); + } +} + +static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) +{ + HookGpencilModifierData *mmd = (HookGpencilModifierData *)md; + + return !mmd->object; +} + +static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + HookGpencilModifierData *lmd = (HookGpencilModifierData *)md; + if (lmd->object != NULL) { + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Hook Modifier"); + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); + } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); +} + +static void foreachObjectLink( + GpencilModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + HookGpencilModifierData *mmd = (HookGpencilModifierData *)md; + + walk(userData, ob, &mmd->object, IDWALK_CB_NOP); +} + +GpencilModifierTypeInfo modifierType_Gpencil_Hook = { + /* name */ "Hook", + /* structName */ "HookGpencilModifierData", + /* structSize */ sizeof(HookGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ 0, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c new file mode 100644 index 00000000000..64f3fbc4a95 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c @@ -0,0 +1,360 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilinstance.c + * \ingroup modifiers + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_blenlib.h" +#include "BLI_rand.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_main.h" +#include "BKE_scene.h" +#include "BKE_layer.h" +#include "BKE_collection.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + InstanceGpencilModifierData *gpmd = (InstanceGpencilModifierData *)md; + gpmd->count[0] = 1; + gpmd->count[1] = 1; + gpmd->count[2] = 1; + gpmd->offset[0] = 1.0f; + gpmd->offset[1] = 1.0f; + gpmd->offset[2] = 1.0f; + gpmd->shift[0] = 0.0f; + gpmd->shift[1] = 0.0f; + gpmd->shift[2] = 0.0f; + gpmd->scale[0] = 1.0f; + gpmd->scale[1] = 1.0f; + gpmd->scale[2] = 1.0f; + gpmd->rnd_rot = 0.5f; + gpmd->rnd_size = 0.5f; + gpmd->lock_axis |= GP_LOCKAXIS_X; + gpmd->flag |= GP_INSTANCE_MAKE_OBJECTS; + + /* fill random values */ + BLI_array_frand(gpmd->rnd, 20, 1); + gpmd->rnd[0] = 1; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +/* -------------------------------- */ + +/* array modifier - generate geometry callback (for viewport/rendering) */ +/* TODO: How to skip this for the simplify options? --> !GP_SIMPLIFY_MODIF(ts, playing) */ +static void generate_geometry( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDframe *gpf) +{ + InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md; + ListBase stroke_cache = {NULL, NULL}; + bGPDstroke *gps; + int idx; + + /* Check which strokes we can use once, and store those results in an array + * for quicker checking of what's valid (since string comparisons are expensive) + */ + const int num_strokes = BLI_listbase_count(&gpf->strokes); + int num_valid = 0; + + bool *valid_strokes = MEM_callocN(sizeof(bool) * num_strokes, __func__); + + for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) { + /* Record whether this stroke can be used + * ATTENTION: The logic here is the inverse of what's used everywhere else! + */ + if (is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 1, gpl, gps, + mmd->flag & GP_INSTANCE_INVERT_LAYER, mmd->flag & GP_INSTANCE_INVERT_PASS)) + { + valid_strokes[idx] = true; + num_valid++; + } + } + + /* Early exit if no strokes can be copied */ + if (num_valid == 0) { + if (G.debug & G_DEBUG) { + printf("GP Array Mod - No strokes to be included\n"); + } + + MEM_SAFE_FREE(valid_strokes); + return; + } + + + /* Generate new instances of all existing strokes, + * keeping each instance together so they maintain + * the correct ordering relative to each other + */ + for (int x = 0; x < mmd->count[0]; x++) { + for (int y = 0; y < mmd->count[1]; y++) { + for (int z = 0; z < mmd->count[2]; z++) { + /* original strokes are at index = 0,0,0 */ + if ((x == 0) && (y == 0) && (z == 0)) { + continue; + } + + /* Compute transforms for this instance */ + const int elem_idx[3] = {x, y, z}; + float mat[4][4]; + + BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat); + + /* apply shift */ + int sh = x; + if (mmd->lock_axis == GP_LOCKAXIS_Y) { + sh = y; + } + if (mmd->lock_axis == GP_LOCKAXIS_Z) { + sh = z; + } + madd_v3_v3fl(mat[3], mmd->shift, sh); + + /* Duplicate original strokes to create this instance */ + for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) { + /* check if stroke can be duplicated */ + if (valid_strokes[idx]) { + /* Duplicate stroke */ + bGPDstroke *gps_dst = MEM_dupallocN(gps); + gps_dst->points = MEM_dupallocN(gps->points); + gps_dst->dvert = MEM_dupallocN(gps->dvert); + BKE_gpencil_stroke_weights_duplicate(gps, gps_dst); + + gps_dst->triangles = MEM_dupallocN(gps->triangles); + + /* Move points */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps_dst->points[i]; + mul_m4_v3(mat, &pt->x); + } + + /* Add new stroke to cache, to be added to the frame once + * all duplicates have been made + */ + BLI_addtail(&stroke_cache, gps_dst); + } + } + } + } + } + + /* merge newly created stroke instances back into the main stroke list */ + BLI_movelisttolist(&gpf->strokes, &stroke_cache); + + /* free temp data */ + MEM_SAFE_FREE(valid_strokes); +} + +/* bakeModifier - "Bake to Data" Mode */ +static void bakeModifierGP_strokes( + Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + generate_geometry(md, depsgraph, ob, gpl, gpf); + } + } +} + +/* -------------------------------- */ + +/* helper to create a new object */ +static Object *array_instance_add_ob_copy(Main *bmain, Scene *scene, Object *from_ob) +{ + Object *ob; + + ob = BKE_object_copy(bmain, from_ob); + BKE_collection_object_add_from(bmain, scene, from_ob, ob); + + zero_v3(ob->loc); + zero_v3(ob->rot); + + DEG_id_type_tag(bmain, ID_OB); + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, 0); + + return ob; +} + +/* bakeModifier - "Make Objects" Mode */ +static void bakeModifierGP_objects(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) +{ + InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + /* reset random */ + mmd->rnd[0] = 1; + + /* generate instances as objects */ + for (int x = 0; x < mmd->count[0]; x++) { + for (int y = 0; y < mmd->count[1]; y++) { + for (int z = 0; z < mmd->count[2]; z++) { + Object *newob; + GpencilModifierData *fmd; + + const int elem_idx[3] = {x, y, z}; + float mat[4][4], finalmat[4][4]; + int sh; + + /* original strokes are at index = 0,0,0 */ + if ((x == 0) && (y == 0) && (z == 0)) { + continue; + } + + /* compute transform for instance */ + BKE_gpencil_instance_modifier_instance_tfm(mmd, elem_idx, mat); + mul_m4_m4m4(finalmat, ob->obmat, mat); + + /* moves to new origin */ + sh = x; + if (mmd->lock_axis == GP_LOCKAXIS_Y) { + sh = y; + } + if (mmd->lock_axis == GP_LOCKAXIS_Z) { + sh = z; + } + madd_v3_v3fl(finalmat[3], mmd->shift, sh); + + /* Create a new object + * + * NOTE: Copies share the same original GP datablock + * Artists can later user make_single_user on these + * to make them unique (if necessary), without too + * much extra memory usage. + */ + newob = array_instance_add_ob_copy(bmain, scene, ob); + + /* remove array on destination object */ + fmd = (GpencilModifierData *)BLI_findstring(&newob->greasepencil_modifiers, md->name, offsetof(GpencilModifierData, name)); + if (fmd) { + BLI_remlink(&newob->greasepencil_modifiers, fmd); + BKE_gpencil_modifier_free(fmd); + } + + /* copy transforms to destination object */ + copy_m4_m4(newob->obmat, finalmat); + + copy_v3_v3(newob->loc, finalmat[3]); + mat4_to_eul(newob->rot, finalmat); + mat4_to_size(newob->size, finalmat); + } + } + } +} + +/* -------------------------------- */ + +/* Generic "generateStrokes" callback */ +static void generateStrokes( + GpencilModifierData *md, Depsgraph *depsgraph, + Object *ob, bGPDlayer *gpl, bGPDframe *gpf) +{ + InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md; + + /* When the "make_objects" flag is set, this modifier is handled as part of the + * draw engine instead. The main benefit is that the instances won't suffer from + * z-ordering problems. + * + * FIXME: Ultimately, the draw-engine hack here shouldn't be necessary, but until + * we find a better fix to the z-ordering problems, it's better to have + * working functionality + */ + if ((mmd->flag & GP_INSTANCE_MAKE_OBJECTS) == 0) { + generate_geometry(md, depsgraph, ob, gpl, gpf); + } +} + +/* Generic "bakeModifier" callback */ +static void bakeModifier( + Main *bmain, Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md; + + /* Create new objects or add all to current datablock. + * Sometimes it's useful to have the option to do either of these... + */ + if (mmd->flag & GP_INSTANCE_MAKE_OBJECTS) { + bakeModifierGP_objects(bmain, depsgraph, md, ob); + } + else { + bakeModifierGP_strokes(depsgraph, md, ob); + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Instance = { + /* name */ "Instance", + /* structName */ "InstanceGpencilModifierData", + /* structSize */ sizeof(InstanceGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ 0, + + /* copyData */ copyData, + + /* deformStroke */ NULL, + /* generateStrokes */ generateStrokes, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c new file mode 100644 index 00000000000..944e787020e --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -0,0 +1,213 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencillattice.c + * \ingroup modifiers + */ + +#include + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_modifier.h" +#include "BKE_lattice.h" +#include "BKE_library_query.h" +#include "BKE_scene.h" +#include "BKE_main.h" +#include "BKE_layer.h" + +#include "MEM_guardedalloc.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +static void initData(GpencilModifierData *md) +{ + LatticeGpencilModifierData *gpmd = (LatticeGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->layername[0] = '\0'; + gpmd->vgname[0] = '\0'; + gpmd->object = NULL; + gpmd->cache_data = NULL; + gpmd->strength = 1.0f; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + int vindex = defgroup_name_index(ob, mmd->vgname); + float weight = 1.0f; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 3, gpl, gps, + mmd->flag & GP_LATTICE_INVERT_LAYER, mmd->flag & GP_LATTICE_INVERT_PASS)) + { + return; + } + + if (mmd->cache_data == NULL) { + return; + } + + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + /* verify vertex group */ + weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_LATTICE_INVERT_VGROUP) == 0), vindex); + if (weight < 0) { + continue; + } + + calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight); + } +} + +/* FIXME: Ideally we be doing this on a copy of the main depsgraph + * (i.e. one where we don't have to worry about restoring state) + */ +static void bakeModifier( + Main *bmain, Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + struct LatticeDeformData *ldata = NULL; + bGPdata *gpd = ob->data; + int oldframe = (int)DEG_get_ctime(depsgraph); + + if (mmd->object == NULL) + return; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* apply lattice effects on this frame + * NOTE: this assumes that we don't want lattice animation on non-keyframed frames + */ + CFRA = gpf->framenum; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* recalculate lattice data */ + BKE_gpencil_lattice_init(ob); + + /* compute lattice effects on this frame */ + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } + + /* free lingering data */ + ldata = (struct LatticeDeformData *)mmd->cache_data; + if (ldata) { + end_latt_deform(ldata); + mmd->cache_data = NULL; + } + + /* return frame state and DB to original state */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); +} + +static void freeData(GpencilModifierData *md) +{ + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + struct LatticeDeformData *ldata = (struct LatticeDeformData *)mmd->cache_data; + /* free deform data */ + if (ldata) { + end_latt_deform(ldata); + } +} + +static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) +{ + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + + return !mmd->object; +} + +static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + LatticeGpencilModifierData *lmd = (LatticeGpencilModifierData *)md; + if (lmd->object != NULL) { + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier"); + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier"); + } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Lattice Modifier"); +} + +static void foreachObjectLink( + GpencilModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; + + walk(userData, ob, &mmd->object, IDWALK_CB_NOP); +} + +GpencilModifierTypeInfo modifierType_Gpencil_Lattice = { + /* name */ "Lattice", + /* structName */ "LatticeGpencilModifierData", + /* structSize */ sizeof(LatticeGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_Single | eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c new file mode 100644 index 00000000000..9b5186755d6 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -0,0 +1,239 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilmirror.c + * \ingroup modifiers + */ + +#include + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_modifier.h" +#include "BKE_library_query.h" +#include "BKE_scene.h" +#include "BKE_main.h" +#include "BKE_layer.h" + +#include "MEM_guardedalloc.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +static void initData(GpencilModifierData *md) +{ + MirrorGpencilModifierData *gpmd = (MirrorGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->layername[0] = '\0'; + gpmd->object = NULL; + gpmd->flag |= GP_MIRROR_AXIS_X; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +static void clip_stroke(MirrorGpencilModifierData *mmd, bGPDstroke *gps) +{ + int i; + bGPDspoint *pt; + float fpt[3]; + if ((mmd->flag & GP_MIRROR_CLIPPING) == 0) { + return; + } + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + copy_v3_v3(fpt, &pt->x); + for (int xi = 0; xi < 3; ++xi) { + if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) { + if (fpt[xi] >= 0.0f) { + fpt[xi] = 0.0f; + } + } + } + copy_v3_v3(&pt->x, fpt); + } + +} + +static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstroke *gps, int axis) +{ + int i; + bGPDspoint *pt; + float factor[3] = { 1.0f, 1.0f, 1.0f }; + factor[axis] = -1.0f; + + float clear[3] = { 0.0f, 0.0f, 0.0f }; + clear[axis] = 1.0f; + + float origin[3]; + float mirror_origin[3]; + + copy_v3_v3(origin, ob->loc); + /* only works with current axis */ + mul_v3_v3(origin, clear); + zero_v3(mirror_origin); + + if (mmd->object) { + copy_v3_v3(mirror_origin, mmd->object->loc); + mul_v3_v3(mirror_origin, clear); + sub_v3_v3(origin, mirror_origin); + } + /* clear other axis */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + add_v3_v3(&pt->x, origin); + mul_v3_v3(&pt->x, factor); + add_v3_v3(&pt->x, mirror_origin); + } + +} + +/* Generic "generateStrokes" callback */ +static void generateStrokes( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDframe *gpf) +{ + MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; + bGPDstroke *gps, *gps_new = NULL; + int tot_strokes; + int i; + + /* count strokes to avoid infinite loop after adding new strokes to tail of listbase */ + tot_strokes = BLI_listbase_count(&gpf->strokes); + + for (i = 0, gps = gpf->strokes.first; i < tot_strokes; i++, gps = gps->next) { + if (is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 1, gpl, gps, + mmd->flag & GP_MIRROR_INVERT_LAYER, mmd->flag & GP_MIRROR_INVERT_PASS)) + { + /* check each axis for mirroring */ + for (int xi = 0; xi < 3; ++xi) { + if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) { + /* clip before duplicate */ + clip_stroke(mmd, gps); + + gps_new = BKE_gpencil_stroke_duplicate(gps); + update_position(ob, mmd, gps_new, xi); + BLI_addtail(&gpf->strokes, gps_new); + } + } + } + } +} + +static void bakeModifier( + Main *bmain, Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = ob->data; + int oldframe = (int)DEG_get_ctime(depsgraph); + + if (mmd->object == NULL) + return; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* apply mirror effects on this frame */ + CFRA = gpf->framenum; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* compute mirror effects on this frame */ + generateStrokes(md, depsgraph, ob, gpl, gpf); + } + } + + /* return frame state and DB to original state */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); +} + +static bool isDisabled(GpencilModifierData *UNUSED(md), int UNUSED(userRenderParams)) +{ + //MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; + + return false; +} + +static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + MirrorGpencilModifierData *lmd = (MirrorGpencilModifierData *)md; + if (lmd->object != NULL) { + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Mirror Modifier"); + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); + } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Mirror Modifier"); +} + +static void foreachObjectLink( + GpencilModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; + + walk(userData, ob, &mmd->object, IDWALK_CB_NOP); +} + +GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { + /* name */ "Mirror", + /* structName */ "MirrorGpencilModifierData", + /* structSize */ sizeof(MirrorGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ NULL, + /* generateStrokes */ generateStrokes, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c new file mode 100644 index 00000000000..37c8bf0b0f0 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -0,0 +1,285 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilnoise.c + * \ingroup modifiers + */ + +#include + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_rand.h" + +#include "PIL_time.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_object.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->flag |= GP_NOISE_MOD_LOCATION; + gpmd->flag |= GP_NOISE_FULL_STROKE; + gpmd->flag |= GP_NOISE_USE_RANDOM; + gpmd->factor = 0.5f; + gpmd->layername[0] = '\0'; + gpmd->vgname[0] = '\0'; + gpmd->step = 1; + gpmd->scene_frame = -999999; + gpmd->gp_frame = -999999; + + gpmd->vrand1 = 1.0; + gpmd->vrand2 = 1.0; +} + +static void freeData(GpencilModifierData *md) +{ + NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md; + + if (mmd->rng != NULL) { + BLI_rng_free(mmd->rng); + } +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +static bool dependsOnTime(GpencilModifierData *md) +{ + NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md; + return (mmd->flag & GP_NOISE_USE_RANDOM) != 0; +} + +/* aply noise effect based on stroke direction */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *depsgraph, + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md; + bGPDspoint *pt0, *pt1; + MDeformVert *dvert; + float shift, vran, vdir; + float normal[3]; + float vec1[3], vec2[3]; +#if 0 + Scene *scene = DEG_get_evaluated_scene(depsgraph); +#endif + int sc_frame = 0; + int sc_diff = 0; + int vindex = defgroup_name_index(ob, mmd->vgname); + float weight = 1.0f; + + /* Random generator, only init once. */ + if (mmd->rng == NULL) { + uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); + rng_seed ^= GET_UINT_FROM_POINTER(mmd); + mmd->rng = BLI_rng_new(rng_seed); + } + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 3, gpl, gps, + mmd->flag & GP_NOISE_INVERT_LAYER, mmd->flag & GP_NOISE_INVERT_PASS)) + { + return; + } + + sc_frame = (int)DEG_get_ctime(depsgraph); + + zero_v3(vec2); + + /* calculate stroke normal*/ + BKE_gpencil_stroke_normal(gps, normal); + + /* move points */ + for (int i = 0; i < gps->totpoints; i++) { + if (((i == 0) || (i == gps->totpoints - 1)) && ((mmd->flag & GP_NOISE_MOVE_EXTREME) == 0)) { + continue; + } + + /* last point is special */ + if (i == gps->totpoints) { + dvert = &gps->dvert[i - 2]; + pt0 = &gps->points[i - 2]; + pt1 = &gps->points[i - 1]; + } + else { + dvert = &gps->dvert[i - 1]; + pt0 = &gps->points[i - 1]; + pt1 = &gps->points[i]; + + } + + /* verify vertex group */ + weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_NOISE_INVERT_VGROUP) == 0), vindex); + if (weight < 0) { + continue; + } + + /* initial vector (p0 -> p1) */ + sub_v3_v3v3(vec1, &pt1->x, &pt0->x); + vran = len_v3(vec1); + /* vector orthogonal to normal */ + cross_v3_v3v3(vec2, vec1, normal); + normalize_v3(vec2); + /* use random noise */ + if (mmd->flag & GP_NOISE_USE_RANDOM) { + sc_diff = abs(mmd->scene_frame - sc_frame); + /* only recalc if the gp frame change or the number of scene frames is bigger than step */ + if ((!gpl->actframe) || (mmd->gp_frame != gpl->actframe->framenum) || + (sc_diff >= mmd->step)) + { + vran = mmd->vrand1 = BLI_rng_get_float(mmd->rng); + vdir = mmd->vrand2 = BLI_rng_get_float(mmd->rng); + mmd->gp_frame = gpl->actframe->framenum; + mmd->scene_frame = sc_frame; + } + else { + vran = mmd->vrand1; + if (mmd->flag & GP_NOISE_FULL_STROKE) { + vdir = mmd->vrand2; + } + else { + int f = (mmd->vrand2 * 10.0f) + i; + vdir = f % 2; + } + } + } + else { + vran = 1.0f; + if (mmd->flag & GP_NOISE_FULL_STROKE) { + vdir = gps->totpoints % 2; + } + else { + vdir = i % 2; + } + mmd->gp_frame = -999999; + } + + /* apply randomness to location of the point */ + if (mmd->flag & GP_NOISE_MOD_LOCATION) { + /* factor is too sensitive, so need divide */ + shift = ((vran * mmd->factor) / 1000.0f) * weight; + if (vdir > 0.5f) { + mul_v3_fl(vec2, shift); + } + else { + mul_v3_fl(vec2, shift * -1.0f); + } + add_v3_v3(&pt1->x, vec2); + } + + /* apply randomness to thickness */ + if (mmd->flag & GP_NOISE_MOD_THICKNESS) { + if (vdir > 0.5f) { + pt1->pressure -= pt1->pressure * vran * mmd->factor; + } + else { + pt1->pressure += pt1->pressure * vran * mmd->factor; + } + CLAMP_MIN(pt1->pressure, GPENCIL_STRENGTH_MIN); + } + + /* apply randomness to color strength */ + if (mmd->flag & GP_NOISE_MOD_STRENGTH) { + if (vdir > 0.5f) { + pt1->strength -= pt1->strength * vran * mmd->factor; + } + else { + pt1->strength += pt1->strength * vran * mmd->factor; + } + CLAMP_MIN(pt1->strength, GPENCIL_STRENGTH_MIN); + } + /* apply randomness to uv rotation */ + if (mmd->flag & GP_NOISE_MOD_UV) { + if (vdir > 0.5f) { + pt1->uv_rot -= pt1->uv_rot * vran * mmd->factor; + } + else { + pt1->uv_rot += pt1->uv_rot * vran * mmd->factor; + } + CLAMP(pt1->uv_rot, -M_PI_2, M_PI_2); + } + } +} + +static void bakeModifier( + struct Main *UNUSED(bmain), Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Noise = { + /* name */ "Noise", + /* structName */ "NoiseGpencilModifierData", + /* structSize */ sizeof(NoiseGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ dependsOnTime, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c new file mode 100644 index 00000000000..8a96c705f08 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -0,0 +1,143 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpenciloffset.c + * \ingroup modifiers + */ + +#include + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_utildefines.h" +#include "BLI_math.h" + +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + OffsetGpencilModifierData *gpmd = (OffsetGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->layername[0] = '\0'; + gpmd->vgname[0] = '\0'; + ARRAY_SET_ITEMS(gpmd->loc, 0.0f, 0.0f, 0.0f); + ARRAY_SET_ITEMS(gpmd->rot, 0.0f, 0.0f, 0.0f); + ARRAY_SET_ITEMS(gpmd->scale, 0.0f, 0.0f, 0.0f); +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +/* change stroke offsetness */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + OffsetGpencilModifierData *mmd = (OffsetGpencilModifierData *)md; + int vindex = defgroup_name_index(ob, mmd->vgname); + + float mat[4][4]; + float loc[3], rot[3], scale[3]; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 1, gpl, gps, + mmd->flag & GP_OFFSET_INVERT_LAYER, mmd->flag & GP_OFFSET_INVERT_PASS)) + { + return; + } + + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + /* verify vertex group */ + float weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_OFFSET_INVERT_VGROUP) == 0), vindex); + if (weight < 0) { + continue; + } + /* calculate matrix */ + mul_v3_v3fl(loc, mmd->loc, weight); + mul_v3_v3fl(rot, mmd->rot, weight); + mul_v3_v3fl(scale, mmd->scale, weight); + add_v3_fl(scale, 1.0); + loc_eul_size_to_mat4(mat, loc, rot, scale); + + mul_m4_v3(mat, &pt->x); + } +} + +static void bakeModifier( + struct Main *UNUSED(bmain), Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Offset = { + /* name */ "Offset", + /* structName */ "OffsetGpencilModifierData", + /* structSize */ sizeof(OffsetGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c new file mode 100644 index 00000000000..bdd651a69fc --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -0,0 +1,171 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilopacity.c + * \ingroup modifiers + */ + +#include + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_material.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->factor = 1.0f; + gpmd->layername[0] = '\0'; + gpmd->vgname[0] = '\0'; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +/* opacity strokes */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md; + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + int vindex = defgroup_name_index(ob, mmd->vgname); + + if (!is_stroke_affected_by_modifier( + ob, + mmd->layername, mmd->pass_index, 3, gpl, gps, + mmd->flag & GP_OPACITY_INVERT_LAYER, mmd->flag & GP_OPACITY_INVERT_PASS)) + { + return; + } + + gp_style->fill_rgba[3]*= mmd->factor; + + /* if factor is > 1, then force opacity */ + if (mmd->factor > 1.0f) { + gp_style->stroke_rgba[3] += mmd->factor - 1.0f; + if (gp_style->fill_rgba[3] > 1e-5) { + gp_style->fill_rgba[3] += mmd->factor - 1.0f; + } + } + + CLAMP(gp_style->stroke_rgba[3], 0.0f, 1.0f); + CLAMP(gp_style->fill_rgba[3], 0.0f, 1.0f); + + /* if opacity > 1.0, affect the strength of the stroke */ + if (mmd->factor > 1.0f) { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + /* verify vertex group */ + float weight = get_modifier_point_weight(dvert, (!(mmd->flag & GP_OPACITY_INVERT_VGROUP) == 0), vindex); + if (weight < 0) { + pt->strength += mmd->factor - 1.0f; + } + else { + pt->strength += (mmd->factor - 1.0f) * weight; + } + CLAMP(pt->strength, 0.0f, 1.0f); + } + } + else { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + /* verify vertex group */ + if (mmd->vgname == NULL) { + pt->strength *= mmd->factor; + } + else { + float weight = get_modifier_point_weight(dvert, (!(mmd->flag & GP_OPACITY_INVERT_VGROUP) == 0), vindex); + if (weight >= 0) { + pt->strength *= mmd->factor * weight; + } + } + CLAMP(pt->strength, 0.0f, 1.0f); + } + } + +} + +static void bakeModifier( + struct Main *UNUSED(bmain), Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { + /* name */ "Opacity", + /* structName */ "OpacityGpencilModifierData", + /* structSize */ sizeof(OpacityGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c new file mode 100644 index 00000000000..f0400e39b73 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -0,0 +1,123 @@ +/* ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilsimplify.c + * \ingroup modifiers + */ + +#include + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_vec_types.h" + +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + SimplifyGpencilModifierData *gpmd = (SimplifyGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->step = 1; + gpmd->factor = 0.0f; + gpmd->layername[0] = '\0'; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + SimplifyGpencilModifierData *mmd = (SimplifyGpencilModifierData *)md; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 4, gpl, gps, + mmd->flag & GP_SIMPLIFY_INVERT_LAYER, mmd->flag & GP_SIMPLIFY_INVERT_PASS)) + { + return; + } + + if (mmd->mode == GP_SIMPLIFY_FIXED) { + for (int i = 0; i < mmd->step; i++) { + BKE_gpencil_simplify_fixed(gps); + } + } + else { + /* simplify stroke using Ramer-Douglas-Peucker algorithm */ + BKE_gpencil_simplify_stroke(gps, mmd->factor); + } +} + +static void bakeModifier( + struct Main *UNUSED(bmain), Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Simplify = { + /* name */ "Simplify", + /* structName */ "SimplifyGpencilModifierData", + /* structSize */ sizeof(SimplifyGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c new file mode 100644 index 00000000000..b83c8ed98b1 --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -0,0 +1,152 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilsmooth.c + * \ingroup modifiers + */ + +#include + +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->flag |= GP_SMOOTH_MOD_LOCATION; + gpmd->factor = 0.5f; + gpmd->layername[0] = '\0'; + gpmd->vgname[0] = '\0'; + gpmd->step = 1; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +/* aply smooth effect based on stroke direction */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md; + int vindex = defgroup_name_index(ob, mmd->vgname); + float weight = 1.0f; + float val; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 3, gpl, gps, + mmd->flag & GP_SMOOTH_INVERT_LAYER, mmd->flag & GP_SMOOTH_INVERT_PASS)) + { + return; + } + + /* smooth stroke */ + if (mmd->factor > 0.0f) { + for (int r = 0; r < mmd->step; r++) { + for (int i = 0; i < gps->totpoints; i++) { + // bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + + /* verify vertex group */ + weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_SMOOTH_INVERT_VGROUP) == 0), vindex); + if (weight < 0) { + continue; + } + + val = mmd->factor * weight; + /* perform smoothing */ + if (mmd->flag & GP_SMOOTH_MOD_LOCATION) { + BKE_gpencil_smooth_stroke(gps, i, val); + } + if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) { + BKE_gpencil_smooth_stroke_strength(gps, i, val); + } + if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0)) { + /* thickness need to repeat process several times */ + for (int r2 = 0; r2 < r * 10; r2++) { + BKE_gpencil_smooth_stroke_thickness(gps, i, val); + } + } + if (mmd->flag & GP_SMOOTH_MOD_UV) { + BKE_gpencil_smooth_stroke_uv(gps, i, val); + } + } + } + } +} + +static void bakeModifier( + struct Main *UNUSED(bmain), Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { + /* name */ "Smooth", + /* structName */ "SmoothGpencilModifierData", + /* structSize */ sizeof(SmoothGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c new file mode 100644 index 00000000000..6fe9c34c06b --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -0,0 +1,193 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilsubdiv.c + * \ingroup modifiers + */ + +#include + +#include "MEM_guardedalloc.h" + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + SubdivGpencilModifierData *gpmd = (SubdivGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->level = 1; + gpmd->layername[0] = '\0'; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +/* subdivide stroke to get more control points */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md; + bGPDspoint *temp_points; + int totnewpoints, oldtotpoints; + int i2; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 3, gpl, gps, + mmd->flag & GP_SUBDIV_INVERT_LAYER, mmd->flag & GP_SUBDIV_INVERT_PASS)) + { + return; + } + + /* loop as many times as levels */ + for (int s = 0; s < mmd->level; s++) { + totnewpoints = gps->totpoints - 1; + /* duplicate points in a temp area */ + temp_points = MEM_dupallocN(gps->points); + oldtotpoints = gps->totpoints; + + /* resize the points arrys */ + gps->totpoints += totnewpoints; + gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + gps->flag |= GP_STROKE_RECALC_CACHES; + + /* move points from last to first to new place */ + i2 = gps->totpoints - 1; + for (int i = oldtotpoints - 1; i > 0; i--) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *pt_final = &gps->points[i2]; + + MDeformVert *dvert = &gps->dvert[i]; + MDeformVert *dvert_final = &gps->dvert[i2]; + + copy_v3_v3(&pt_final->x, &pt->x); + pt_final->pressure = pt->pressure; + pt_final->strength = pt->strength; + pt_final->time = pt->time; + pt_final->flag = pt->flag; + + dvert_final->totweight = dvert->totweight; + dvert_final->dw = dvert->dw; + i2 -= 2; + } + /* interpolate mid points */ + i2 = 1; + for (int i = 0; i < oldtotpoints - 1; i++) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *next = &temp_points[i + 1]; + bGPDspoint *pt_final = &gps->points[i2]; + MDeformVert *dvert_final = &gps->dvert[i2]; + + /* add a half way point */ + interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); + pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f); + pt_final->strength = interpf(pt->strength, next->strength, 0.5f); + CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); + pt_final->time = interpf(pt->time, next->time, 0.5f); + + dvert_final->totweight = 0; + dvert_final->dw = NULL; + i2 += 2; + } + + MEM_SAFE_FREE(temp_points); + + /* move points to smooth stroke (not simple flag )*/ + if ((mmd->flag & GP_SUBDIV_SIMPLE) == 0) { + /* duplicate points in a temp area with the new subdivide data */ + temp_points = MEM_dupallocN(gps->points); + + /* extreme points are not changed */ + for (int i = 0; i < gps->totpoints - 2; i++) { + bGPDspoint *pt = &temp_points[i]; + bGPDspoint *next = &temp_points[i + 1]; + bGPDspoint *pt_final = &gps->points[i + 1]; + + /* move point */ + interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f); + } + /* free temp memory */ + MEM_SAFE_FREE(temp_points); + } + } +} + +static void bakeModifier( + struct Main *UNUSED(bmain), Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { + /* name */ "Subdivision", + /* structName */ "SubdivGpencilModifierData", + /* structSize */ sizeof(SubdivGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c new file mode 100644 index 00000000000..118cc33255f --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -0,0 +1,171 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpencilthick.c + * \ingroup modifiers + */ + +#include + +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_utildefines.h" + +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->thickness = 0; + gpmd->layername[0] = '\0'; + gpmd->vgname[0] = '\0'; + gpmd->curve_thickness = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curve_thickness) { + curvemapping_initialize(gpmd->curve_thickness); + } +} + +static void freeData(GpencilModifierData *md) +{ + ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; + + if (gpmd->curve_thickness) { + curvemapping_free(gpmd->curve_thickness); + } +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + ThickGpencilModifierData *gmd = (ThickGpencilModifierData *)md; + ThickGpencilModifierData *tgmd = (ThickGpencilModifierData *)target; + + if (tgmd->curve_thickness != NULL) { + curvemapping_free(tgmd->curve_thickness); + tgmd->curve_thickness = NULL; + } + + BKE_gpencil_modifier_copyData_generic(md, target); + + tgmd->curve_thickness = curvemapping_copy(gmd->curve_thickness); +} + +/* change stroke thickness */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + ThickGpencilModifierData *mmd = (ThickGpencilModifierData *)md; + int vindex = defgroup_name_index(ob, mmd->vgname); + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 3, gpl, gps, + mmd->flag & GP_THICK_INVERT_LAYER, mmd->flag & GP_THICK_INVERT_PASS)) + { + return; + } + + /* if normalize, set stroke thickness */ + if (mmd->flag & GP_THICK_NORMALIZE) { + gps->thickness = mmd->thickness; + } + + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = &gps->dvert[i]; + float curvef = 1.0f; + /* verify vertex group */ + float weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_THICK_INVERT_VGROUP) == 0), vindex); + if (weight < 0) { + continue; + } + + if (mmd->flag & GP_THICK_NORMALIZE) { + pt->pressure = 1.0f; + } + else { + if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) { + /* normalize value to evaluate curve */ + float value = (float)i / (gps->totpoints - 1); + curvef = curvemapping_evaluateF(mmd->curve_thickness, 0, value); + } + + pt->pressure += mmd->thickness * weight * curvef; + CLAMP(pt->strength, 0.0f, 1.0f); + } + } +} + +static void bakeModifier( + struct Main *UNUSED(bmain), Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + bGPdata *gpd = ob->data; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Thick = { + /* name */ "Thickness", + /* structName */ "ThickGpencilModifierData", + /* structSize */ sizeof(ThickGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ freeData, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c new file mode 100644 index 00000000000..9d1e9eccb8c --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -0,0 +1,186 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/modifiers/intern/MOD_gpenciltint.c + * \ingroup modifiers + */ + +#include + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_math_vector.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_material.h" +#include "BKE_main.h" + +#include "DEG_depsgraph.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +static void initData(GpencilModifierData *md) +{ + TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->factor = 0.5f; + gpmd->layername[0] = '\0'; + ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f); + gpmd->flag |= GP_TINT_CREATE_COLORS; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +/* tint strokes */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *gpl, bGPDstroke *gps) +{ + TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, mmd->pass_index, 1, gpl, gps, + mmd->flag & GP_TINT_INVERT_LAYER, mmd->flag & GP_TINT_INVERT_PASS)) + { + return; + } + + interp_v3_v3v3(gps->runtime.tmp_stroke_rgba, gps->runtime.tmp_stroke_rgba, mmd->rgb, mmd->factor); + interp_v3_v3v3(gps->runtime.tmp_fill_rgba, gps->runtime.tmp_fill_rgba, mmd->rgb, mmd->factor); + + /* if factor is > 1, the alpha must be changed to get full tint */ + if (mmd->factor > 1.0f) { + gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f; + if (gps->runtime.tmp_fill_rgba[3] > 1e-5) { + gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f; + } + } + + CLAMP4(gps->runtime.tmp_stroke_rgba, 0.0f, 1.0f); + CLAMP4(gps->runtime.tmp_fill_rgba, 0.0f, 1.0f); + + /* if factor > 1.0, affect the strength of the stroke */ + if (mmd->factor > 1.0f) { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + pt->strength += mmd->factor - 1.0f; + CLAMP(pt->strength, 0.0f, 1.0f); + } + } +} + +static void bakeModifier( + Main *bmain, Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + bGPdata *gpd = ob->data; + + GHash *gh_color = BLI_ghash_str_new("GP_Tint modifier"); + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + + Material *mat = give_current_material(ob, gps->mat_nr + 1); + if (mat == NULL) + continue; + MaterialGPencilStyle *gp_style = mat->gp_style; + /* skip stroke if it doesn't have color info */ + if (ELEM(NULL, gp_style)) + continue; + + copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); + copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); + + /* look for color */ + if (mmd->flag & GP_TINT_CREATE_COLORS) { + Material *newmat = (Material *)BLI_ghash_lookup(gh_color, mat->id.name); + if (newmat == NULL) { + BKE_object_material_slot_add(bmain, ob); + newmat = BKE_material_copy(bmain, mat); + assign_material(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_EXISTING); + + copy_v4_v4(newmat->gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba); + copy_v4_v4(newmat->gp_style->fill_rgba, gps->runtime.tmp_fill_rgba); + + BLI_ghash_insert(gh_color, mat->id.name, newmat); + } + /* reasign color index */ + int idx = BKE_object_material_slot_find_index(ob, newmat); + gps->mat_nr = idx - 1; + } + else { + /* reuse existing color */ + copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba); + copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba); + } + + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } + /* free hash buffers */ + if (gh_color) { + BLI_ghash_free(gh_color, NULL, NULL); + gh_color = NULL; + } +} + +GpencilModifierTypeInfo modifierType_Gpencil_Tint = { + /* name */ "Tint", + /* structName */ "TintGpencilModifierData", + /* structSize */ sizeof(TintGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 8273f3f1992..b9cc1de447f 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -260,6 +260,14 @@ data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_gpencil_stroke_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_gpencil_stroke_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_gpencil_stroke_geom.glsl SRC) + +data_to_c_simple(shaders/gpu_shader_gpencil_fill_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC) + + if(WITH_MOD_SMOKE) add_definitions(-DWITH_SMOKE) endif() diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 7f334cec21f..704abdb13a1 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -346,7 +346,10 @@ typedef enum GPUBuiltinShader { GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, /* Uniformly scaled */ GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE, GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR, - /* specialized for UI drawing */ + /* grease pencil drawing */ + GPU_SHADER_GPENCIL_STROKE, + GPU_SHADER_GPENCIL_FILL, + /* specialized for widget drawing */ GPU_SHADER_2D_WIDGET_BASE, GPU_SHADER_2D_WIDGET_BASE_INST, GPU_SHADER_2D_WIDGET_SHADOW, diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 3543c73f71d..0d5183d82ab 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -162,6 +162,13 @@ extern char datatoc_gpu_shader_vsm_store_frag_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_vert_glsl[]; extern char datatoc_gpu_shader_sep_gaussian_blur_frag_glsl[]; +extern char datatoc_gpu_shader_gpencil_stroke_vert_glsl[]; +extern char datatoc_gpu_shader_gpencil_stroke_frag_glsl[]; +extern char datatoc_gpu_shader_gpencil_stroke_geom_glsl[]; + +extern char datatoc_gpu_shader_gpencil_fill_vert_glsl[]; +extern char datatoc_gpu_shader_gpencil_fill_frag_glsl[]; + /* cache of built-in shaders (each is created on first use) */ static GPUShader *builtin_shaders[GPU_NUM_BUILTIN_SHADERS] = { NULL }; @@ -868,6 +875,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) datatoc_gpu_shader_2D_nodelink_frag_glsl }, [GPU_SHADER_2D_NODELINK_INST] = { datatoc_gpu_shader_2D_nodelink_vert_glsl, datatoc_gpu_shader_2D_nodelink_frag_glsl }, + + [GPU_SHADER_GPENCIL_STROKE] = { datatoc_gpu_shader_gpencil_stroke_vert_glsl, + datatoc_gpu_shader_gpencil_stroke_frag_glsl, + datatoc_gpu_shader_gpencil_stroke_geom_glsl }, + + [GPU_SHADER_GPENCIL_FILL] = { datatoc_gpu_shader_gpencil_fill_vert_glsl, + datatoc_gpu_shader_gpencil_fill_frag_glsl }, }; if (builtin_shaders[shader] == NULL) { diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl new file mode 100644 index 00000000000..328fbbe26a1 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_frag.glsl @@ -0,0 +1,166 @@ +uniform vec4 color; +uniform vec4 color2; +uniform int fill_type; +uniform float mix_factor; + +uniform float g_angle; +uniform float g_radius; +uniform float g_boxsize; +uniform vec2 g_scale; +uniform vec2 g_shift; + +uniform float t_angle; +uniform vec2 t_scale; +uniform vec2 t_offset; +uniform int t_mix; +uniform int t_flip; +uniform float t_opacity; + +uniform sampler2D myTexture; + +/* keep this list synchronized with list in DNA_brush_types.h */ +#define SOLID 0 +#define GRADIENT 1 +#define RADIAL 2 +#define CHESS 3 +#define TEXTURE 4 + +in vec2 texCoord_interp; +out vec4 fragColor; +#define texture2D texture + +void set_color(in vec4 color, in vec4 color2, in vec4 tcolor, in float mixv, in float factor, + in int tmix, in int flip, out vec4 ocolor) +{ + /* full color A */ + if (mixv == 1.0) { + if (tmix == 1) { + if (flip == 0) { + ocolor = color; + } + else { + ocolor = tcolor; + } + } + else { + if (flip == 0) { + ocolor = color; + } + else { + ocolor = color2; + } + } + } + /* full color B */ + else if (mixv == 0.0) { + if (tmix == 1) { + if (flip == 0) { + ocolor = tcolor; + } + else { + ocolor = color; + } + } + else { + if (flip == 0) { + ocolor = color2; + } + else { + ocolor = color; + } + } + } + /* mix of colors */ + else { + if (tmix == 1) { + if (flip == 0) { + ocolor = mix(color, tcolor, factor); + } + else { + ocolor = mix(tcolor, color, factor); + } + } + else { + if (flip == 0) { + ocolor = mix(color, color2, factor); + } + else { + ocolor = mix(color2, color, factor); + } + } + } +} + +void main() +{ + vec2 t_center = vec2(0.5, 0.5); + mat2 matrot_tex = mat2(cos(t_angle), -sin(t_angle), sin(t_angle), cos(t_angle)); + vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + t_offset; + vec4 tmp_color = texture2D(myTexture, rot_tex * t_scale); + vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * t_opacity); + vec4 chesscolor; + + /* solid fill */ + if (fill_type == SOLID) { + if (t_mix == 1) { + fragColor = mix(color, text_color, mix_factor); + } + else { + fragColor = color; + } + } + else { + vec2 center = vec2(0.5, 0.5) + g_shift; + mat2 matrot = mat2(cos(g_angle), -sin(g_angle), sin(g_angle), cos(g_angle)); + vec2 rot = (((matrot * (texCoord_interp - center)) + center) * g_scale) + g_shift; + /* gradient */ + if (fill_type == GRADIENT) { + set_color(color, color2, text_color, mix_factor, rot.x - mix_factor + 0.5, t_mix, t_flip, fragColor); + } + /* radial gradient */ + if (fill_type == RADIAL) { + float in_rad = g_radius * mix_factor; + float ex_rad = g_radius - in_rad; + float intensity = 0; + float distance = length((center - texCoord_interp) * g_scale); + if (distance > g_radius) { + discard; + } + if (distance > in_rad) { + intensity = clamp(((distance - in_rad) / ex_rad), 0.0, 1.0); + } + set_color(color, color2, text_color, mix_factor, intensity, t_mix, t_flip, fragColor); + } + /* chessboard */ + if (fill_type == CHESS) { + vec2 pos = rot / g_boxsize; + if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) || (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) { + if (t_flip == 0) { + chesscolor = color; + } + else { + chesscolor = color2; + } + } + else { + if (t_flip == 0) { + chesscolor = color2; + } + else { + chesscolor = color; + } + } + /* mix with texture */ + if (t_mix == 1) { + fragColor = mix(chesscolor, text_color, mix_factor); + } + else { + fragColor = chesscolor; + } + } + /* texture */ + if (fill_type == TEXTURE) { + fragColor = text_color; + } + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl new file mode 100644 index 00000000000..2bc381a3689 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_fill_vert.glsl @@ -0,0 +1,11 @@ +uniform mat4 ModelViewProjectionMatrix; + +in vec3 pos; +in vec2 texCoord; +out vec2 texCoord_interp; + +void main(void) +{ + gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 ); + texCoord_interp = texCoord; +} diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl new file mode 100644 index 00000000000..7bb7693d202 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_frag.glsl @@ -0,0 +1,20 @@ +in vec4 mColor; +in vec2 mTexCoord; + +out vec4 fragColor; + +void main() +{ + const vec2 center = vec2(0, 0.5); + vec4 tColor = vec4(mColor); + /* if alpha < 0, then encap */ + if (mColor.a < 0) { + tColor.a = tColor.a * -1.0; + float dist = length(mTexCoord - center); + if (dist > 0.25) { + discard; + } + } + /* Solid */ + fragColor = tColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl new file mode 100644 index 00000000000..3de1bd838b3 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl @@ -0,0 +1,196 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform vec2 Viewport; +uniform int xraymode; + +layout(lines_adjacency) in; +layout(triangle_strip, max_vertices = 13) out; + +in vec4 finalColor[4]; +in float finalThickness[4]; + +out vec4 mColor; +out vec2 mTexCoord; + +#define GP_XRAY_FRONT 0 +#define GP_XRAY_3DSPACE 1 +#define GP_XRAY_BACK 2 + +/* project 3d point to 2d on screen space */ +vec2 toScreenSpace(vec4 vertex) +{ + return vec2(vertex.xy / vertex.w) * Viewport; +} + +/* get zdepth value */ +float getZdepth(vec4 point) +{ + if (xraymode == GP_XRAY_FRONT) { + return 0.0; + } + if (xraymode == GP_XRAY_3DSPACE) { + return (point.z / point.w); + } + if (xraymode == GP_XRAY_BACK) { + return 1.0; + } + + /* in front by default */ + return 0.0; +} +void main(void) +{ + float MiterLimit = 0.75; + + /* receive 4 points */ + vec4 P0 = gl_in[0].gl_Position; + vec4 P1 = gl_in[1].gl_Position; + vec4 P2 = gl_in[2].gl_Position; + vec4 P3 = gl_in[3].gl_Position; + + /* get the four vertices passed to the shader */ + vec2 sp0 = toScreenSpace(P0); // start of previous segment + vec2 sp1 = toScreenSpace(P1); // end of previous segment, start of current segment + vec2 sp2 = toScreenSpace(P2); // end of current segment, start of next segment + vec2 sp3 = toScreenSpace(P3); // end of next segment + + /* culling outside viewport */ + vec2 area = Viewport * 4.0; + if (sp1.x < -area.x || sp1.x > area.x) return; + if (sp1.y < -area.y || sp1.y > area.y) return; + if (sp2.x < -area.x || sp2.x > area.x) return; + if (sp2.y < -area.y || sp2.y > area.y) return; + + /* determine the direction of each of the 3 segments (previous, current, next) */ + vec2 v0 = normalize(sp1 - sp0); + vec2 v1 = normalize(sp2 - sp1); + vec2 v2 = normalize(sp3 - sp2); + + /* determine the normal of each of the 3 segments (previous, current, next) */ + vec2 n0 = vec2(-v0.y, v0.x); + vec2 n1 = vec2(-v1.y, v1.x); + vec2 n2 = vec2(-v2.y, v2.x); + + /* determine miter lines by averaging the normals of the 2 segments */ + vec2 miter_a = normalize(n0 + n1); // miter at start of current segment + vec2 miter_b = normalize(n1 + n2); // miter at end of current segment + + /* determine the length of the miter by projecting it onto normal and then inverse it */ + float an1 = dot(miter_a, n1); + float bn1 = dot(miter_b, n2); + if (an1 == 0) an1 = 1; + if (bn1 == 0) bn1 = 1; + float length_a = finalThickness[1] / an1; + float length_b = finalThickness[2] / bn1; + if (length_a <= 0.0) length_a = 0.01; + if (length_b <= 0.0) length_b = 0.01; + + /* prevent excessively long miters at sharp corners */ + if (dot(v0, v1) < -MiterLimit) { + miter_a = n1; + length_a = finalThickness[1]; + + /* close the gap */ + if (dot(v0, n1) > 0) { + mTexCoord = vec2(0, 0); + mColor = finalColor[1]; + gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0); + mColor = finalColor[1]; + gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0.5); + mColor = finalColor[1]; + gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + EndPrimitive(); + } + else { + mTexCoord = vec2(0, 1); + mColor = finalColor[1]; + gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 1); + mColor = finalColor[1]; + gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0.5); + mColor = finalColor[1]; + gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + EndPrimitive(); + } + } + + if (dot(v1, v2) < -MiterLimit) { + miter_b = n1; + length_b = finalThickness[2]; + } + + /* generate the start endcap (alpha < 0 used as endcap flag)*/ + if (P0 == P2) { + mTexCoord = vec2(1, 0.5); + mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; + vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0; + gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0); + mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; + gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 1); + mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; + gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + } + + /* generate the triangle strip */ + mTexCoord = vec2(0, 0); + mColor = finalColor[1]; + gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 1); + mColor = finalColor[1]; + gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0); + mColor = finalColor[2]; + gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 1); + mColor = finalColor[2]; + gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + /* generate the end endcap (alpha < 0 used as endcap flag)*/ + if (P1 == P3) { + mTexCoord = vec2(0, 1); + mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; + gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + mTexCoord = vec2(0, 0); + mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; + gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + + mTexCoord = vec2(1, 0.5); + mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; + vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0; + gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0); + EmitVertex(); + } + + EndPrimitive(); +} diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl new file mode 100644 index 00000000000..5f4f56dcca1 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl @@ -0,0 +1,33 @@ +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ProjectionMatrix; + +uniform float pixsize; /* rv3d->pixsize */ +uniform float pixelsize; /* U.pixelsize */ +uniform int keep_size; +uniform float objscale; +uniform int pixfactor; + +in vec3 pos; +in vec4 color; +in float thickness; + +out vec4 finalColor; +out float finalThickness; + +#define TRUE 1 + +float defaultpixsize = pixsize * pixelsize * (1000.0 / pixfactor); + +void main(void) +{ + gl_Position = ModelViewProjectionMatrix * vec4( pos, 1.0 ); + finalColor = color; + + if (keep_size == TRUE) { + finalThickness = thickness; + } + else { + float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) : (thickness / defaultpixsize); + finalThickness = max(size * objscale, 1.0); + } +} diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index ec71f28cb23..634819b33ce 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -564,6 +564,7 @@ enum { INDEX_ID_IP, INDEX_ID_AC, INDEX_ID_KE, + INDEX_ID_PAL, INDEX_ID_GD, INDEX_ID_NT, INDEX_ID_IM, @@ -581,7 +582,6 @@ enum { INDEX_ID_TXT, INDEX_ID_SO, INDEX_ID_GR, - INDEX_ID_PAL, INDEX_ID_PC, INDEX_ID_BR, INDEX_ID_PA, diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index fc3b4afe18d..dcb7fbd344b 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -44,6 +44,7 @@ struct CurveMapping; struct MTex; struct Image; +struct Material; typedef struct BrushClone { struct Image *image; /* image for clone tool */ @@ -51,6 +52,109 @@ typedef struct BrushClone { float alpha, pad; /* transparency for drawing of clone image */ } BrushClone; + +typedef struct BrushGpencilSettings { + float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */ + float draw_sensitivity; /* amount of sensivity to apply to newly created strokes */ + float draw_strength; /* amount of alpha strength to apply to newly created strokes */ + float draw_jitter; /* amount of jitter to apply to newly created strokes */ + float draw_angle; /* angle when the brush has full thickness */ + float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */ + float draw_random_press; /* factor of randomness for pressure */ + float draw_random_strength; /* factor of strength for strength */ + float draw_random_sub; /* factor of randomness for subdivision */ + short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */ + short draw_subdivide; /* number of times to subdivide new strokes */ + short flag; /* internal grease pencil drawing flags */ + + short thick_smoothlvl; /* number of times to apply thickness smooth factor to new strokes */ + float thick_smoothfac; /* amount of thickness smoothing to apply to newly created strokes */ + + float fill_threshold; /* factor for transparency */ + short fill_leak; /* number of pixel to consider the leak is too small (x 2) */ + char pad_1[6]; + + int fill_simplylvl; /* number of simplify steps */ + int fill_draw_mode; /* type of control lines drawing mode */ + int icon_id; /* icon identifier */ + + int input_samples; /* maximum distance before generate new point for very fast mouse movements */ + float uv_random; /* random factor for UV rotation */ + + int brush_type; /* type of brush (draw, fill, erase, etc..) */ + int eraser_mode; /* soft, hard or stroke */ + float active_smooth; /* smooth while drawing factor */ + char pad_2[4]; + + struct CurveMapping *curve_sensitivity; + struct CurveMapping *curve_strength; + struct CurveMapping *curve_jitter; + + /* optional link of material to replace default in context */ + struct Material *material; /* material */ +} BrushGpencilSettings; + +/* BrushGpencilSettings->gp_flag */ +typedef enum eGPDbrush_Flag { + /* brush use pressure */ + GP_BRUSH_USE_PRESSURE = (1 << 0), + /* brush use pressure for alpha factor */ + GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 1), + /* brush use pressure for alpha factor */ + GP_BRUSH_USE_JITTER_PRESSURE = (1 << 2), + /* enable screen cursor */ + GP_BRUSH_ENABLE_CURSOR = (1 << 5), + /* fill hide transparent */ + GP_BRUSH_FILL_HIDE = (1 << 6), + /* show fill help lines */ + GP_BRUSH_FILL_SHOW_HELPLINES = (1 << 7), + /* lazy mouse */ + GP_BRUSH_STABILIZE_MOUSE = (1 << 8), + /* lazy mouse override (internal only) */ + GP_BRUSH_STABILIZE_MOUSE_TEMP = (1 << 9), + /* default eraser brush for quick switch */ + GP_BRUSH_DEFAULT_ERASER = (1 << 10), + /* settings group */ + GP_BRUSH_GROUP_SETTINGS = (1 << 11), + /* Random settings group */ + GP_BRUSH_GROUP_RANDOM = (1 << 12) +} eGPDbrush_Flag; + +/* BrushGpencilSettings->gp_fill_draw_mode */ +typedef enum eGP_FillDrawModes { + GP_FILL_DMODE_BOTH = 0, + GP_FILL_DMODE_STROKE = 1, + GP_FILL_DMODE_CONTROL = 2, +} eGP_FillDrawModes; + +/* BrushGpencilSettings->brush type */ +typedef enum eGP_BrushType { + GP_BRUSH_TYPE_DRAW = 0, + GP_BRUSH_TYPE_FILL = 1, + GP_BRUSH_TYPE_ERASE = 2, +} eGP_BrushType; + +/* BrushGpencilSettings->gp_eraser_mode */ +typedef enum eGP_BrushEraserMode { + GP_BRUSH_ERASER_SOFT = 0, + GP_BRUSH_ERASER_HARD = 1, + GP_BRUSH_ERASER_STROKE = 2, +} eGP_BrushEraserMode; + +/* BrushGpencilSettings default brush icons */ +typedef enum eGP_BrushIcons { + GP_BRUSH_ICON_PENCIL = 1, + GP_BRUSH_ICON_PEN = 2, + GP_BRUSH_ICON_INK = 3, + GP_BRUSH_ICON_INKNOISE = 4, + GP_BRUSH_ICON_BLOCK = 5, + GP_BRUSH_ICON_MARKER = 6, + GP_BRUSH_ICON_FILL = 7, + GP_BRUSH_ICON_ERASE_SOFT = 8, + GP_BRUSH_ICON_ERASE_HARD = 9, + GP_BRUSH_ICON_ERASE_STROKE = 10 +} eGP_BrushIcons; + typedef struct Brush { ID id; @@ -139,8 +243,10 @@ typedef struct Brush { float mask_stencil_pos[2]; float mask_stencil_dimension[2]; -} Brush; + struct BrushGpencilSettings *gpencil_settings; + +} Brush; typedef struct PaletteColor { struct PaletteColor *next, *prev; /* two values, one to store rgb, other to store values for sculpt/weight */ @@ -355,5 +461,6 @@ enum { }; #define MAX_BRUSH_PIXEL_RADIUS 500 +#define GP_MAX_BRUSH_PIXEL_RADIUS 1000 #endif /* __DNA_BRUSH_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index 8ed38b0b05d..4f860e16b88 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -99,6 +99,7 @@ typedef enum eCurveMappingPreset { CURVE_PRESET_MID9 = 4, CURVE_PRESET_ROUND = 5, CURVE_PRESET_ROOT = 6, + CURVE_PRESET_GAUSS = 7, } eCurveMappingPreset; /* histogram->mode */ diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h new file mode 100644 index 00000000000..150b4a2d9f1 --- /dev/null +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -0,0 +1,404 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file DNA_greasepencil_modifier_types.h + * \ingroup DNA + */ + +#ifndef __DNA_GREASEPENCIL_TYPES_H__ +#define __DNA_GREASEPENCIL_TYPES_H__ + +#include "DNA_defs.h" +#include "DNA_listBase.h" + +/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! + * (ONLY ADD NEW ITEMS AT THE END) + */ + +struct RNG; + +typedef enum GpencilModifierType { + eGpencilModifierType_None = 0, + eGpencilModifierType_Noise = 1, + eGpencilModifierType_Subdiv = 2, + eGpencilModifierType_Thick = 3, + eGpencilModifierType_Tint = 4, + eGpencilModifierType_Instance = 5, + eGpencilModifierType_Build = 6, + eGpencilModifierType_Opacity = 7, + eGpencilModifierType_Color = 8, + eGpencilModifierType_Lattice = 9, + eGpencilModifierType_Simplify = 10, + eGpencilModifierType_Smooth = 11, + eGpencilModifierType_Hook = 12, + eGpencilModifierType_Offset = 13, + eGpencilModifierType_Mirror = 14, + NUM_GREASEPENCIL_MODIFIER_TYPES +} GpencilModifierType; + +typedef enum GpencilModifierMode { + eGpencilModifierMode_Realtime = (1 << 0), + eGpencilModifierMode_Render = (1 << 1), + eGpencilModifierMode_Editmode = (1 << 2), + eGpencilModifierMode_Expanded = (1 << 3), +} GpencilModifierMode; + +typedef enum { + /* This modifier has been inserted in local override, and hence can be fully edited. */ + eGpencilModifierFlag_StaticOverride_Local = (1 << 0), +} GpencilModifierFlag; + +typedef struct GpencilModifierData { + struct GpencilModifierData *next, *prev; + + int type, mode; + int stackindex; + short flag; + short pad; + char name[64]; /* MAX_NAME */ + + char *error; +} GpencilModifierData; + +typedef struct NoiseGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + int pass_index; /* custom index for passes */ + int flag; /* several flags */ + float factor; /* factor of noise */ + int step; /* how many frames before recalculate randoms */ + int gp_frame; /* last gp frame used */ + int scene_frame; /* last scene frame used */ + float vrand1, vrand2; /* random values */ + struct RNG *rng; +} NoiseGpencilModifierData; + +typedef enum eNoiseGpencil_Flag { + GP_NOISE_USE_RANDOM = (1 << 0), + GP_NOISE_MOD_LOCATION = (1 << 1), + GP_NOISE_MOD_STRENGTH = (1 << 2), + GP_NOISE_MOD_THICKNESS = (1 << 3), + GP_NOISE_FULL_STROKE = (1 << 4), + GP_NOISE_MOVE_EXTREME = (1 << 5), + GP_NOISE_INVERT_LAYER = (1 << 6), + GP_NOISE_INVERT_PASS = (1 << 7), + GP_NOISE_INVERT_VGROUP = (1 << 8), + GP_NOISE_MOD_UV = (1 << 9), +} eNoiseGpencil_Flag; + +typedef struct SubdivGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + int level; /* factor of subdivision */ + char pad[4]; +} SubdivGpencilModifierData; + +typedef enum eSubdivGpencil_Flag { + GP_SUBDIV_SIMPLE = (1 << 0), + GP_SUBDIV_INVERT_LAYER = (1 << 1), + GP_SUBDIV_INVERT_PASS = (1 << 2), +} eSubdivGpencil_Flag; + +typedef struct ThickGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + int thickness; /* Thickness change */ + char pad[4]; + struct CurveMapping *curve_thickness; +} ThickGpencilModifierData; + +typedef enum eThickGpencil_Flag { + GP_THICK_INVERT_LAYER = (1 << 0), + GP_THICK_INVERT_PASS = (1 << 1), + GP_THICK_INVERT_VGROUP = (1 << 2), + GP_THICK_CUSTOM_CURVE = (1 << 3), + GP_THICK_NORMALIZE = (1 << 4), +} eThickGpencil_Flag; + +typedef struct TintGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + float rgb[3]; /* Tint color */ + float factor; /* Mix factor */ +} TintGpencilModifierData; + +typedef enum eTintGpencil_Flag { + GP_TINT_CREATE_COLORS = (1 << 0), + GP_TINT_INVERT_LAYER = (1 << 1), + GP_TINT_INVERT_PASS = (1 << 2), +} eTintGpencil_Flag; + +typedef struct ColorGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + float hsv[3]; /* hsv factors */ + char pad[4]; +} ColorGpencilModifierData; + +typedef enum eColorGpencil_Flag { + GP_COLOR_CREATE_COLORS = (1 << 0), + GP_COLOR_INVERT_LAYER = (1 << 1), + GP_COLOR_INVERT_PASS = (1 << 2), +} eColorGpencil_Flag; + +typedef struct OpacityGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + float factor; /* Main Opacity factor */ + char pad[4]; +} OpacityGpencilModifierData; + +typedef enum eOpacityGpencil_Flag { + GP_OPACITY_INVERT_LAYER = (1 << 0), + GP_OPACITY_INVERT_PASS = (1 << 1), + GP_OPACITY_INVERT_VGROUP = (1 << 2), +} eOpacityGpencil_Flag; + +typedef struct InstanceGpencilModifierData { + GpencilModifierData modifier; + int count[3]; /* number of elements in array */ + int flag; /* several flags */ + float offset[3]; /* Location increments */ + float shift[3]; /* shift increment */ + float rnd_size; /* random size factor */ + float rnd_rot; /* random size factor */ + float rot[3]; /* Rotation changes */ + float scale[3]; /* Scale changes */ + float rnd[20]; /* (first element is the index) random values */ + int lock_axis; /* lock shift to one axis */ + + int pass_index; /* custom index for passes */ + char layername[64]; /* layer name */ +} InstanceGpencilModifierData; + +typedef enum eInstanceGpencil_Flag { + GP_INSTANCE_RANDOM_SIZE = (1 << 0), + GP_INSTANCE_RANDOM_ROT = (1 << 1), + GP_INSTANCE_INVERT_LAYER = (1 << 2), + GP_INSTANCE_INVERT_PASS = (1 << 3), + GP_INSTANCE_MAKE_OBJECTS = (1 << 4), +} eInstanceGpencil_Flag; + +typedef struct BuildGpencilModifierData { + GpencilModifierData modifier; + + char layername[64]; /* if set, restrict modifier to operating on this layer */ + int pass_index; + + int pad; + + float start_frame; /* If GP_BUILD_RESTRICT_TIME is set, the defines the frame range where GP frames are considered */ + float end_frame; + + float start_delay; /* For each pair of gp keys, number of frames before strokes start appearing */ + float length; /* For each pair of gp keys, number of frames that build effect must be completed within */ + + short flag; /* (eGpencilBuild_Flag) Options for controlling modifier behaviour */ + + short mode; /* (eGpencilBuild_Mode) How are strokes ordered */ + short transition; /* (eGpencilBuild_Transition) In what order do stroke points appear/disappear */ + + short time_alignment; /* (eGpencilBuild_TimeAlignment) For the "Concurrent" mode, when should "shorter" strips start/end */ +} BuildGpencilModifierData; + +typedef enum eBuildGpencil_Mode { + /* Strokes are shown one by one until all have appeared */ + GP_BUILD_MODE_SEQUENTIAL = 0, + /* All strokes start at the same time */ + GP_BUILD_MODE_CONCURRENT = 1, +} eBuildGpencil_Mode; + +typedef enum eBuildGpencil_Transition { + /* Show in forward order */ + GP_BUILD_TRANSITION_GROW = 0, + /* Hide in reverse order */ + GP_BUILD_TRANSITION_SHRINK = 1, + /* Hide in forward order */ + GP_BUILD_TRANSITION_FADE = 2, +} eBuildGpencil_Transition; + +typedef enum eBuildGpencil_TimeAlignment { + /* All strokes start at same time */ + GP_BUILD_TIMEALIGN_START = 0, + /* All strokes end at same time */ + GP_BUILD_TIMEALIGN_END = 1, + + /* TODO: Random Offsets, Stretch-to-Fill */ +} eBuildGpencil_TimeAlignment; + +typedef enum eBuildGpencil_Flag { + /* Restrict modifier to particular layer/passes? */ + GP_BUILD_INVERT_LAYER = (1 << 0), + GP_BUILD_INVERT_PASS = (1 << 1), + + /* Restrict modifier to only operating between the nominated frames */ + GP_BUILD_RESTRICT_TIME = (1 << 2), +} eBuildGpencil_Flag; + +typedef struct LatticeGpencilModifierData { + GpencilModifierData modifier; + struct Object *object; + char layername[64]; /* layer name */ + char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + float strength; + char pad[4]; + void *cache_data; /* runtime only (LatticeDeformData) */ +} LatticeGpencilModifierData; + +typedef enum eLatticeGpencil_Flag { + GP_LATTICE_INVERT_LAYER = (1 << 0), + GP_LATTICE_INVERT_PASS = (1 << 1), + GP_LATTICE_INVERT_VGROUP = (1 << 2), +} eLatticeGpencil_Flag; + +typedef struct MirrorGpencilModifierData { + GpencilModifierData modifier; + struct Object *object; + char layername[64]; /* layer name */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ +} MirrorGpencilModifierData; + +typedef enum eMirrorGpencil_Flag { + GP_MIRROR_INVERT_LAYER = (1 << 0), + GP_MIRROR_INVERT_PASS = (1 << 1), + GP_MIRROR_CLIPPING = (1 << 2), + GP_MIRROR_AXIS_X = (1 << 3), + GP_MIRROR_AXIS_Y = (1 << 4), + GP_MIRROR_AXIS_Z = (1 << 5), +} eMirrorGpencil_Flag; + +typedef struct HookGpencilModifierData { + GpencilModifierData modifier; + + struct Object *object; + char subtarget[64]; /* optional name of bone target, MAX_ID_NAME-2 */ + char layername[64]; /* layer name */ + char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + int pass_index; /* custom index for passes */ + + int flag; + char falloff_type; /* use enums from WarpGpencilModifier (exact same functionality) */ + char pad[3]; + float parentinv[4][4]; /* matrix making current transform unmodified */ + float cent[3]; /* visualization of hook */ + float falloff; /* if not zero, falloff is distance where influence zero */ + float force; + struct CurveMapping *curfalloff; +} HookGpencilModifierData; + +typedef enum eHookGpencil_Flag { + GP_HOOK_INVERT_LAYER = (1 << 0), + GP_HOOK_INVERT_PASS = (1 << 1), + GP_HOOK_INVERT_VGROUP = (1 << 2), + GP_HOOK_UNIFORM_SPACE = (1 << 3), +} eHookGpencil_Flag; + +typedef enum eHookGpencil_Falloff { + eGPHook_Falloff_None = 0, + eGPHook_Falloff_Curve = 1, + eGPHook_Falloff_Sharp = 2, + eGPHook_Falloff_Smooth = 3, + eGPHook_Falloff_Root = 4, + eGPHook_Falloff_Linear = 5, + eGPHook_Falloff_Const = 6, + eGPHook_Falloff_Sphere = 7, + eGPHook_Falloff_InvSquare = 8, +} eHookGpencil_Falloff; + +typedef struct SimplifyGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + float factor; /* factor of simplify */ + short mode; /* type of simplify */ + short step; /* every n vertex to keep */ +} SimplifyGpencilModifierData; + +typedef enum eSimplifyGpencil_Flag { + GP_SIMPLIFY_INVERT_LAYER = (1 << 0), + GP_SIMPLIFY_INVERT_PASS = (1 << 1), +} eSimplifyGpencil_Flag; + +typedef enum eSimplifyGpencil_Mode { + /* Keep only one vertex every n vertices */ + GP_SIMPLIFY_FIXED = 0, + /* Use RDP algorithm */ + GP_SIMPLIFY_ADAPTATIVE = 1, +} eSimplifyGpencil_Mode; + +typedef struct OffsetGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + int pass_index; /* custom index for passes */ + int flag; /* flags */ + float loc[3]; + float rot[3]; + float scale[3]; + char pad[4]; +} OffsetGpencilModifierData; + +typedef enum eOffsetGpencil_Flag { + GP_OFFSET_INVERT_LAYER = (1 << 0), + GP_OFFSET_INVERT_PASS = (1 << 1), + GP_OFFSET_INVERT_VGROUP = (1 << 2) +} eOffsetGpencil_Flag; + +typedef struct SmoothGpencilModifierData { + GpencilModifierData modifier; + char layername[64]; /* layer name */ + char vgname[64]; /* optional vertexgroup name, MAX_VGROUP_NAME */ + int pass_index; /* custom index for passes */ + int flag; /* several flags */ + float factor; /* factor of noise */ + int step; /* how many times apply smooth */ +} SmoothGpencilModifierData; + +typedef enum eSmoothGpencil_Flag { + GP_SMOOTH_MOD_LOCATION = (1 << 0), + GP_SMOOTH_MOD_STRENGTH = (1 << 1), + GP_SMOOTH_MOD_THICKNESS = (1 << 2), + GP_SMOOTH_INVERT_LAYER = (1 << 3), + GP_SMOOTH_INVERT_PASS = (1 << 4), + GP_SMOOTH_INVERT_VGROUP = (1 << 5), + GP_SMOOTH_MOD_UV = (1 << 6), +} eSmoothGpencil_Flag; + +#define MOD_MESHSEQ_READ_ALL \ + (MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR) + +#endif /* __DNA_GREASEPENCIL_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index e2ee561de7f..8febfbc8ffc 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -36,6 +36,17 @@ struct AnimData; struct CurveMapping; +struct GHash; +struct MDeformVert; + +/* TODO: add size as userprefs parameter */ +#define GP_OBGPENCIL_DEFAULT_SIZE 0.2f +#define GP_DEFAULT_PIX_FACTOR 1.0f +#define GP_DEFAULT_GRID_LINES 4 +#define GP_MAX_INPUT_SAMPLES 10 + +/* ***************************************** */ +/* GP Stroke Points */ /* Grease-Pencil Annotations - 'Stroke Point' * -> Coordinates may either be 2d or 3d depending on settings at the time @@ -47,7 +58,10 @@ typedef struct bGPDspoint { float pressure; /* pressure of input device (from 0 to 1) at this point */ float strength; /* color strength (used for alpha factor) */ float time; /* seconds since start of stroke */ - int flag; /* additional options (NOTE: can shrink this field down later if needed) */ + int flag; /* additional options */ + + float uv_fac; /* factor of uv along the stroke */ + float uv_rot; /* uv rotation for dot mode */ } bGPDspoint; /* bGPDspoint->flag */ @@ -59,54 +73,24 @@ typedef enum eGPDspoint_Flag { GP_SPOINT_TAG = (1 << 1), } eGPSPoint_Flag; +/* ***************************************** */ +/* GP Fill - Triangle Tesselation Data */ + /* Grease-Pencil Annotations - 'Triangle' - * A triangle contains the index of three vertices for filling the stroke - * This is only used if high quality fill is enabled. - * (not saved to blend file). + * -> A triangle contains the index of three vertices for filling the stroke + * This is only used if high quality fill is enabled */ typedef struct bGPDtriangle { /* indices for tesselated triangle used for GP Fill */ unsigned int verts[3]; + /* texture coordinates for verts */ + float uv[3][2]; } bGPDtriangle; -/* GP brush (used for new strokes) */ -typedef struct bGPDbrush { - struct bGPDbrush *next, *prev; +/* ***************************************** */ - char info[64]; /* Brush name. Must be unique. */ - short thickness; /* thickness to apply to strokes */ - short flag; - float draw_smoothfac; /* amount of smoothing to apply to newly created strokes */ - short draw_smoothlvl; /* number of times to apply smooth factor to new strokes */ - short sublevel; /* number of times to subdivide new strokes */ - - float draw_sensitivity; /* amount of sensivity to apply to newly created strokes */ - float draw_strength; /* amount of alpha strength to apply to newly created strokes */ - float draw_jitter; /* amount of jitter to apply to newly created strokes */ - float draw_angle; /* angle when the brush has full thickness */ - float draw_angle_factor; /* factor to apply when angle change (only 90 degrees) */ - float draw_random_press; /* factor of randomness for sensitivity and strength */ - float draw_random_sub; /* factor of randomness for subdivision */ - struct CurveMapping *cur_sensitivity; - struct CurveMapping *cur_strength; - struct CurveMapping *cur_jitter; -} bGPDbrush; - -/* bGPDbrush->flag */ -typedef enum eGPDbrush_Flag { - /* brush is active */ - GP_BRUSH_ACTIVE = (1 << 0), - /* brush use pressure */ - GP_BRUSH_USE_PRESSURE = (1 << 1), - /* brush use pressure for alpha factor */ - GP_BRUSH_USE_STENGTH_PRESSURE = (1 << 2), - /* brush use pressure for alpha factor */ - GP_BRUSH_USE_JITTER_PRESSURE = (1 << 3), - /* brush use random for pressure */ - GP_BRUSH_USE_RANDOM_PRESSURE = (1 << 4), - /* brush use random for strength */ - GP_BRUSH_USE_RANDOM_STRENGTH = (1 << 5) -} eGPDbrush_Flag; +/* ***************************************** */ +/* GP Palettes (Deprecated - 2.78 - 2.79 only) */ /* color of palettes */ typedef struct bGPDpalettecolor { @@ -129,9 +113,7 @@ typedef enum eGPDpalettecolor_Flag { /* do onion skinning */ PC_COLOR_ONIONSKIN = (1 << 3), /* "volumetric" strokes */ - PC_COLOR_VOLUMETRIC = (1 << 4), - /* Use High quality fill */ - PC_COLOR_HQ_FILL = (1 << 5) + PC_COLOR_VOLUMETRIC = (1 << 4) } eGPDpalettecolor_Flag; /* palette of colors */ @@ -152,6 +134,21 @@ typedef enum eGPDpalette_Flag { PL_PALETTE_ACTIVE = (1 << 0) } eGPDpalette_Flag; +/* ***************************************** */ +/* GP Strokes */ + +/* Runtime temp data for bGPDstroke */ +typedef struct bGPDstroke_runtime { + /* runtime final colors (result of original colors and modifiers) */ + float tmp_stroke_rgba[4]; + float tmp_fill_rgba[4]; + + /* temporary layer name only used during copy/paste to put the stroke in the original layer */ + char tmp_layerinfo[128]; + + float multi_frame_falloff; /* runtime falloff factor (only for transform) */ +} bGPDstroke_runtime; + /* Grease-Pencil Annotations - 'Stroke' * -> A stroke represents a (simplified version) of the curve * drawn by the user in one 'mousedown'->'mouseup' operation @@ -168,14 +165,16 @@ typedef struct bGPDstroke { short flag, pad[2]; /* various settings about this stroke */ double inittime; /* Init time of stroke */ - /* The pointer to color is only used during drawing, but not saved - * colorname is the join with the palette, but when draw, the pointer is update if the value is NULL - * to speed up the drawing - */ - char colorname[128]; /* color name */ - bGPDpalettecolor *palcolor; /* current palette color */ - /* temporary layer name only used during copy/paste to put the stroke in the original layer */ - char tmp_layerinfo[128]; + + char colorname[128] DNA_DEPRECATED; /* color name */ + + int mat_nr; /* material index */ + char pad_[4]; + + struct MDeformVert *dvert; /* vertex weight data */ + + bGPDstroke_runtime runtime; + char pad_1[4]; } bGPDstroke; /* bGPDstroke->flag */ @@ -190,14 +189,22 @@ typedef enum eGPDstroke_Flag { GP_STROKE_SELECT = (1 << 3), /* Recalculate triangulation for high quality fill (when true, force a new recalc) */ GP_STROKE_RECALC_CACHES = (1 << 4), - /* Recalculate the color pointer using the name as index (true force a new recalc) */ - GP_STROKE_RECALC_COLOR = (1 << 5), /* Flag used to indicate that stroke is closed and draw edge between last and first point */ GP_STROKE_CYCLIC = (1 << 7), + /* Flag used to indicate that stroke is used for fill close and must use fill color for stroke and no fill area */ + GP_STROKE_NOFILL = (1 << 8), /* only for use with stroke-buffer (while drawing eraser) */ GP_STROKE_ERASER = (1 << 15) } eGPDstroke_Flag; +/* ***************************************** */ +/* GP Frame */ + +/* Runtime temp data for bGPDframe */ +typedef struct bGPDframe_runtime { + float viewmatrix[4][4]; /* parent matrix for drawing */ +} bGPDframe_runtime; + /* Grease-Pencil Annotations - 'Frame' * -> Acts as storage for the 'image' formed by strokes */ @@ -210,6 +217,8 @@ typedef struct bGPDframe { short flag; /* temp settings */ short key_type; /* keyframe type (eBezTriple_KeyframeType) */ + + bGPDframe_runtime runtime; } bGPDframe; /* bGPDframe->flag */ @@ -220,6 +229,16 @@ typedef enum eGPDframe_Flag { GP_FRAME_SELECT = (1 << 1) } eGPDframe_Flag; +/* ***************************************** */ +/* GP Layer */ + +/* Runtime temp data for bGPDlayer */ +typedef struct bGPDlayer_runtime { + struct GHash *derived_data; /* runtime data created by modifiers */ + int icon_id; /* id for dynamic icon used to show annotation color preview for layer */ + char pad[4]; +} bGPDlayer_runtime; + /* Grease-Pencil Annotations - 'Layer' */ typedef struct bGPDlayer { struct bGPDlayer *next, *prev; @@ -228,27 +247,27 @@ typedef struct bGPDlayer { bGPDframe *actframe; /* active frame (should be the frame that is currently being displayed) */ short flag; /* settings for layer */ - short thickness; /* current thickness to apply to strokes */ - - short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */ - short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */ + short onion_flag; /* Per-layer onion-skinning flags (eGPDlayer_OnionFlag) */ - float gcolor_prev[3]; /* optional color for ghosts before the active frame */ - float gcolor_next[3]; /* optional color for ghosts after the active frame */ + float color[4]; /* Color for strokes in layers. Used for annotations, and for ruler (which uses GPencil internally) */ + float fill[4]; /* Fill color for strokes in layers. Not used anymore (was only for) */ - float color[4]; /* Color for strokes in layers (replaced by palettecolor). Only used for ruler (which uses GPencil internally) */ - float fill[4]; /* Fill color for strokes in layers. Not used and replaced by palettecolor fill */ + char info[128]; /* name/reference info for this layer (i.e. "director's comments, 12/3") + * needs to be kept unique, as it's used as the layer identifier */ - char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3") - * this is used for the name of the layer too and kept unique. */ + short thickness; /* thickness to apply to strokes (Annotations) */ + char pad_1[2]; struct Object *parent; /* parent object */ float inverse[4][4]; /* inverse matrix (only used if parented) */ char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */ - short partype, pad; + short partype; + short line_change; /* Thickness adjustment */ float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */ float opacity; /* Opacity of the layer */ + + bGPDlayer_runtime runtime; } bGPDlayer; /* bGPDlayer->flag */ @@ -261,51 +280,89 @@ typedef enum eGPDlayer_Flag { GP_LAYER_ACTIVE = (1 << 2), /* draw points of stroke for debugging purposes */ GP_LAYER_DRAWDEBUG = (1 << 3), - /* do onion skinning */ - GP_LAYER_ONIONSKIN = (1 << 4), /* for editing in Action Editor */ GP_LAYER_SELECT = (1 << 5), /* current frame for layer can't be changed */ GP_LAYER_FRAMELOCK = (1 << 6), /* don't render xray (which is default) */ GP_LAYER_NO_XRAY = (1 << 7), - /* use custom color for ghosts before current frame */ - GP_LAYER_GHOST_PREVCOL = (1 << 8), - /* use custom color for ghosts after current frame */ - GP_LAYER_GHOST_NEXTCOL = (1 << 9), /* "volumetric" strokes */ GP_LAYER_VOLUMETRIC = (1 << 10), - /* Use high quality fill (instead of buggy legacy OpenGL Fill) */ - GP_LAYER_HQ_FILL = (1 << 11), /* Unlock color */ GP_LAYER_UNLOCK_COLOR = (1 << 12), - /* always show onion skins (i.e. even during renders/animation playback) */ - GP_LAYER_GHOST_ALWAYS = (1 << 13), } eGPDlayer_Flag; +/* bGPDlayer->onion_flag */ +typedef enum eGPDlayer_OnionFlag { + /* do onion skinning */ + GP_LAYER_ONIONSKIN = (1 << 0), +} eGPDlayer_OnionFlag; + +/* ***************************************** */ +/* GP Datablock */ + +/* Runtime temp data for bGPdata */ +typedef struct bGPdata_runtime { + /* Drawing Manager cache */ + struct GHash *batch_cache_data; + void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */ + + /* GP Object drawing */ + float scolor[4]; /* buffer stroke color */ + float sfill[4]; /* buffer fill color */ + short mode; /* settings for color */ + short bstroke_style; /* buffer style for drawing strokes (used to select shader type) */ + short bfill_style; /* buffer style for filling areas (used to select shader type) */ + + /* Stroke Buffer data (only used during paint-session) + * - buffer must be initialized before use, but freed after + * whole paint operation is over + */ + short sbuffer_size; /* number of elements currently in cache */ + short sbuffer_sflag; /* flags for stroke that cache represents */ + char pad_[6]; +} bGPdata_runtime; + /* Grease-Pencil Annotations - 'DataBlock' */ typedef struct bGPdata { ID id; /* Grease Pencil data is a datablock */ struct AnimData *adt; /* animation data - for animating draw settings */ - /* saved Grease-Pencil data */ + /* Grease-Pencil data */ ListBase layers; /* bGPDlayers */ int flag; /* settings for this datablock */ - /* not-saved stroke buffer data (only used during paint-session) - * - buffer must be initialized before use, but freed after - * whole paint operation is over - */ - short sbuffer_size; /* number of elements currently in cache */ - short sbuffer_sflag; /* flags for stroke that cache represents */ - void *sbuffer; /* stroke buffer (can hold GP_STROKE_BUFFER_MAX) */ - float scolor[4]; /* buffer color using palettes */ - float sfill[4]; /* buffer fill color */ - char pad[6]; /* padding for compiler alignment error */ - short sflag; /* settings for palette color */ - - /* saved palettes */ - ListBase palettes; + short xray_mode; /* xray mode for strokes (eGP_DepthOrdering) */ + char pad_1[2]; + + /* Palettes */ + ListBase palettes DNA_DEPRECATED; /* list of bGPDpalette's - Deprecated (2.78 - 2.79 only) */ + + /* 3D Viewport/Appearance Settings */ + float pixfactor; /* factor to define pixel size conversion */ + float line_color[4]; /* color for edit line */ + + /* Onion skinning */ + float onion_factor; /* onion alpha factor change */ + int onion_mode; /* onion skinning range (eGP_OnionModes) */ + int onion_flag; /* onion skinning flags (eGPD_OnionFlag) */ + short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */ + short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */ + + float gcolor_prev[3]; /* optional color for ghosts before the active frame */ + float gcolor_next[3]; /* optional color for ghosts after the active frame */ + + char pad[4]; + struct Material **mat; /* materials array */ + short totcol; /* total materials */ + + /* stats */ + short totlayer; + short totframe; + short totstroke; + short totpoint; + char pad_2[6]; + bGPdata_runtime runtime; } bGPdata; /* bGPdata->flag */ @@ -314,8 +371,12 @@ typedef struct bGPdata { * changes made during the porting process. */ typedef enum eGPdata_Flag { - /* don't allow painting to occur at all */ - /* GP_DATA_LMBPLOCK = (1 << 0), */ + /* datablock is used for "annotations" + * NOTE: This flag used to be used in 2.4x, but should hardly ever have been set. + * We can use this freely now, as all GP datablocks from pre-2.8 will get + * set on file load (as many old use cases are for "annotations" only) + */ + GP_DATA_ANNOTATIONS = (1 << 0), /* show debugging info in viewport (i.e. status print) */ GP_DATA_DISPINFO = (1 << 1), @@ -339,10 +400,80 @@ typedef enum eGPdata_Flag { /* Stroke Editing Mode - Toggle to enable alternative keymap for easier editing of stroke points */ GP_DATA_STROKE_EDITMODE = (1 << 8), - /* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */ + /* Main flag to switch onion skinning on/off */ GP_DATA_SHOW_ONIONSKINS = (1 << 9), /* Draw a green and red point to indicate start and end of the stroke */ - GP_DATA_SHOW_DIRECTION = (1 << 10) + GP_DATA_SHOW_DIRECTION = (1 << 10), + + /* Batch drawing cache need to be recalculated */ + GP_DATA_CACHE_IS_DIRTY = (1 << 11), + + /* Stroke Paint Mode - Toggle paint mode */ + GP_DATA_STROKE_PAINTMODE = (1 << 12), + /* Stroke Editing Mode - Toggle sculpt mode */ + GP_DATA_STROKE_SCULPTMODE = (1 << 13), + /* Stroke Editing Mode - Toggle weight paint mode */ + GP_DATA_STROKE_WEIGHTMODE = (1 << 14), + + /* keep stroke thickness unchanged when zoom change */ + GP_DATA_STROKE_KEEPTHICKNESS = (1 << 15), + + /* Allow edit several frames at the same time */ + GP_DATA_STROKE_MULTIEDIT = (1 << 16), } eGPdata_Flag; +/* gpd->onion_flag */ +typedef enum eGPD_OnionFlag { + /* use custom color for ghosts before current frame */ + GP_ONION_GHOST_PREVCOL = (1 << 0), + /* use custom color for ghosts after current frame */ + GP_ONION_GHOST_NEXTCOL = (1 << 1), + /* always show onion skins (i.e. even during renders/animation playback) */ + GP_ONION_GHOST_ALWAYS = (1 << 2), + /* use fade color in onion skin */ + GP_ONION_FADE = (1 << 3), + /* Loop showing first frame after last frame */ + GP_ONION_LOOP = (1 << 4), +} eGPD_OnionFlag; + +/* gpd->onion_mode */ +typedef enum eGP_OnionModes { + GP_ONION_MODE_ABSOLUTE = 0, + GP_ONION_MODE_RELATIVE = 1, + GP_ONION_MODE_SELECTED = 2, +} eGP_OnionModes; + +/* xray modes (Depth Ordering) */ +typedef enum eGP_DepthOrdering { + GP_XRAY_FRONT = 0, + GP_XRAY_3DSPACE = 1, + GP_XRAY_BACK = 2 +} eGP_DepthOrdering; + +/* ***************************************** */ +/* Mode Checking Macros */ + +/* Check if 'multiedit sessions' is enabled */ +#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd) \ + ((gpd) && (gpd->flag & \ + (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)) && \ + (gpd->flag & GP_DATA_STROKE_MULTIEDIT)) + +/* Macros to check grease pencil modes */ +#define GPENCIL_ANY_MODE(gpd) \ + ((gpd) && (gpd->flag & \ + (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | \ + GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE))) +#define GPENCIL_ANY_EDIT_MODE(gpd) \ + ((gpd) && (gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE))) +#define GPENCIL_PAINT_MODE(gpd) \ + ((gpd) && (gpd->flag & (GP_DATA_STROKE_PAINTMODE))) +#define GPENCIL_SCULPT_OR_WEIGHT_MODE(gpd) \ + ((gpd) && (gpd->flag & (GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE))) +#define GPENCIL_NONE_EDIT_MODE(gpd) \ + ((gpd) && ((gpd->flag & (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE)) == 0)) +#define GPENCIL_LAZY_MODE(brush, shift) \ + (((brush) && ((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) && (shift == 0))) || \ + (((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && (shift == 1))) + #endif /* __DNA_GPENCIL_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index eb469895fd7..50d9b890724 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -54,6 +54,59 @@ typedef struct TexPaintSlot { int pad; } TexPaintSlot; +typedef struct MaterialGPencilStyle { + struct Image *sima; /* Texture image for strokes */ + struct Image *ima; /* Texture image for filling */ + float stroke_rgba[4]; /* color for paint and strokes (alpha included) */ + float fill_rgba[4]; /* color that should be used for drawing "fills" for strokes (alpha included) */ + float mix_rgba[4]; /* secondary color used for gradients and other stuff */ + short flag; /* settings */ + short index; /* custom index for passes */ + short stroke_style; /* style for drawing strokes (used to select shader type) */ + short fill_style; /* style for filling areas (used to select shader type) */ + float mix_factor; /* factor used to define shader behavior (several uses) */ + float gradient_angle; /* angle used for gradients orientation */ + float gradient_radius; /* radius for radial gradients */ + float pattern_gridsize; /* cheesboard size */ + float gradient_scale[2]; /* uv coordinates scale */ + float gradient_shift[2]; /* factor to shift filling in 2d space */ + float texture_angle; /* angle used for texture orientation */ + float texture_scale[2]; /* texture scale (separated of uv scale) */ + float texture_offset[2]; /* factor to shift texture in 2d space */ + float texture_opacity; /* texture opacity */ + float texture_pixsize; /* pixel size for uv along the stroke */ + int mode; /* drawing mode (line or dots) */ + + int gradient_type; /* type of gradient */ + char pad[4]; +} MaterialGPencilStyle; + +/* MaterialGPencilStyle->flag */ +typedef enum eMaterialGPencilStyle_Flag { + /* Fill Texture is a pattern */ + GP_STYLE_FILL_PATTERN = (1 << 0), + /* don't display color */ + GP_STYLE_COLOR_HIDE = (1 << 1), + /* protected from further editing */ + GP_STYLE_COLOR_LOCKED = (1 << 2), + /* do onion skinning */ + GP_STYLE_COLOR_ONIONSKIN = (1 << 3), + /* clamp texture */ + GP_STYLE_COLOR_TEX_CLAMP = (1 << 4), + /* mix texture */ + GP_STYLE_COLOR_TEX_MIX = (1 << 5), + /* Flip fill colors */ + GP_STYLE_COLOR_FLIP_FILL = (1 << 6), + /* Stroke Texture is a pattern */ + GP_STYLE_STROKE_PATTERN = (1 << 7) +} eMaterialGPencilStyle_Flag; + +typedef enum eMaterialGPencilStyle_Mode { + GP_STYLE_MODE_LINE = 0, /* line */ + GP_STYLE_MODE_DOTS = 1, /* dots */ + GP_STYLE_MODE_BOX = 2, /* rectangles */ +} eMaterialGPencilStyle_Mode; + typedef struct Material { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -107,6 +160,9 @@ typedef struct Material { /* Runtime cache for GLSL materials. */ ListBase gpumaterial; + + /* grease pencil color */ + struct MaterialGPencilStyle *gp_style; } Material; /* **************** MATERIAL ********************* */ @@ -229,4 +285,24 @@ enum { MA_BS_HASHED, }; +/* Grease Pencil Stroke styles */ +enum { + GP_STYLE_STROKE_STYLE_SOLID = 0, + GP_STYLE_STROKE_STYLE_TEXTURE +}; + +/* Grease Pencil Fill styles */ +enum { + GP_STYLE_FILL_STYLE_SOLID = 0, + GP_STYLE_FILL_STYLE_GRADIENT, + GP_STYLE_FILL_STYLE_CHESSBOARD, + GP_STYLE_FILL_STYLE_TEXTURE +}; + +/* Grease Pencil Gradient Types */ +enum { + GP_STYLE_GRADIENT_LINEAR = 0, + GP_STYLE_GRADIENT_RADIAL +}; + #endif diff --git a/source/blender/makesdna/DNA_object_enums.h b/source/blender/makesdna/DNA_object_enums.h index 802ca6c7d0d..01228376174 100644 --- a/source/blender/makesdna/DNA_object_enums.h +++ b/source/blender/makesdna/DNA_object_enums.h @@ -37,7 +37,10 @@ typedef enum eObjectMode { OB_MODE_TEXTURE_PAINT = 1 << 4, OB_MODE_PARTICLE_EDIT = 1 << 5, OB_MODE_POSE = 1 << 6, - OB_MODE_GPENCIL = 1 << 7, /* NOTE: Just a dummy to make the UI nicer */ + OB_MODE_GPENCIL_EDIT = 1 << 7, + OB_MODE_GPENCIL_PAINT = 1 << 8, + OB_MODE_GPENCIL_SCULPT = 1 << 9, + OB_MODE_GPENCIL_WEIGHT = 1 << 10, } eObjectMode; /* Any mode where the brush system is used. */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index a8d50543e80..47fb2feb7f4 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -180,7 +180,9 @@ typedef struct Object { ListBase effect DNA_DEPRECATED; // XXX deprecated... keep for readfile ListBase defbase; /* list of bDeformGroup (vertex groups) names and flag only */ ListBase modifiers; /* list of ModifierData structures */ + ListBase greasepencil_modifiers; /* list of GpencilModifierData structures */ ListBase fmaps; /* list of facemaps */ + ListBase shader_fx; /* list of viewport effects. Actually only used by grease pencil */ int mode; /* Local object mode */ int restore_mode; @@ -351,6 +353,9 @@ enum { /* 23 and 24 are for life and sector (old file compat.) */ OB_ARMATURE = 25, +/* Grease Pencil object used in 3D view but not used for annotation in 2D */ + OB_GPENCIL = 26, + OB_TYPE_MAX, }; @@ -361,9 +366,9 @@ enum { /* check if the object type supports materials */ #define OB_TYPE_SUPPORT_MATERIAL(_type) \ - ((_type) >= OB_MESH && (_type) <= OB_MBALL) + (((_type) >= OB_MESH && (_type) <= OB_MBALL) || ((_type) == OB_GPENCIL)) #define OB_TYPE_SUPPORT_VGROUP(_type) \ - (ELEM(_type, OB_MESH, OB_LATTICE)) + (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL)) #define OB_TYPE_SUPPORT_EDITMODE(_type) \ (ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)) #define OB_TYPE_SUPPORT_PARVERT(_type) \ @@ -375,10 +380,10 @@ enum { /* is this ID type used as object data */ #define OB_DATA_SUPPORT_ID(_id_type) \ - (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_LP, ID_CA, ID_LT, ID_AR)) + (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_LP, ID_CA, ID_LT, ID_GD, ID_AR)) #define OB_DATA_SUPPORT_ID_CASE \ - ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_LP: case ID_CA: case ID_LT: case ID_AR + ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_LP: case ID_CA: case ID_LT: case ID_GD: case ID_AR /* partype: first 4 bits: type */ enum { @@ -466,6 +471,12 @@ enum { OB_EMPTY_IMAGE = 8, }; +/* gpencil add types */ +enum { + GP_EMPTY = 0, + GP_MONKEY = 1 +}; + /* boundtype */ enum { OB_BOUND_BOX = 0, diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index a4235a07ed5..6629eeae3fa 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -66,7 +66,6 @@ struct AnimData; struct Editing; struct SceneStats; struct bGPdata; -struct bGPDbrush; struct MovieClip; struct ColorSpace; struct SceneCollection; @@ -686,7 +685,8 @@ typedef struct RenderData { /* render simplify */ short simplify_subsurf; short simplify_subsurf_render; - short pad9, pad10; + short simplify_gpencil; + short pad10; float simplify_particles; float simplify_particles_render; @@ -905,6 +905,11 @@ typedef struct UvSculpt { Paint paint; } UvSculpt; +/* grease pencil drawing brushes */ +typedef struct GpPaint { + Paint paint; +} GpPaint; + /* ------------------------------------------- */ /* Vertex Paint */ @@ -929,15 +934,18 @@ enum { typedef enum eGP_EditBrush_Types { GP_EDITBRUSH_TYPE_SMOOTH = 0, GP_EDITBRUSH_TYPE_THICKNESS = 1, - GP_EDITBRUSH_TYPE_GRAB = 2, - GP_EDITBRUSH_TYPE_PUSH = 3, - GP_EDITBRUSH_TYPE_TWIST = 4, - GP_EDITBRUSH_TYPE_PINCH = 5, - GP_EDITBRUSH_TYPE_RANDOMIZE = 6, - GP_EDITBRUSH_TYPE_SUBDIVIDE = 7, - GP_EDITBRUSH_TYPE_SIMPLIFY = 8, - GP_EDITBRUSH_TYPE_CLONE = 9, - GP_EDITBRUSH_TYPE_STRENGTH = 10, + GP_EDITBRUSH_TYPE_STRENGTH = 2, + GP_EDITBRUSH_TYPE_GRAB = 3, + GP_EDITBRUSH_TYPE_PUSH = 4, + GP_EDITBRUSH_TYPE_TWIST = 5, + GP_EDITBRUSH_TYPE_PINCH = 6, + GP_EDITBRUSH_TYPE_RANDOMIZE = 7, + GP_EDITBRUSH_TYPE_CLONE = 8, + GP_EDITBRUSH_TYPE_SUBDIVIDE = 9, + GP_EDITBRUSH_TYPE_SIMPLIFY = 10, + /* add any sculpt brush above this value */ + GP_EDITBRUSH_TYPE_WEIGHT = 11, + /* add any weight paint brush below this value. Do no mix brushes */ /* !!! Update GP_EditBrush_Data brush[###]; below !!! */ TOT_GP_EDITBRUSH_TYPES @@ -956,6 +964,8 @@ typedef struct GP_EditBrush_Data { short size; /* radius of brush */ short flag; /* eGP_EditBrush_Flag */ float strength; /* strength of effect */ + float curcolor_add[3]; /* cursor color for add */ + float curcolor_sub[3]; /* cursor color for sub */ } GP_EditBrush_Data; /* GP_EditBrush_Data.flag */ @@ -969,20 +979,31 @@ typedef enum eGP_EditBrush_Flag { GP_EDITBRUSH_FLAG_USE_FALLOFF = (1 << 2), /* smooth brush affects pressure values as well */ - GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE = (1 << 3) + GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE = (1 << 3), + /* enable screen cursor */ + GP_EDITBRUSH_FLAG_ENABLE_CURSOR = (1 << 4), + /* temporary invert action */ + GP_EDITBRUSH_FLAG_TMP_INVERT = (1 << 5), } eGP_EditBrush_Flag; /* GPencil Stroke Sculpting Settings */ typedef struct GP_BrushEdit_Settings { - GP_EditBrush_Data brush[11]; /* TOT_GP_EDITBRUSH_TYPES */ + GP_EditBrush_Data brush[12]; /* TOT_GP_EDITBRUSH_TYPES */ void *paintcursor; /* runtime */ - int brushtype; /* eGP_EditBrush_Types */ + int brushtype; /* eGP_EditBrush_Types (sculpt) */ int flag; /* eGP_BrushEdit_SettingsFlag */ int lock_axis; /* eGP_Lockaxis_Types lock drawing to one axis */ - float alpha; /* alpha factor for selection color */ + char pad1[4]; + + /* weight paint is a submode of sculpt but use its own index. All weight paint + * brushes must be defined at the end of the brush array. + */ + int weighttype; /* eGP_EditBrush_Types (weight paint) */ + char pad[4]; + struct CurveMapping *cur_falloff; /* multiframe edit falloff effect by frame */ } GP_BrushEdit_Settings; /* GP_BrushEdit_Settings.flag */ @@ -995,6 +1016,12 @@ typedef enum eGP_BrushEdit_SettingsFlag { GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2), /* apply brush to thickness */ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3), + /* apply brush to thickness */ + GP_BRUSHEDIT_FLAG_WEIGHT_MODE = (1 << 4), + /* enable falloff for multiframe editing */ + GP_BRUSHEDIT_FLAG_FRAME_FALLOFF = (1 << 5), + /* apply brush to uv data */ + GP_BRUSHEDIT_FLAG_APPLY_UV = (1 << 6), } eGP_BrushEdit_SettingsFlag; @@ -1213,6 +1240,7 @@ typedef struct ToolSettings { VPaint *wpaint; /* weight paint */ Sculpt *sculpt; UvSculpt *uvsculpt; /* uv smooth */ + GpPaint *gp_paint; /* gpencil paint */ /* Vertex group weight - used only for editmode, not weight * paint */ @@ -1236,19 +1264,19 @@ typedef struct ToolSettings { /* Auto-IK */ short autoik_chainlen; /* runtime only */ - /* SCE_MPR_LOC/SCAL */ - char gizmo_flag; - /* Grease Pencil */ char gpencil_flags; /* flags/options for how the tool works */ - char gpencil_src; /* for main 3D view Grease Pencil, where data comes from */ char gpencil_v3d_align; /* stroke placement settings: 3D View */ char gpencil_v2d_align; /* : General 2D Editor */ char gpencil_seq_align; /* : Sequencer Preview */ char gpencil_ima_align; /* : Image Editor */ - char _pad3[3]; + /* Annotations */ + char annotate_v3d_align; /* stroke placement settings - 3D View */ + + short annotate_thickness; /* default stroke thickness for annotation strokes */ + char _pad3[2]; /* Grease Pencil Sculpt */ struct GP_BrushEdit_Settings gp_sculpt; @@ -1256,10 +1284,7 @@ typedef struct ToolSettings { /* Grease Pencil Interpolation Tool(s) */ struct GP_Interpolate_Settings gp_interpolate; - /* Grease Pencil Drawing Brushes (bGPDbrush) */ - ListBase gp_brushes; - - /* Image Paint (8 byttse aligned please!) */ + /* Image Paint (8 bytes aligned please!) */ struct ImagePaintSettings imapaint; /* Particle Editing */ @@ -1281,7 +1306,9 @@ typedef struct ToolSettings { /* Alt+RMB option */ char edge_mode; char edge_mode_live_unwrap; - char _pad1; + + /* SCE_MPR_LOC/SCAL */ + char gizmo_flag; /* Transform */ char transform_pivot_point; @@ -1503,7 +1530,7 @@ typedef struct Scene { /* Units */ struct UnitSettings unit; - /* Grease Pencil */ + /* Grease Pencil - Annotations */ struct bGPdata *gpd; /* Movie Tracking */ @@ -1515,6 +1542,7 @@ typedef struct Scene { uint64_t customdata_mask; /* XXX. runtime flag for drawing, actually belongs in the window, only used by BKE_object_handle_update() */ uint64_t customdata_mask_modal; /* XXX. same as above but for temp operator use (gl renders) */ + /* Color Management */ ColorManagedViewSettings view_settings; ColorManagedDisplaySettings display_settings; @@ -2020,19 +2048,27 @@ typedef enum eImagePaintMode { /* ToolSettings.gpencil_flags */ typedef enum eGPencil_Flags { - /* "Continuous Drawing" - The drawing operator enters a mode where multiple strokes can be drawn */ - GP_TOOL_FLAG_PAINTSESSIONS_ON = (1 << 0), /* When creating new frames, the last frame gets used as the basis for the new one */ GP_TOOL_FLAG_RETAIN_LAST = (1 << 1), /* Add the strokes below all strokes in the layer */ - GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2) + GP_TOOL_FLAG_PAINT_ONBACK = (1 << 2), + /* Show compact list of colors */ + GP_TOOL_FLAG_THUMBNAIL_LIST = (1 << 3), } eGPencil_Flags; -/* ToolSettings.gpencil_src */ -typedef enum eGPencil_Source_3D { - GP_TOOL_SOURCE_SCENE = 0, - GP_TOOL_SOURCE_OBJECT = 1 -} eGPencil_Source_3d; +/* scene->r.simplify_gpencil */ +typedef enum eGPencil_SimplifyFlags { + /* Simplify */ + SIMPLIFY_GPENCIL_ENABLE = (1 << 0), + /* Simplify on play */ + SIMPLIFY_GPENCIL_ON_PLAY = (1 << 1), + /* Simplify fill on viewport */ + SIMPLIFY_GPENCIL_FILL = (1 << 2), + /* Simplify modifier on viewport */ + SIMPLIFY_GPENCIL_MODIFIER = (1 << 3), + /* Remove fill external line */ + SIMPLIFY_GPENCIL_REMOVE_FILL_LINE = (1 << 4) +} eGPencil_SimplifyFlags; /* ToolSettings.gpencil_*_align - Stroke Placement mode flags */ typedef enum eGPencil_Placement_Flags { @@ -2048,6 +2084,7 @@ typedef enum eGPencil_Placement_Flags { /* "Use Endpoints" */ GP_PROJECT_DEPTH_STROKE_ENDPOINTS = (1 << 4), + GP_PROJECT_CURSOR = (1 << 5), } eGPencil_Placement_Flags; /* ToolSettings.particle flag */ diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h new file mode 100644 index 00000000000..15147cf2b6c --- /dev/null +++ b/source/blender/makesdna/DNA_shader_fx_types.h @@ -0,0 +1,196 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file DNA_shader_fx_types.h + * \ingroup DNA + */ + +#ifndef __DNA_SHADERFX_TYPES_H__ +#define __DNA_SHADERFX_TYPES_H__ + +#include "DNA_defs.h" +#include "DNA_listBase.h" + +struct DRWShadingGroup; + +/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! + * (ONLY ADD NEW ITEMS AT THE END) + */ + +typedef enum ShaderFxType { + eShaderFxType_None = 0, + eShaderFxType_Blur = 1, + eShaderFxType_Flip = 2, + eShaderFxType_Light = 3, + eShaderFxType_Pixel = 4, + eShaderFxType_Swirl = 5, + eShaderFxType_Wave = 6, + eShaderFxType_Rim = 7, + eShaderFxType_Colorize = 8, + NUM_SHADER_FX_TYPES +} ShaderFxType; + +typedef enum ShaderFxMode { + eShaderFxMode_Realtime = (1 << 0), + eShaderFxMode_Render = (1 << 1), + eShaderFxMode_Editmode = (1 << 2), + eShaderFxMode_Expanded = (1 << 3), +} ShaderFxMode; + +typedef enum { + /* This fx has been inserted in local override, and hence can be fully edited. */ + eShaderFxFlag_StaticOverride_Local = (1 << 0), +} ShaderFxFlag; + +typedef struct ShaderFxData { + struct ShaderFxData *next, *prev; + + int type, mode; + int stackindex; + short flag; + short pad; + char name[64]; /* MAX_NAME */ + + char *error; +} ShaderFxData; + +/* Runtime temp data */ +typedef struct ShaderFxData_runtime { + struct DRWShadingGroup *fx_sh; + struct DRWShadingGroup *fx_sh_b; + struct DRWShadingGroup *fx_sh_c; +} ShaderFxData_runtime; + +typedef struct BlurShaderFxData { + ShaderFxData shaderfx; + int radius[2]; + int flag; /* flags */ + int samples; /* number of samples */ + float coc; /* circle of confusion */ + int blur[2]; /* not visible in rna */ + char pad[4]; + ShaderFxData_runtime runtime; +} BlurShaderFxData; + +typedef enum eBlurShaderFx_Flag { + FX_BLUR_DOF_MODE = (1 << 0) +} eBlurShaderFx_Flag; + +typedef struct ColorizeShaderFxData { + ShaderFxData shaderfx; + int mode; + float low_color[4]; + float high_color[4]; + float factor; + int flag; /* flags */ + char pad[4]; + ShaderFxData_runtime runtime; +} ColorizeShaderFxData; + +typedef enum ColorizeShaderFxModes { + eShaderFxColorizeMode_GrayScale = 0, + eShaderFxColorizeMode_Sepia = 1, + eShaderFxColorizeMode_BiTone = 2, + eShaderFxColorizeMode_Custom = 3, + eShaderFxColorizeMode_Transparent = 4, +} ColorizeShaderFxModes; + +typedef struct FlipShaderFxData { + ShaderFxData shaderfx; + int flag; /* flags */ + int flipmode; /* internal, not visible in rna */ + ShaderFxData_runtime runtime; +} FlipShaderFxData; + +typedef enum eFlipShaderFx_Flag { + FX_FLIP_HORIZONTAL = (1 << 0), + FX_FLIP_VERTICAL = (1 << 1), +} eFlipShaderFx_Flag; + +typedef struct LightShaderFxData { + ShaderFxData shaderfx; + struct Object *object; + int flag; /* flags */ + float energy; + float ambient; + float loc[4]; /* internal, not visible in rna */ + char pad[4]; + ShaderFxData_runtime runtime; +} LightShaderFxData; + +typedef struct PixelShaderFxData { + ShaderFxData shaderfx; + int size[3]; /* last element used for shader only */ + int flag; /* flags */ + float rgba[4]; + ShaderFxData_runtime runtime; +} PixelShaderFxData; + +typedef enum ePixelShaderFx_Flag { + FX_PIXEL_USE_LINES = (1 << 0), +} ePixelShaderFx_Flag; + +typedef struct RimShaderFxData { + ShaderFxData shaderfx; + int offset[2]; + int flag; /* flags */ + float rim_rgb[3]; + float mask_rgb[3]; + int mode; + int blur[2]; + int samples; + char pad[4]; + ShaderFxData_runtime runtime; +} RimShaderFxData; + +typedef enum RimShaderFxModes { + eShaderFxRimMode_Normal = 0, + eShaderFxRimMode_Overlay = 1, + eShaderFxRimMode_Add = 2, + eShaderFxRimMode_Subtract = 3, + eShaderFxRimMode_Multiply = 4, + eShaderFxRimMode_Divide = 5, +} RimShaderFxModes; + +typedef struct SwirlShaderFxData { + ShaderFxData shaderfx; + struct Object *object; + int flag; /* flags */ + int radius; + float angle; + int transparent; /* not visible in rna */ + ShaderFxData_runtime runtime; +} SwirlShaderFxData; + +typedef enum eSwirlShaderFx_Flag { + FX_SWIRL_MAKE_TRANSPARENT = (1 << 0), +} eSwirlShaderFx_Flag; + +typedef struct WaveShaderFxData { + ShaderFxData shaderfx; + float amplitude; + float period; + float phase; + int orientation; + int flag; /* flags */ + char pad[4]; + ShaderFxData_runtime runtime; +} WaveShaderFxData; +#endif /* __DNA_SHADERFX_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index d6d043b03ae..5404f4160fd 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -198,6 +198,7 @@ typedef enum eSpaceButtons_Context { BCONTEXT_VIEW_LAYER = 13, BCONTEXT_TOOL = 14, BCONTEXT_WORKSPACE = 15, + BCONTEXT_SHADERFX = 16, /* always as last... */ BCONTEXT_TOT @@ -1346,7 +1347,7 @@ typedef enum eSpaceClip_Flag { SC_SHOW_GRID = (1 << 9), SC_SHOW_STABLE = (1 << 10), SC_MANUAL_CALIBRATION = (1 << 11), - SC_SHOW_GPENCIL = (1 << 12), + SC_SHOW_ANNOTATION = (1 << 12), SC_SHOW_FILTERS = (1 << 13), SC_SHOW_GRAPH_FRAMES = (1 << 14), SC_SHOW_GRAPH_TRACKS_MOTION = (1 << 15), diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index e7a540f9afc..cb2c69e2fa1 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -651,7 +651,9 @@ typedef struct UserDef { struct WalkNavigation walk_navigation; short opensubdiv_compute_type; - char pad5[6]; + short gpencil_multisamples; /* eMultiSample_Type, amount of samples for Grease Pencil */ + + char pad5[4]; } UserDef; extern UserDef U; /* from blenkernel blender.c */ @@ -958,7 +960,7 @@ typedef enum eNdof_Flag { #define NDOF_PIXELS_PER_SECOND 600.0f -/* UserDef.ogl_multisamples */ +/* UserDef.ogl_multisamples and gpencil_multisamples */ typedef enum eMultiSample_Type { USER_MULTISAMPLE_NONE = 0, USER_MULTISAMPLE_2 = 2, diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index bbbaf8bb957..27b07a317ed 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -190,6 +190,14 @@ typedef struct View3DOverlay { float wireframe_threshold; char _pad0[4]; + /* grease pencil setttings */ + float gpencil_grid_scale; + float gpencil_paper_opacity; + int gpencil_grid_lines; + int gpencil_grid_axis; + float gpencil_grid_opacity; + char _pad1[4]; + } View3DOverlay; /* 3D ViewPort Struct */ @@ -256,7 +264,8 @@ typedef struct View3D { char multiview_eye; /* multiview current eye - for internal use */ - char pad3[4]; + /* actually only used to define the opacity of the grease pencil vertex in edit mode */ + float vertex_opacity; /* note, 'fx_settings.dof' is currently _not_ allocated, * instead set (temporarily) from camera */ @@ -340,7 +349,7 @@ typedef struct View3D { /* View3d->flag2 (short) */ #define V3D_RENDER_OVERRIDE (1 << 2) #define V3D_SOLID_TEX (1 << 3) -#define V3D_SHOW_GPENCIL (1 << 4) +#define V3D_SHOW_ANNOTATION (1 << 4) #define V3D_LOCK_CAMERA (1 << 5) #define V3D_RENDER_SHADOW (1 << 6) /* This is a runtime only flag that's used to tell draw_mesh_object() that we're doing a shadow pass instead of a regular draw */ #define V3D_SHOW_RECONSTRUCTION (1 << 7) @@ -353,9 +362,13 @@ typedef struct View3D { #define V3D_OCCLUDE_WIRE (1 << 14) #define V3D_SHOW_MODE_SHADE_OVERRIDE (1 << 15) /* XXX: DNA deprecated */ - /* View3d->flag3 (short) */ -#define V3D_SHOW_WORLD (1 << 0) /* LEGACY replaced by V3D_SHADING_BACKGROUND_WORLD */ +#define V3D_SHOW_WORLD (1 << 0) /* LEGACY replaced by V3D_SHADING_BACKGROUND_WORLD */ +#define V3D_GP_SHOW_PAPER (1 << 2) /* Activate paper to cover all viewport */ +#define V3D_GP_SHOW_GRID (1 << 3) /* Activate paper grid */ +#define V3D_GP_SHOW_EDIT_LINES (1 << 4) +#define V3D_GP_SHOW_MULTIEDIT_LINES (1 << 5) +#define V3D_GP_SHOW_ONION_SKIN (1 << 6) /* main switch at view level */ /* View3DShading->light */ enum { @@ -482,4 +495,12 @@ enum { #define RV3D_CAMZOOM_MIN_FACTOR 0.1657359312880714853f #define RV3D_CAMZOOM_MAX_FACTOR 44.9852813742385702928f +/* View3d.gpencil_grid_axis */ +enum { + V3D_GP_GRID_AXIS_LOCK = (1 << 0), + V3D_GP_GRID_AXIS_X = (1 << 1), + V3D_GP_GRID_AXIS_Y = (1 << 2), + V3D_GP_GRID_AXIS_Z = (1 << 3), +}; + #endif diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index a1bfac66115..7b27ec05865 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -113,6 +113,8 @@ static const char *includefiles[] = { "DNA_particle_types.h", "DNA_cloth_types.h", "DNA_gpencil_types.h", + "DNA_gpencil_modifier_types.h", + "DNA_shader_fx_types.h", "DNA_windowmanager_types.h", "DNA_anim_types.h", "DNA_boid_types.h", @@ -1337,6 +1339,8 @@ int main(int argc, char **argv) #include "DNA_particle_types.h" #include "DNA_cloth_types.h" #include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_windowmanager_types.h" #include "DNA_anim_types.h" #include "DNA_boid_types.h" diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index cb5e2e61f9a..16194c9b419 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -269,9 +269,6 @@ extern StructRNA RNA_FreestyleSettings; extern StructRNA RNA_Function; extern StructRNA RNA_GPencilFrame; extern StructRNA RNA_GPencilLayer; -extern StructRNA RNA_GPencilPalette; -extern StructRNA RNA_GPencilPaletteColor; -extern StructRNA RNA_GPencilBrush; extern StructRNA RNA_GPencilInterpolateSettings; extern StructRNA RNA_GPencilStroke; extern StructRNA RNA_GPencilStrokePoint; @@ -600,6 +597,31 @@ extern StructRNA RNA_SunLight; extern StructRNA RNA_SurfaceCurve; extern StructRNA RNA_SurfaceDeformModifier; extern StructRNA RNA_SurfaceModifier; +extern StructRNA RNA_GpencilModifier; +extern StructRNA RNA_BuildGpencilModifier; +extern StructRNA RNA_NoiseGpencilModifier; +extern StructRNA RNA_SubdivGpencilModifier; +extern StructRNA RNA_SimplifyGpencilModifier; +extern StructRNA RNA_ThickGpencilModifier; +extern StructRNA RNA_TintGpencilModifier; +extern StructRNA RNA_ColorGpencilModifier; +extern StructRNA RNA_InstanceGpencilModifier; +extern StructRNA RNA_DupliGpencilModifier; +extern StructRNA RNA_OpacityGpencilModifier; +extern StructRNA RNA_LatticeGpencilModifier; +extern StructRNA RNA_MirrorGpencilModifier; +extern StructRNA RNA_SmoothGpencilModifier; +extern StructRNA RNA_HookGpencilModifier; +extern StructRNA RNA_OffsetGpencilModifier; +extern StructRNA RNA_ShaderFx; +extern StructRNA RNA_ShaderFxBlur; +extern StructRNA RNA_ShaderFxColorize; +extern StructRNA RNA_ShaderFxFlip; +extern StructRNA RNA_ShaderFxLight; +extern StructRNA RNA_ShaderFxPixel; +extern StructRNA RNA_ShaderFxRim; +extern StructRNA RNA_ShaderFxSwirl; +extern StructRNA RNA_ShaderFxWave; extern StructRNA RNA_TexMapping; extern StructRNA RNA_Text; extern StructRNA RNA_TextBox; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 043375a066a..4c0861757f4 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -44,6 +44,7 @@ extern const EnumPropertyItem rna_enum_id_type_items[]; extern const EnumPropertyItem rna_enum_object_mode_items[]; extern const EnumPropertyItem rna_enum_object_empty_drawtype_items[]; +extern const EnumPropertyItem rna_enum_object_gpencil_type_items[]; extern const EnumPropertyItem rna_enum_metaelem_type_items[]; extern const EnumPropertyItem rna_enum_proportional_falloff_items[]; @@ -65,6 +66,8 @@ extern const EnumPropertyItem rna_enum_object_modifier_type_items[]; extern const EnumPropertyItem rna_enum_constraint_type_items[]; extern const EnumPropertyItem rna_enum_boidrule_type_items[]; extern const EnumPropertyItem rna_enum_sequence_modifier_type_items[]; +extern const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[]; +extern const EnumPropertyItem rna_enum_object_shaderfx_type_items[]; extern const EnumPropertyItem rna_enum_modifier_triangulate_quad_method_items[]; extern const EnumPropertyItem rna_enum_modifier_triangulate_ngon_method_items[]; @@ -228,6 +231,7 @@ const EnumPropertyItem *rna_node_socket_type_itemf( struct bContext; struct PointerRNA; struct PropertyRNA; + const EnumPropertyItem *rna_TransformOrientation_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free); const EnumPropertyItem *rna_Sensor_type_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free); const EnumPropertyItem *rna_Actuator_type_itemf(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free); diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index eb32a5fc6cb..ec240c222a1 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -49,6 +49,8 @@ set(DEFSRC rna_fcurve.c rna_fluidsim.c rna_gpencil.c + rna_gpencil_modifier.c + rna_shader_fx.c rna_group.c rna_image.c rna_key.c diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 393ebc15d3e..b0713987e16 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3416,6 +3416,8 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh}, {"rna_meta.c", "rna_meta_api.c", RNA_def_meta}, {"rna_modifier.c", NULL, RNA_def_modifier}, + {"rna_gpencil_modifier.c", NULL, RNA_def_greasepencil_modifier}, + {"rna_shader_fx.c", NULL, RNA_def_shader_fx }, {"rna_nla.c", NULL, RNA_def_nla}, {"rna_nodetree.c", NULL, RNA_def_nodetree}, {"rna_object.c", "rna_object_api.c", RNA_def_object}, diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 4f1e29b482d..0f3e74c567f 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -31,6 +31,8 @@ #include "DNA_texture_types.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" +#include "DNA_workspace_types.h" +#include "DNA_gpencil_types.h" #include "BLI_math.h" @@ -122,6 +124,44 @@ const EnumPropertyItem rna_enum_brush_image_tool_items[] = { {0, NULL, 0, NULL, NULL} }; +#ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_gpencil_brush_types_items[] = { + { GP_BRUSH_TYPE_DRAW, "DRAW", ICON_GREASEPENCIL_STROKE_PAINT, "Draw", "The brush is of type used for drawing strokes" }, + { GP_BRUSH_TYPE_FILL, "FILL", ICON_COLOR, "Fill", "The brush is of type used for filling areas" }, + { GP_BRUSH_TYPE_ERASE, "ERASE", ICON_PANEL_CLOSE, "Erase", "The brush is used for erasing strokes" }, + { 0, NULL, 0, NULL, NULL } +}; + +static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = { + { GP_BRUSH_ERASER_SOFT, "SOFT", 0, "Soft", "Use soft eraser" }, + { GP_BRUSH_ERASER_HARD, "HARD", 0, "Hard", "Use hard eraser" }, + { GP_BRUSH_ERASER_STROKE, "STROKE", 0, "Stroke", "Use stroke eraser" }, + { 0, NULL, 0, NULL, NULL } +}; + +static EnumPropertyItem rna_enum_gpencil_fill_draw_modes_items[] = { + { GP_FILL_DMODE_STROKE, "STROKE", 0, "Strokes", "Use visible strokes as fill boundary limits" }, + { GP_FILL_DMODE_CONTROL, "CONTROL", 0, "Control", "Use internal control lines as fill boundary limits" }, + { GP_FILL_DMODE_BOTH, "BOTH", 0, "Both", "Use visible strokes and control lines as fill boundary limits" }, + { 0, NULL, 0, NULL, NULL } +}; + +static EnumPropertyItem rna_enum_gpencil_brush_icons_items[] = { + { GP_BRUSH_ICON_PENCIL, "PENCIL", ICON_GPBRUSH_PENCIL, "Pencil", "" }, + { GP_BRUSH_ICON_PEN, "PEN", ICON_GPBRUSH_PEN, "Pen", "" }, + { GP_BRUSH_ICON_INK, "INK", ICON_GPBRUSH_INK, "Ink", "" }, + { GP_BRUSH_ICON_INKNOISE, "INKNOISE", ICON_GPBRUSH_INKNOISE, "Ink Noise", "" }, + { GP_BRUSH_ICON_BLOCK, "BLOCK", ICON_GPBRUSH_BLOCK, "Block", "" }, + { GP_BRUSH_ICON_MARKER, "MARKER", ICON_GPBRUSH_MARKER, "Marker", "" }, + { GP_BRUSH_ICON_FILL, "FILL", ICON_GPBRUSH_FILL, "Fill", "" }, + { GP_BRUSH_ICON_ERASE_SOFT, "SOFT", ICON_GPBRUSH_ERASE_SOFT, "Eraser Soft", "" }, + { GP_BRUSH_ICON_ERASE_HARD, "HARD", ICON_GPBRUSH_ERASE_HARD, "Eraser Hard", "" }, + { GP_BRUSH_ICON_ERASE_STROKE, "STROKE", ICON_GPBRUSH_ERASE_STROKE, "Eraser Stroke", "" }, + { 0, NULL, 0, NULL, NULL } +}; +#endif + + #ifdef RNA_RUNTIME #include "MEM_guardedalloc.h" @@ -442,6 +482,33 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi WM_main_add_notifier(NC_BRUSH | NA_EDITED, br); } +static const EnumPropertyItem *rna_DynamicGpencil_type_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + Main *bmain = CTX_data_main(C); + EnumPropertyItem *item = NULL, item_tmp = { 0 }; + int totitem = 0; + int i = 0; + + Brush *brush; + for (brush = bmain->brush.first; brush; brush = brush->id.next, i++) { + if (brush->gpencil_settings == NULL) + continue; + + item_tmp.identifier = brush->id.name + 2; + item_tmp.name = brush->id.name + 2; + item_tmp.value = i; + item_tmp.icon = brush->gpencil_settings->icon_id; + + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + static void rna_TextureSlot_brush_angle_update(bContext *C, PointerRNA *ptr) { Scene *scene = CTX_data_scene(C); @@ -615,6 +682,58 @@ static const EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C, PointerRNA *U return brush_stroke_method_items; } } + +/* Grease Pencil Drawing Brushes Settings */ +static void rna_BrushGpencilSettings_default_eraser_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) +{ + ToolSettings *ts = scene->toolsettings; + Paint *paint = &ts->gp_paint->paint; + Brush *brush_cur = paint->brush; + + /* disable default eraser in all brushes */ + for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) { + if ((brush != brush_cur) && + (brush->ob_mode == OB_MODE_GPENCIL_PAINT) && + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) + { + brush->gpencil_settings->flag &= ~GP_BRUSH_DEFAULT_ERASER; + } + } +} + +static void rna_BrushGpencilSettings_eraser_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) +{ + ToolSettings *ts = scene->toolsettings; + Paint *paint = &ts->gp_paint->paint; + Brush *brush = paint->brush; + + /* set eraser icon */ + if ((brush) && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) { + switch (brush->gpencil_settings->eraser_mode) { + case GP_BRUSH_ERASER_SOFT: + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; + break; + case GP_BRUSH_ERASER_HARD: + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD; + break; + case GP_BRUSH_ERASER_STROKE: + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE; + break; + default: + brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT; + break; + } + } +} + +static bool rna_BrushGpencilSettings_material_poll(PointerRNA *UNUSED(ptr), PointerRNA value) +{ + Material *ma = (Material *)value.data; + + /* GP materials only */ + return (ma->gp_style != NULL); +} + #else static void rna_def_brush_texture_slot(BlenderRNA *brna) @@ -809,6 +928,316 @@ static void rna_def_image_paint_capabilities(BlenderRNA *brna) #undef IMAPAINT_TOOL_CAPABILITY } +static void rna_def_gpencil_options(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* Grease Pencil Drawing - generated dynamically */ + static const EnumPropertyItem prop_dynamic_gpencil_type[] = { + { 1, "DRAW", 0, "Draw", "" }, + { 0, NULL, 0, NULL, NULL } + }; + + srna = RNA_def_struct(brna, "BrushGpencilSettings", NULL); + RNA_def_struct_sdna(srna, "BrushGpencilSettings"); + RNA_def_struct_ui_text(srna, "Grease Pencil Brush Settings", "Settings for grease pencil brush"); + + /* grease pencil drawing brushes */ + prop = RNA_def_property(srna, "grease_pencil_tool", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "brush_type"); + RNA_def_property_enum_items(prop, prop_dynamic_gpencil_type); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_DynamicGpencil_type_itemf"); + RNA_def_property_ui_text(prop, "Grease Pencil Tool", ""); + /* TODO: GPXX review update */ + RNA_def_property_update(prop, 0, NULL); + //RNA_def_property_update(prop, 0, "rna_Brush_gpencil_tool_update"); + + /* Sensitivity factor for new strokes */ + prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity"); + RNA_def_property_range(prop, 0.1f, 3.0f); + RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Strength factor for new strokes */ + prop = RNA_def_property(srna, "pen_strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_strength"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Jitter factor for new strokes */ + prop = RNA_def_property(srna, "pen_jitter", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_jitter"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Randomnes factor for pressure */ + prop = RNA_def_property(srna, "random_pressure", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_random_press"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Pressure Randomness", "Randomness factor for pressure in new strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Randomnes factor for strength */ + prop = RNA_def_property(srna, "random_strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_random_strength"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Strength Randomness", "Randomness factor strength in new strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Randomnes factor for subdivision */ + prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_random_sub"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Random Subdivision", "Randomness factor for new strokes after subdivision"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Angle when brush is full size */ + prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "draw_angle"); + RNA_def_property_range(prop, -M_PI_2, M_PI_2); + RNA_def_property_ui_text(prop, "Angle", + "Direction of the stroke at which brush gives maximal thickness " + "(0° for horizontal)"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Factor to change brush size depending of angle */ + prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Angle Factor", + "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Smoothing factor for new strokes */ + prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac"); + RNA_def_property_range(prop, 0.0, 2.0f); + RNA_def_property_ui_text(prop, "Smooth", + "Amount of smoothing to apply after finish newly created strokes, to reduce jitter/noise"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Iterations of the Smoothing factor */ + prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl"); + RNA_def_property_range(prop, 1, 3); + RNA_def_property_ui_text(prop, "Iterations", + "Number of times to smooth newly created strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Thickness smoothing factor for new strokes */ + prop = RNA_def_property(srna, "pen_thick_smooth_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "thick_smoothfac"); + RNA_def_property_range(prop, 0.0, 2.0f); + RNA_def_property_ui_text(prop, "Smooth Thickness", + "Amount of thickness smoothing to apply after finish newly created strokes, to reduce jitter/noise"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Thickness iterations of the Smoothing factor */ + prop = RNA_def_property(srna, "pen_thick_smooth_steps", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "thick_smoothlvl"); + RNA_def_property_range(prop, 1, 3); + RNA_def_property_ui_text(prop, "Iterations Thickness", + "Number of times to smooth thickness for newly created strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Subdivision level for new strokes */ + prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "draw_subdivide"); + RNA_def_property_range(prop, 0, 3); + RNA_def_property_ui_text(prop, "Subdivision Steps", + "Number of times to subdivide newly created strokes, for less jagged strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Curves for pressure */ + prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "curve_sensitivity"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "curve_strength"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "curve_jitter"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* fill threshold for transparence */ + prop = RNA_def_property(srna, "gpencil_fill_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "fill_threshold"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Threshold", + "Threshold to consider color transparent for filling"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* fill leak size */ + prop = RNA_def_property(srna, "gpencil_fill_leak", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "fill_leak"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Leak Size", + "Size in pixels to consider the leak closed"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* fill simplify steps */ + prop = RNA_def_property(srna, "gpencil_fill_simplyfy_level", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "fill_simplylvl"); + RNA_def_property_range(prop, 0, 10); + RNA_def_property_ui_text(prop, "Simplify", + "Number of simplify steps (large values reduce fill accuracy)"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "uv_random", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "uv_random"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "UV Random", "Random factor for autogenerated UV rotation"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "input_samples", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "input_samples"); + RNA_def_property_range(prop, 0, GP_MAX_INPUT_SAMPLES); + RNA_def_property_ui_text(prop, "Input Samples", "Generate intermediate points for very fast mouse movements. Set to 0 to disable"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* active smooth factor while drawing */ + prop = RNA_def_property(srna, "active_smooth_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "active_smooth"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Active Smooth", + "Amount of smoothing while drawing "); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* brush standard icon */ + prop = RNA_def_property(srna, "gp_icon", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "icon_id"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_icons_items); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_ui_text(prop, "Grease Pencil Icon", ""); + + /* Flags */ + prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE); + RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); + RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE); + RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); + RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE); + RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); + RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "use_stabilizer", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_STABILIZE_MOUSE); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text(prop, "Stabilizer", + "Draw lines with a delay to allow smooth strokes. Press Shift key to override while drawing"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_ENABLE_CURSOR); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "gpencil_brush_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "brush_type"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_types_items); + RNA_def_property_ui_text(prop, "Type", "Category of the brush"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "eraser_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "eraser_mode"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_brush_eraser_modes_items); + RNA_def_property_ui_text(prop, "Mode", "Eraser Mode"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_eraser_mode_update"); + + prop = RNA_def_property(srna, "gpencil_fill_draw_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "fill_draw_mode"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_fill_draw_modes_items); + RNA_def_property_ui_text(prop, "Mode", "Mode to draw boundary limits"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + /* Material */ + prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Material"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_BrushGpencilSettings_material_poll"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_ui_text(prop, "Material", "Material used for strokes drawn using this brush"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + prop = RNA_def_property(srna, "gpencil_fill_show_boundary", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_SHOW_HELPLINES); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text(prop, "Show Lines", "Show help lines for filling to see boundaries"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "gpencil_fill_hide", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_HIDE); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text(prop, "Hide", "Hide transparent lines to use as boundary for filling"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "default_eraser", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_DEFAULT_ERASER); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_icon(prop, ICON_UNPINNED, 1); + RNA_def_property_ui_text(prop, "Default Eraser", "Use this brush when enable eraser with fast switch key"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_BrushGpencilSettings_default_eraser_update"); + + prop = RNA_def_property(srna, "enable_settings", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_SETTINGS); + RNA_def_property_ui_text(prop, "Settings", "Enable additional post processing options for new strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "enable_random", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_GROUP_RANDOM); + RNA_def_property_ui_text(prop, "Random Settings", "Enable random settings for brush"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); +} + static void rna_def_brush(BlenderRNA *brna) { StructRNA *srna; @@ -1373,6 +1802,10 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_TEXTURE_PAINT); RNA_def_property_ui_text(prop, "Use Texture", "Use this brush in texture paint mode"); + prop = RNA_def_property(srna, "use_paint_grease_pencil", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ob_mode", OB_MODE_GPENCIL_PAINT); + RNA_def_property_ui_text(prop, "Use Sculpt", "Use this brush in grease pencil drawing mode"); + /* texture */ prop = RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "BrushTextureSlot"); @@ -1475,6 +1908,13 @@ static void rna_def_brush(BlenderRNA *brna) RNA_def_property_struct_type(prop, "ImapaintToolCapabilities"); RNA_def_property_pointer_funcs(prop, "rna_Imapaint_tool_capabilities_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Image Painting Capabilities", "Brush's capabilities in image paint mode"); + + prop = RNA_def_property(srna, "gpencil_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "BrushGpencilSettings"); + RNA_def_property_pointer_sdna(prop, NULL, "gpencil_settings"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Gpencil Settings", ""); + } @@ -1543,6 +1983,7 @@ void RNA_def_brush(BlenderRNA *brna) rna_def_brush_capabilities(brna); rna_def_sculpt_capabilities(brna); rna_def_image_paint_capabilities(brna); + rna_def_gpencil_options(brna); rna_def_brush_texture_slot(brna); rna_def_operator_stroke_element(brna); } diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 7b07faf8ee7..781be07f1dc 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -52,6 +52,10 @@ const EnumPropertyItem rna_enum_context_mode_items[] = { {CTX_MODE_PAINT_TEXTURE, "PAINT_TEXTURE", 0, "Texture Paint", ""}, {CTX_MODE_PARTICLE, "PARTICLE", 0, "Particle", ""}, {CTX_MODE_OBJECT, "OBJECT", 0, "Object", ""}, + {CTX_MODE_GPENCIL_PAINT, "GPENCIL_PAINT", 0, "Grease Pencil Paint", "" }, + {CTX_MODE_GPENCIL_EDIT, "GPENCIL_EDIT", 0, "Grease Pencil Edit", "" }, + {CTX_MODE_GPENCIL_SCULPT, "GPENCIL_SCULPT", 0, "Grease Pencil Sculpt", "" }, + {CTX_MODE_GPENCIL_WEIGHT, "GPENCIL_WEIGHT", 0, "Grease Pencil Weight Paint", "" }, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index d9dba4679e0..f84f31b02f1 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -26,8 +26,12 @@ #include +#include "BLI_math.h" + +#include "DNA_meshdata_types.h" #include "DNA_gpencil_types.h" #include "DNA_scene_types.h" +#include "DNA_brush_types.h" #include "MEM_guardedalloc.h" @@ -38,10 +42,12 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" #include "WM_types.h" +#include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "ED_gpencil.h" @@ -53,31 +59,54 @@ static const EnumPropertyItem parent_type_items[] = { {0, NULL, 0, NULL, NULL} }; +#ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_gpencil_xraymodes_items[] = { + { GP_XRAY_FRONT, "FRONT", 0, "Front", "Draw all strokes in front" }, + { GP_XRAY_3DSPACE, "3DSPACE", 0, "3DSpace", "Draw strokes relative to other objects in 3D space" }, + { GP_XRAY_BACK, "BACK", 0, "Back", "Draw all strokes on back" }, + { 0, NULL, 0, NULL, NULL } +}; + +static EnumPropertyItem rna_enum_gpencil_onion_modes_items[] = { + { GP_ONION_MODE_ABSOLUTE, "ABSOLUTE", 0, "Frames", "Frames in absolute range of scene frame number" }, + { GP_ONION_MODE_RELATIVE, "RELATIVE", 0, "Keyframes", "Frames in relative range of grease pencil keyframes" }, + { GP_ONION_MODE_SELECTED, "SELECTED", 0, "Selected", "Only Selected Frames" }, + { 0, NULL, 0, NULL, NULL } +}; +#endif #ifdef RNA_RUNTIME #include "BLI_math.h" +#include "BLI_ghash.h" #include "WM_api.h" +#include "BKE_action.h" #include "BKE_animsys.h" #include "BKE_gpencil.h" -#include "BKE_action.h" +#include "BKE_icons.h" +#include "DEG_depsgraph.h" -static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) + +static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { + DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA); WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } -static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +static void rna_GPencil_editmode_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { + bGPdata *gpd = (bGPdata *)ptr->id.data; + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + /* Notify all places where GPencil data lives that the editing state is different */ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); WM_main_add_notifier(NC_SCENE | ND_MODE | NC_MOVIECLIP, NULL); } -static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, PointerRNA *ptr) +static void UNUSED_FUNCTION(rna_GPencil_onion_skinning_update)(Main *bmain, Scene *scene, PointerRNA *ptr) { bGPdata *gpd = (bGPdata *)ptr->id.data; bGPDlayer *gpl; @@ -87,7 +116,7 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer * stays in sync with the status of the actual layers */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->flag & GP_LAYER_ONIONSKIN) { + if (gpl->onion_flag & GP_LAYER_ONIONSKIN) { enabled = true; } } @@ -102,16 +131,22 @@ static void rna_GPencil_onion_skinning_update(Main *bmain, Scene *scene, Pointer rna_GPencil_update(bmain, scene, ptr); } -static void rna_GPencil_stroke_colorname_update(Main *bmain, Scene *scene, PointerRNA *ptr) + +/* Poll Callback to filter GP Datablocks to only show those for Annotations */ +bool rna_GPencil_datablocks_annotations_poll(PointerRNA *UNUSED(ptr), const PointerRNA value) { - bGPDstroke *gps = (bGPDstroke *)ptr->data; - gps->flag |= GP_STROKE_RECALC_COLOR; - gps->palcolor = NULL; + bGPdata *gpd = value.data; + return (gpd->flag & GP_DATA_ANNOTATIONS) != 0; +} - /* Now do standard updates... */ - rna_GPencil_update(bmain, scene, ptr); +/* Poll Callback to filter GP Datablocks to only show those for GP Objects */ +bool rna_GPencil_datablocks_obdata_poll(PointerRNA *UNUSED(ptr), const PointerRNA value) +{ + bGPdata *gpd = value.data; + return (gpd->flag & GP_DATA_ANNOTATIONS) == 0; } + static char *rna_GPencilLayer_path(PointerRNA *ptr) { bGPDlayer *gpl = (bGPDlayer *)ptr->data; @@ -133,36 +168,6 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr, const char ** return PROP_EDITABLE; } -static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *max, - int *softmin, int *softmax) -{ - bGPDlayer *gpl = ptr->data; - - /* The restrictions on max width here are due to OpenGL on Windows not supporting - * any widths greater than 10 (for driver-drawn) strokes/points. - * - * Although most of our 2D strokes also don't suffer from this restriction, - * it's relatively hard to test for that. So, for now, only volumetric strokes - * get to be larger... - */ - - /* From GP v2 this value is used to increase or decrease the thickness of the stroke */ - if (gpl->flag & GP_LAYER_VOLUMETRIC) { - *min = -300; - *max = 300; - - *softmin = -100; - *softmax = 100; - } - else { - *min = -10; - *max = 10; - - *softmin = -10; - *softmax = 10; - } -} - /* set parent */ static void set_parent(bGPDlayer *gpl, Object *par, const int type, const char *substr) { @@ -202,21 +207,6 @@ static void rna_GPencilLayer_parent_set(PointerRNA *ptr, PointerRNA value) set_parent(gpl, par, gpl->partype, gpl->parsubstr); } else { - /* keep strokes in the same place, so apply current transformation */ - if (gpl->parent != NULL) { - bGPDspoint *pt; - int i; - float diff_mat[4][4]; - /* calculate difference matrix */ - ED_gpencil_parent_location(gpl, diff_mat); - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - mul_m4_v3(diff_mat, &pt->x); - } - } - } - } /* clear parent */ gpl->parent = NULL; } @@ -306,6 +296,15 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value) { bGPdata *gpd = ptr->id.data; + /* Don't allow setting active layer to NULL if layers exist + * as this breaks various tools. Tools should be used instead + * if it's necessary to remove layers + */ + if (value.data == NULL) { + printf("%s: Setting active layer to None is not allowed\n", __func__); + return; + } + if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */ bGPDlayer *gl; @@ -349,6 +348,36 @@ static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int *softmax = *max; } +static const EnumPropertyItem *rna_GPencil_active_layer_itemf( + bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + bGPdata *gpd = (bGPdata *)ptr->id.data; + bGPDlayer *gpl; + EnumPropertyItem *item = NULL, item_tmp = {0}; + int totitem = 0; + int i = 0; + + if (ELEM(NULL, C, gpd)) { + return DummyRNA_NULL_items; + } + + /* Existing layers */ + for (gpl = gpd->layers.first, i = 0; gpl; gpl = gpl->next, i++) { + item_tmp.identifier = gpl->info; + item_tmp.name = gpl->info; + item_tmp.value = i; + + item_tmp.icon = BKE_icon_gplayer_color_ensure(gpl); + + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value) { bGPdata *gpd = ptr->id.data; @@ -366,31 +395,6 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value) BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info); } -static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const bool value) -{ - bGPdata *gpd = ptr->id.data; - bGPDlayer *gpl; - - /* set new value */ - if (value) { - /* enable on active layer (it's the one that's most likely to be of interest right now) */ - gpl = BKE_gpencil_layer_getactive(gpd); - if (gpl) { - gpl->flag |= GP_LAYER_ONIONSKIN; - } - - gpd->flag |= GP_DATA_SHOW_ONIONSKINS; - } - else { - /* disable on all layers - allowa quickly turning them all off, without having to check */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - gpl->flag &= ~GP_LAYER_ONIONSKIN; - } - - gpd->flag &= ~GP_DATA_SHOW_ONIONSKINS; - } -} - static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd, const bGPDspoint *pt, bGPDlayer **r_gpl, bGPDframe **r_gpf) { bGPDlayer *gpl; @@ -454,14 +458,21 @@ static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pr stroke->points = MEM_recallocN_id(stroke->points, sizeof(bGPDspoint) * (stroke->totpoints + count), "gp_stroke_points"); + stroke->dvert = MEM_recallocN_id(stroke->dvert, + sizeof(MDeformVert) * (stroke->totpoints + count), + "gp_stroke_weight"); /* init the pressure and strength values so that old scripts won't need to * be modified to give these initial values... */ for (int i = 0; i < count; i++) { bGPDspoint *pt = stroke->points + (stroke->totpoints + i); + MDeformVert *dvert = stroke->dvert + (stroke->totpoints + i); pt->pressure = pressure; pt->strength = strength; + + dvert->totweight = 0; + dvert->dw = NULL; } stroke->totpoints += count; @@ -471,6 +482,7 @@ static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pr static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports, int index) { bGPDspoint *pt_tmp = stroke->points; + MDeformVert *pt_dvert = stroke->dvert; /* python style negative indexing */ if (index < 0) { @@ -485,27 +497,35 @@ static void rna_GPencil_stroke_point_pop(bGPDstroke *stroke, ReportList *reports stroke->totpoints--; stroke->points = MEM_callocN(sizeof(bGPDspoint) * stroke->totpoints, "gp_stroke_points"); + stroke->dvert = MEM_callocN(sizeof(MDeformVert) * stroke->totpoints, "gp_stroke_weights"); - if (index > 0) + if (index > 0) { memcpy(stroke->points, pt_tmp, sizeof(bGPDspoint) * index); + /* verify weight data is available */ + if (pt_dvert != NULL) { + memcpy(stroke->dvert, pt_dvert, sizeof(MDeformVert) * index); + } + } - if (index < stroke->totpoints) + if (index < stroke->totpoints) { memcpy(&stroke->points[index], &pt_tmp[index + 1], sizeof(bGPDspoint) * (stroke->totpoints - index)); + if (pt_dvert != NULL) { + memcpy(&stroke->dvert[index], &pt_dvert[index + 1], sizeof(MDeformVert) * (stroke->totpoints - index)); + } + } /* free temp buffer */ MEM_freeN(pt_tmp); + if (pt_dvert != NULL) { + MEM_freeN(pt_dvert); + } WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } -static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame, const char *colorname) +static bGPDstroke *rna_GPencil_stroke_new(bGPDframe *frame) { bGPDstroke *stroke = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); - if (colorname) { - BLI_strncpy(stroke->colorname, colorname, sizeof(stroke->colorname)); - } - stroke->palcolor = NULL; - stroke->flag |= GP_STROKE_RECALC_COLOR; BLI_addtail(&frame->strokes, stroke); return stroke; @@ -635,260 +655,18 @@ static void rna_GPencil_clear(bGPdata *gpd) WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } -/* Palettes */ -static bGPDpalette *rna_GPencil_palette_new(bGPdata *gpd, const char *name, bool setactive) -{ - bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, name, setactive != 0); - - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return palette; -} - -static void rna_GPencil_palette_remove(bGPdata *gpd, ReportList *reports, PointerRNA *palette_ptr) -{ - bGPDpalette *palette = palette_ptr->data; - if (BLI_findindex(&gpd->palettes, palette) == -1) { - BKE_report(reports, RPT_ERROR, "Palette not found in grease pencil data"); - return; - } - - BKE_gpencil_palette_delete(gpd, palette); - RNA_POINTER_INVALIDATE(palette_ptr); - - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -static PointerRNA rna_GPencil_active_palette_get(PointerRNA *ptr) -{ - bGPdata *gpd = ptr->id.data; - - if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */ - bGPDpalette *palette; - - for (palette = gpd->palettes.first; palette; palette = palette->next) { - if (palette->flag & PL_PALETTE_ACTIVE) { - break; - } - } - - if (palette) { - return rna_pointer_inherit_refine(ptr, &RNA_GPencilPalette, palette); - } - } - - return rna_pointer_inherit_refine(ptr, NULL, NULL); -} - -static void rna_GPencil_active_palette_set(PointerRNA *ptr, PointerRNA value) -{ - bGPdata *gpd = ptr->id.data; - - if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */ - bGPDpalette *palette; - - for (palette = gpd->palettes.first; palette; palette = palette->next) { - if (palette == value.data) { - palette->flag |= PL_PALETTE_ACTIVE; - } - else { - palette->flag &= ~PL_PALETTE_ACTIVE; - } - } - /* force color recalc */ - BKE_gpencil_palette_change_strokes(gpd); - - WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); - } -} - -static int rna_GPencilPalette_index_get(PointerRNA *ptr) -{ - bGPdata *gpd = (bGPdata *)ptr->id.data; - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - - return BLI_findindex(&gpd->palettes, palette); -} - -static void rna_GPencilPalette_index_set(PointerRNA *ptr, int value) -{ - bGPdata *gpd = (bGPdata *)ptr->id.data; - bGPDpalette *palette = BLI_findlink(&gpd->palettes, value); - - BKE_gpencil_palette_setactive(gpd, palette); - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -static void rna_GPencilPalette_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) -{ - bGPdata *gpd = (bGPdata *)ptr->id.data; - - *min = 0; - *max = max_ii(0, BLI_listbase_count(&gpd->palettes) - 1); - - *softmin = *min; - *softmax = *max; -} - -/* Palette colors */ -static bGPDpalettecolor *rna_GPencilPalette_color_new(bGPDpalette *palette) -{ - bGPDpalettecolor *color = BKE_gpencil_palettecolor_addnew(palette, DATA_("Color"), true); - - return color; -} - -static void rna_GPencilPalette_color_remove(bGPDpalette *palette, ReportList *reports, PointerRNA *color_ptr) -{ - bGPDpalettecolor *color = color_ptr->data; - - if (BLI_findindex(&palette->colors, color) == -1) { - BKE_reportf(reports, RPT_ERROR, "Palette '%s' does not contain color given", palette->info + 2); - return; - } - - BKE_gpencil_palettecolor_delete(palette, color); - RNA_POINTER_INVALIDATE(color_ptr); - - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -static PointerRNA rna_GPencilPalette_active_color_get(PointerRNA *ptr) -{ - bGPDpalette *palette = (bGPDpalette *)ptr->data; - bGPDpalettecolor *color; - - for (color = palette->colors.first; color; color = color->next) { - if (color->flag & PC_COLOR_ACTIVE) { - break; - } - } - - if (color) { - return rna_pointer_inherit_refine(ptr, &RNA_GPencilPaletteColor, color); - } - - return rna_pointer_inherit_refine(ptr, NULL, NULL); -} - -static void rna_GPencilPalette_active_color_set(PointerRNA *ptr, PointerRNA value) -{ - bGPDpalette *palette = (bGPDpalette *)ptr->data; - bGPDpalettecolor *color = value.data; - - BKE_gpencil_palettecolor_setactive(palette, color); -} - -static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value) -{ - bGPdata *gpd = ptr->id.data; - bGPDpalette *palette = ptr->data; - - char oldname[64] = ""; - BLI_strncpy(oldname, palette->info, sizeof(oldname)); - - /* copy the new name into the name slot */ - BLI_strncpy_utf8(palette->info, value, sizeof(palette->info)); - - BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info), - sizeof(palette->info)); - /* now fix animation paths */ - BKE_animdata_fix_paths_rename_all(&gpd->id, "palettes", oldname, palette->info); -} - -static char *rna_GPencilPalette_path(PointerRNA *ptr) -{ - bGPDpalette *palette = ptr->data; - char name_esc[sizeof(palette->info) * 2]; - - BLI_strescape(name_esc, palette->info, sizeof(name_esc)); - - return BLI_sprintfN("palettes[\"%s\"]", name_esc); -} - -static char *rna_GPencilPalette_color_path(PointerRNA *ptr) -{ - bGPdata *gpd = ptr->id.data; - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = ptr->data; - - char name_palette[sizeof(palette->info) * 2]; - char name_color[sizeof(palcolor->info) * 2]; - - BLI_strescape(name_palette, palette->info, sizeof(name_palette)); - BLI_strescape(name_color, palcolor->info, sizeof(name_color)); - - return BLI_sprintfN("palettes[\"%s\"].colors[\"%s\"]", name_palette, name_color); -} - -static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value) -{ - bGPdata *gpd = ptr->id.data; - bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); - bGPDpalettecolor *palcolor = ptr->data; - - char oldname[64] = ""; - BLI_strncpy(oldname, palcolor->info, sizeof(oldname)); - - /* copy the new name into the name slot */ - BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info)); - BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info), - sizeof(palcolor->info)); - - /* rename all strokes */ - BKE_gpencil_palettecolor_changename(gpd, oldname, palcolor->info); - - /* now fix animation paths */ - BKE_animdata_fix_paths_rename_all(&gpd->id, "colors", oldname, palcolor->info); -} - -static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value) +static void rna_GpencilVertex_groups_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { bGPDstroke *gps = ptr->data; - /* copy the new name into the name slot */ - BLI_strncpy_utf8(gps->colorname, value, sizeof(gps->colorname)); -} + if (gps->dvert) { + MDeformVert *dvert = gps->dvert; - -static bool rna_GPencilPaletteColor_is_stroke_visible_get(PointerRNA *ptr) -{ - bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data; - return (pcolor->color[3] > GPENCIL_ALPHA_OPACITY_THRESH); -} - -static bool rna_GPencilPaletteColor_is_fill_visible_get(PointerRNA *ptr) -{ - bGPDpalettecolor *pcolor = (bGPDpalettecolor *)ptr->data; - return (pcolor->fill[3] > GPENCIL_ALPHA_OPACITY_THRESH); -} - -static int rna_GPencilPaletteColor_index_get(PointerRNA *ptr) -{ - bGPDpalette *palette = (bGPDpalette *)ptr->data; - bGPDpalettecolor *pcolor = BKE_gpencil_palettecolor_getactive(palette); - - return BLI_findindex(&palette->colors, pcolor); -} - -static void rna_GPencilPaletteColor_index_set(PointerRNA *ptr, int value) -{ - bGPDpalette *palette = (bGPDpalette *)ptr->data; - bGPDpalettecolor *pcolor = BLI_findlink(&palette->colors, value); - BKE_gpencil_palettecolor_setactive(palette, pcolor); -} - -static void rna_GPencilPaletteColor_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) -{ - bGPDpalette *palette = (bGPDpalette *)ptr->data; - - *min = 0; - *max = max_ii(0, BLI_listbase_count(&palette->colors) - 1); - - *softmin = *min; - *softmax = *max; + rna_iterator_array_begin(iter, (void *)dvert->dw, sizeof(MDeformWeight), dvert->totweight, 0, NULL); + } + else + rna_iterator_array_begin(iter, NULL, 0, 0, 0, NULL); } - #else static void rna_def_gpencil_stroke_point(BlenderRNA *brna) @@ -918,11 +696,24 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Strength", "Color intensity (alpha factor)"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "uv_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "uv_fac"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "UV Factor", "Internal UV factor"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "uv_rotation", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "uv_rot"); + RNA_def_property_range(prop, 0.0f, M_PI * 2); + RNA_def_property_ui_text(prop, "UV Rotation", "Internal UV factor for dot mode"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT); RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set"); RNA_def_property_ui_text(prop, "Select", "Point is selected for viewport editing"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + } static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop) @@ -955,7 +746,7 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna) srna = RNA_def_struct(brna, "GPencilTriangle", NULL); RNA_def_struct_sdna(srna, "bGPDtriangle"); - RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for HQ fill"); + RNA_def_struct_ui_text(srna, "Triangle", "Triangulation data for Grease Pencil fills"); /* point v1 */ prop = RNA_def_property(srna, "v1", PROP_INT, PROP_NONE); @@ -974,6 +765,51 @@ static void rna_def_gpencil_triangle(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "verts[2]"); RNA_def_property_ui_text(prop, "v3", "Third triangle vertex index"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* texture coord for point v1 */ + prop = RNA_def_property(srna, "uv1", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "uv[0]"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "uv1", "First triangle vertex texture coordinates"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* texture coord for point v2 */ + prop = RNA_def_property(srna, "uv2", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "uv[1]"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "uv2", "Second triangle vertex texture coordinates"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + /* texture coord for point v3 */ + prop = RNA_def_property(srna, "uv3", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "uv[2]"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "uv3", "Third triangle vertex texture coordinates"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); +} + +static void rna_def_gpencil_mvert_group(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "GpencilVertexGroupElement", NULL); + RNA_def_struct_sdna(srna, "MDeformWeight"); + RNA_def_struct_ui_text(srna, "Vertex Group Element", "Weight value of a vertex in a vertex group"); + RNA_def_struct_ui_icon(srna, ICON_GROUP_VERTEX); + + /* we can't point to actual group, it is in the object and so + * there is no unique group to point to, hence the index */ + prop = RNA_def_property(srna, "group", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "def_nr"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Group Index", ""); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Weight", "Vertex Weight"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); } static void rna_def_gpencil_stroke(BlenderRNA *brna) @@ -1000,24 +836,30 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Stroke Points", "Stroke data points"); rna_def_gpencil_stroke_points_api(brna, prop); + /* vertex groups */ + prop = RNA_def_property(srna, "groups", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_funcs(prop, "rna_GpencilVertex_groups_begin", "rna_iterator_array_next", + "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL); + RNA_def_property_struct_type(prop, "GpencilVertexGroupElement"); + RNA_def_property_ui_text(prop, "Groups", "Weights for the vertex groups this vertex is member of"); + /* Triangles */ prop = RNA_def_property(srna, "triangles", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "triangles", "tot_triangles"); RNA_def_property_struct_type(prop, "GPencilTriangle"); RNA_def_property_ui_text(prop, "Triangles", "Triangulation data for HQ fill"); - /* Color */ - prop = RNA_def_property(srna, "color", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "GPencilPaletteColor"); - RNA_def_property_pointer_sdna(prop, NULL, "palcolor"); - RNA_def_property_ui_text(prop, "Palette Color", "Color from palette used in Stroke"); - RNA_def_property_update(prop, 0, "rna_GPencil_update"); + /* Material Index */ + prop = RNA_def_property(srna, "material_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "mat_nr"); + RNA_def_property_ui_text(prop, "Material Index", "Index of material used in this stroke"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Settings */ prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, stroke_draw_mode_items); - RNA_def_property_ui_text(prop, "Draw Mode", ""); + RNA_def_property_ui_text(prop, "Draw Mode", "Coordinate space that stroke is in"); RNA_def_property_update(prop, 0, "rna_GPencil_update"); prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); @@ -1026,22 +868,23 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Select", "Stroke is selected for viewport editing"); RNA_def_property_update(prop, 0, "rna_GPencil_update"); - /* Color Name */ - prop = RNA_def_property(srna, "colorname", PROP_STRING, PROP_NONE); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilStrokeColor_info_set"); - RNA_def_property_ui_text(prop, "Color Name", "Palette color name"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_stroke_colorname_update"); - /* Cyclic: Draw a line from end to start point */ prop = RNA_def_property(srna, "draw_cyclic", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_CYCLIC); RNA_def_property_ui_text(prop, "Cyclic", "Enable cyclic drawing, closing the stroke"); RNA_def_property_update(prop, 0, "rna_GPencil_update"); + /* No fill: The stroke never must fill area and must use fill color as stroke color (this is a special flag for fill brush) */ + prop = RNA_def_property(srna, "is_nofill_stroke", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_NOFILL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "No Fill", "Special stroke to use as boundary for filling areas"); + RNA_def_property_update(prop, 0, "rna_GPencil_update"); + /* Line Thickness */ prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "thickness"); - RNA_def_property_range(prop, 1, 300); + RNA_def_property_range(prop, 1, 1000); RNA_def_property_ui_range(prop, 1, 10, 1, 0); RNA_def_property_ui_text(prop, "Thickness", "Thickness of stroke (in pixels)"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); @@ -1062,7 +905,6 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_GPencil_stroke_new"); RNA_def_function_ui_description(func, "Add a new grease pencil stroke"); - parm = RNA_def_string(func, "colorname", 0, MAX_NAME, "Color", "Name of the color"); parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "", "The newly created stroke"); RNA_def_function_return(func, parm); @@ -1183,20 +1025,30 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_editable_func(prop, "rna_GPencilLayer_active_frame_editable"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - /* Draw Style */ - // TODO: replace these with a "draw type" combo (i.e. strokes only, filled strokes, strokes + fills, volumetric)? - prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_VOLUMETRIC); - RNA_def_property_ui_text(prop, "Volumetric Strokes", - "Draw strokes as a series of circular blobs, resulting in a volumetric effect"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Layer Opacity */ prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "opacity"); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + /* Stroke Drawing Color (Annotations) */ + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Color", "Color for all strokes in this layer"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + /* Line Thickness (Annotations) */ + prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "thickness"); + RNA_def_property_range(prop, 1, 10); + RNA_def_property_ui_text(prop, "Thickness", "Thickness of annotation strokes"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + /* Tint Color */ prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "tintcolor"); @@ -1212,62 +1064,21 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Tint Factor", "Factor of tinting color"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - /* Line Thickness change */ + /* Line Thickness Change */ prop = RNA_def_property(srna, "line_change", PROP_INT, PROP_PIXEL); - RNA_def_property_int_sdna(prop, NULL, "thickness"); - //RNA_def_property_range(prop, 1, 10); /* 10 px limit comes from Windows OpenGL limits for natively-drawn strokes */ - RNA_def_property_int_funcs(prop, NULL, NULL, "rna_GPencilLayer_line_width_range"); - RNA_def_property_ui_text(prop, "Thickness", "Thickness change to apply to current strokes (in pixels)"); + RNA_def_property_int_sdna(prop, NULL, "line_change"); + RNA_def_property_range(prop, -300, 300); + RNA_def_property_ui_range(prop, -100, 100, 1.0, 1); + RNA_def_property_ui_text(prop, "Thickness Change", "Thickness change to apply to current strokes (in pixels)"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Onion-Skinning */ prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ONIONSKIN); + RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_LAYER_ONIONSKIN); RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_onion_skinning_update"); - - prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "gstep"); - RNA_def_property_range(prop, -1, 120); - RNA_def_property_ui_text(prop, "Frames Before", - "Maximum number of frames to show before current frame " - "(0 = show only the previous sketch, -1 = don't show any frames before current)"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "gstep_next"); - RNA_def_property_range(prop, -1, 120); - RNA_def_property_ui_text(prop, "Frames After", - "Maximum number of frames to show after current frame " - "(0 = show only the next sketch, -1 = don't show any frames after current)"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL); - RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "gcolor_prev"); - RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "gcolor_next"); - RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_ALWAYS); - RNA_def_property_ui_text(prop, "Always Show Ghosts", - "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Flags */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE); @@ -1296,7 +1107,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - /* expose as layers.active */ + /* exposed as layers.active */ #if 0 prop = RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE); @@ -1310,7 +1121,6 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, "rna_GPencil_update"); - /* XXX keep this option? */ prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_DRAWDEBUG); RNA_def_property_ui_text(prop, "Show Points", "Draw the points which make up the strokes (for debugging purposes)"); @@ -1399,215 +1209,24 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, - "rna_GPencil_active_layer_index_get", - "rna_GPencil_active_layer_index_set", - "rna_GPencil_active_layer_index_range"); + RNA_def_property_int_funcs( + prop, + "rna_GPencil_active_layer_index_get", + "rna_GPencil_active_layer_index_set", + "rna_GPencil_active_layer_index_range"); RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); -} - -static void rna_def_gpencil_palettecolor(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - srna = RNA_def_struct(brna, "GPencilPaletteColor", NULL); - RNA_def_struct_sdna(srna, "bGPDpalettecolor"); - RNA_def_struct_ui_text(srna, "Grease Pencil Palette color", "Collection of related colors"); - RNA_def_struct_path_func(srna, "rna_GPencilPalette_color_path"); - - /* Stroke Drawing Color */ - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "color"); - RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Color", "Color for strokes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "color[3]"); - RNA_def_property_range(prop, 0.0, 1.0f); - RNA_def_property_ui_text(prop, "Opacity", "Color Opacity"); + /* Active Layer - As an enum (for selecting active layer for annotations) */ + prop = RNA_def_property(srna, "active_note", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs( + prop, + "rna_GPencil_active_layer_index_get", + "rna_GPencil_active_layer_index_set", + "rna_GPencil_active_layer_itemf"); + RNA_def_property_enum_items(prop, DummyRNA_DEFAULT_items); /* purely dynamic, as it maps to user-data */ + RNA_def_property_ui_text(prop, "Active Note", "Note/Layer to add annotation strokes to"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Name */ - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "info"); - RNA_def_property_ui_text(prop, "Name", "Color name"); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPaletteColor_info_set"); - RNA_def_struct_name_property(srna, prop); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Fill Drawing Color */ - prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "fill"); - RNA_def_property_array(prop, 3); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Fill alpha */ - prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "fill[3]"); - RNA_def_property_range(prop, 0.0, 1.0f); - RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Flags */ - prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_HIDE); - RNA_def_property_ui_icon(prop, ICON_HIDE_OFF, 1); - RNA_def_property_ui_text(prop, "Hide", "Set color Visibility"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_LOCKED); - RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1); - RNA_def_property_ui_text(prop, "Locked", "Protect color from further editing and/or frame changes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_ONIONSKIN); - RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0); - RNA_def_property_ui_text(prop, "Show in Ghosts", "Display strokes using this color when showing onion skins"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Draw Style */ - prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_VOLUMETRIC); - RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in " - "a volumetric effect"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Use High quality fill */ - prop = RNA_def_property(srna, "use_hq_fill", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_HQ_FILL); - RNA_def_property_ui_text(prop, "High Quality Fill", "Fill strokes using high quality to avoid glitches " - "(slower fps during animation play)"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Read-only state props (for simpler UI code) */ - prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_stroke_visible_get", NULL); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible"); - - prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_GPencilPaletteColor_is_fill_visible_get", NULL); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible"); -} - -/* palette colors api */ -static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cprop) -{ - StructRNA *srna; - PropertyRNA *prop; - - FunctionRNA *func; - PropertyRNA *parm; - - RNA_def_property_srna(cprop, "GPencilPaletteColors"); - srna = RNA_def_struct(brna, "GPencilPaletteColors", NULL); - RNA_def_struct_sdna(srna, "bGPDpalette"); - RNA_def_struct_ui_text(srna, "Palette colors", "Collection of palette colors"); - - func = RNA_def_function(srna, "new", "rna_GPencilPalette_color_new"); - RNA_def_function_ui_description(func, "Add a new color to the palette"); - parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The newly created color"); - RNA_def_function_return(func, parm); - - func = RNA_def_function(srna, "remove", "rna_GPencilPalette_color_remove"); - RNA_def_function_ui_description(func, "Remove a color from the palette"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color to remove"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); - RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); - - prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "GPencilPaletteColor"); - RNA_def_property_pointer_funcs(prop, "rna_GPencilPalette_active_color_get", "rna_GPencilPalette_active_color_set", NULL, NULL); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Active Palette Color", "Current active color"); - - prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, - "rna_GPencilPaletteColor_index_get", - "rna_GPencilPaletteColor_index_set", - "rna_GPencilPaletteColor_index_range"); - RNA_def_property_ui_text(prop, "Active color Index", "Index of active palette color"); -} - -static void rna_def_gpencil_palette(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "GPencilPalette", NULL); - RNA_def_struct_sdna(srna, "bGPDpalette"); - RNA_def_struct_ui_text(srna, "Grease Pencil Palette", "Collection of related palettes"); - RNA_def_struct_path_func(srna, "rna_GPencilPalette_path"); - RNA_def_struct_ui_icon(srna, ICON_COLOR); - - /* Name */ - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "info"); - RNA_def_property_ui_text(prop, "Name", "Palette name"); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilPalette_info_set"); - RNA_def_struct_name_property(srna, prop); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - /* Colors */ - prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "colors", NULL); - RNA_def_property_struct_type(prop, "GPencilPaletteColor"); - RNA_def_property_ui_text(prop, "Colors", "Colors of the palette"); - rna_def_gpencil_palettecolors_api(brna, prop); - -} - -static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop) -{ - StructRNA *srna; - PropertyRNA *prop; - - FunctionRNA *func; - PropertyRNA *parm; - - RNA_def_property_srna(cprop, "GreasePencilPalettes"); - srna = RNA_def_struct(brna, "GreasePencilPalettes", NULL); - RNA_def_struct_sdna(srna, "bGPdata"); - RNA_def_struct_ui_text(srna, "Grease Pencil Palettes", "Collection of grease pencil palettes"); - - func = RNA_def_function(srna, "new", "rna_GPencil_palette_new"); - RNA_def_function_ui_description(func, "Add a new grease pencil palette"); - parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - RNA_def_boolean(func, "set_active", true, "Set Active", "Activate the newly created palette"); - parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette"); - RNA_def_function_return(func, parm); - - func = RNA_def_function(srna, "remove", "rna_GPencil_palette_remove"); - RNA_def_function_ui_description(func, "Remove a grease pencil palette"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The palette to remove"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); - RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); - - prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "GPencilPalette"); - RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_palette_get", "rna_GPencil_active_palette_set", - NULL, NULL); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Active Palette", "Current active palette"); - - prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, - "rna_GPencilPalette_index_get", - "rna_GPencilPalette_index_set", - "rna_GPencilPalette_index_range"); - RNA_def_property_ui_text(prop, "Active Palette Index", "Index of active palette"); } static void rna_def_gpencil_data(BlenderRNA *brna) @@ -1616,6 +1235,10 @@ static void rna_def_gpencil_data(BlenderRNA *brna) PropertyRNA *prop; FunctionRNA *func; + static float default_1[4] = { 0.6f, 0.6f, 0.6f, 0.5f }; + static float onion_dft1[3] = { 0.145098f, 0.419608f, 0.137255f }; /* green */ + static float onion_dft2[3] = { 0.125490f, 0.082353f, 0.529412f }; /* blue */ + srna = RNA_def_struct(brna, "GreasePencil", "ID"); RNA_def_struct_sdna(srna, "bGPdata"); RNA_def_struct_ui_text(srna, "Grease Pencil", "Freehand annotation sketchbook"); @@ -1628,28 +1251,52 @@ static void rna_def_gpencil_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Layers", ""); rna_def_gpencil_layers_api(brna, prop); - /* Palettes */ - prop = RNA_def_property(srna, "palettes", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "palettes", NULL); - RNA_def_property_struct_type(prop, "GPencilPalette"); - RNA_def_property_ui_text(prop, "Palettes", ""); - rna_def_gpencil_palettes_api(brna, prop); - /* Animation Data */ rna_def_animdata_common(srna); + /* materials */ + prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol"); + RNA_def_property_struct_type(prop, "Material"); + RNA_def_property_ui_text(prop, "Materials", ""); + RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */ + RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int"); + + /* xray modes */ + prop = RNA_def_property(srna, "xray_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "xray_mode"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_xraymodes_items); + RNA_def_property_ui_text(prop, "Xray", ""); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* Flags */ prop = RNA_def_property(srna, "use_stroke_edit_mode", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_EDITMODE); RNA_def_property_ui_text(prop, "Stroke Edit Mode", "Edit Grease Pencil strokes instead of viewport data"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update"); + prop = RNA_def_property(srna, "is_stroke_paint_mode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_PAINTMODE); + RNA_def_property_ui_text(prop, "Stroke Paint Mode", "Draw Grease Pencil strokes on click/drag"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update"); + + prop = RNA_def_property(srna, "is_stroke_sculpt_mode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_SCULPTMODE); + RNA_def_property_ui_text(prop, "Stroke Sculpt Mode", "Sculpt Grease Pencil strokes instead of viewport data"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update"); + + prop = RNA_def_property(srna, "is_stroke_weight_mode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_WEIGHTMODE); + RNA_def_property_ui_text(prop, "Stroke Weight Paint Mode", "Grease Pencil weight paint"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, "rna_GPencil_editmode_update"); + prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_ONIONSKINS); - RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_use_onion_skinning_set"); - RNA_def_property_ui_text(prop, "Onion Skins", - "Show ghosts of the frames before and after the current frame, toggle to enable on active layer or disable all"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + RNA_def_property_ui_text(prop, "Onion Skins", "Show ghosts of the frames before and after the current frame"); + RNA_def_property_update(prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update"); prop = RNA_def_property(srna, "show_stroke_direction", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_SHOW_DIRECTION); @@ -1657,6 +1304,102 @@ static void rna_def_gpencil_data(BlenderRNA *brna) "and smaller red dot (end) points"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "show_constant_thickness", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_KEEPTHICKNESS); + RNA_def_property_ui_text(prop, "Keep thickness", "Show stroke with same thickness when viewport zoom change"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "pixfactor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "pixfactor"); + RNA_def_property_range(prop, 0.1f, 30.0f); + RNA_def_property_ui_range(prop, 0.1f, 30.0f, 1, 2); + RNA_def_property_ui_text(prop, "Scale", "Scale conversion factor for pixel size (use larger values for thicker lines)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_multiedit", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_MULTIEDIT); + RNA_def_property_ui_text(prop, "MultiFrame", "Edit strokes from multiple grease pencil keyframes at the same time (keyframes must be selected to be included)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "edit_line_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "line_color"); + RNA_def_property_array(prop, 4); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_array_default(prop, default_1); + RNA_def_property_ui_text(prop, "Edit Line Color", "Color for editing line"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + /* onion skinning */ + prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "gstep"); + RNA_def_property_range(prop, 0, 120); + RNA_def_property_int_default(prop, 1); + RNA_def_property_ui_text(prop, "Frames Before", + "Maximum number of frames to show before current frame " + "(0 = don't show any frames before current)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "gstep_next"); + RNA_def_property_range(prop, 0, 120); + RNA_def_property_int_default(prop, 1); + RNA_def_property_ui_text(prop, "Frames After", + "Maximum number of frames to show after current frame " + "(0 = don't show any frames after current)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_GHOST_PREVCOL | GP_ONION_GHOST_NEXTCOL); + RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "gcolor_prev"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_array_default(prop, onion_dft1); + RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame"); + RNA_def_property_update(prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "gcolor_next"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_array_default(prop, onion_dft2); + RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame"); + RNA_def_property_update(prop, NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_GHOST_ALWAYS); + RNA_def_property_ui_text(prop, "Always Show Ghosts", + "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "onion_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "onion_mode"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_onion_modes_items); + RNA_def_property_ui_text(prop, "Mode", "Mode to display frames"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_onion_fade", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_FADE); + RNA_def_property_ui_text(prop, "Fade", + "Display onion keyframes with a fade in color transparency"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_onion_loop", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_ONION_LOOP); + RNA_def_property_ui_text(prop, "Loop", + "Display first onion keyframes using next frame color to show indication of loop start frame"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "onion_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "onion_factor"); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_range(prop, 0.0, 1.0f); + RNA_def_property_ui_text(prop, "Onion Opacity", "Change fade opacity of displayed onion frames"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* API Functions */ func = RNA_def_function(srna, "clear", "rna_GPencil_clear"); RNA_def_function_ui_description(func, "Remove all the grease pencil data"); @@ -1670,12 +1413,12 @@ void RNA_def_gpencil(BlenderRNA *brna) rna_def_gpencil_layer(brna); rna_def_gpencil_frame(brna); - rna_def_gpencil_triangle(brna); + rna_def_gpencil_stroke(brna); rna_def_gpencil_stroke_point(brna); + rna_def_gpencil_triangle(brna); - rna_def_gpencil_palette(brna); - rna_def_gpencil_palettecolor(brna); + rna_def_gpencil_mvert_group(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c new file mode 100644 index 00000000000..df64121b2b4 --- /dev/null +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -0,0 +1,1314 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/makesrna/intern/rna_gpencil_modifier.c + * \ingroup RNA + */ + + +#include +#include +#include + +#include "DNA_armature_types.h" +#include "DNA_cachefile_types.h" +#include "DNA_mesh_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_object_force_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "BLT_translation.h" + +#include "BKE_animsys.h" +#include "BKE_data_transfer.h" +#include "BKE_DerivedMesh.h" +#include "BKE_dynamicpaint.h" +#include "BKE_effect.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_remap.h" +#include "BKE_multires.h" +#include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */ +#include "BKE_gpencil_modifier.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "rna_internal.h" + +#include "WM_api.h" +#include "WM_types.h" + +const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { + {0, "", 0, N_("Generate"), "" }, + {eGpencilModifierType_Instance, "GP_INSTANCE", ICON_MOD_ARRAY, "Instance", "Create grid of duplicate instances"}, + {eGpencilModifierType_Build, "GP_BUILD", ICON_MOD_BUILD, "Build", "Create duplication of strokes"}, + {eGpencilModifierType_Simplify, "GP_SIMPLIFY", ICON_MOD_DECIM, "Simplify", "Simplify stroke reducing number of points"}, + {eGpencilModifierType_Subdiv, "GP_SUBDIV", ICON_MOD_SUBSURF, "Subdivide", "Subdivide stroke adding more control points"}, + {0, "", 0, N_("Deform"), "" }, + {eGpencilModifierType_Hook, "GP_HOOK", ICON_HOOK, "Hook", "Deform stroke points using objects"}, + {eGpencilModifierType_Lattice, "GP_LATTICE", ICON_MOD_LATTICE, "Lattice", "Deform strokes using lattice"}, + {eGpencilModifierType_Mirror, "GP_MIRROR", ICON_MOD_MIRROR, "Mirror", "Duplicate strokes like a mirror"}, + {eGpencilModifierType_Noise, "GP_NOISE", ICON_RNDCURVE, "Noise", "Add noise to strokes"}, + {eGpencilModifierType_Offset, "GP_OFFSET", ICON_MOD_DISPLACE, "Offset", "Change stroke location, rotation or scale"}, + {eGpencilModifierType_Smooth, "GP_SMOOTH", ICON_MOD_SMOOTH, "Smooth", "Smooth stroke"}, + {eGpencilModifierType_Thick, "GP_THICK", ICON_MAN_ROT, "Thickness", "Change stroke thickness"}, + {0, "", 0, N_("Color"), "" }, + {eGpencilModifierType_Color, "GP_COLOR", ICON_GROUP_VCOL, "Hue/Saturation", "Apply changes to stroke colors"}, + {eGpencilModifierType_Opacity, "GP_OPACITY", ICON_MOD_MASK, "Opacity", "Opacity of the strokes"}, + {eGpencilModifierType_Tint, "GP_TINT", ICON_COLOR, "Tint", "Tint strokes with new color"}, + {0, NULL, 0, NULL, NULL} +}; + +#ifndef RNA_RUNTIME +static const EnumPropertyItem modifier_gphook_falloff_items[] = { + { eGPHook_Falloff_None, "NONE", 0, "No Falloff", "" }, + { eGPHook_Falloff_Curve, "CURVE", 0, "Curve", "" }, + { eGPHook_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", "" }, + { eGPHook_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", "" }, + { eGPHook_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", "" }, + { eGPHook_Falloff_InvSquare, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", "" }, + { eGPHook_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", "" }, + { eGPHook_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", "" }, + { eGPHook_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", "" }, + { 0, NULL, 0, NULL, NULL } +}; + +static const EnumPropertyItem rna_enum_gpencil_lockshift_items[] = { + { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Use X axis" }, + { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Use Y axis" }, + { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Use Z axis" }, + { 0, NULL, 0, NULL, NULL } +}; + +#endif + +#ifdef RNA_RUNTIME + +#include "DNA_particle_types.h" +#include "DNA_curve_types.h" +#include "DNA_smoke_types.h" + +#include "BKE_cachefile.h" +#include "BKE_context.h" +#include "BKE_library.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_object.h" +#include "BKE_gpencil.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr) +{ + GpencilModifierData *md = (GpencilModifierData *)ptr->data; + + switch ((GpencilModifierType)md->type) { + case eGpencilModifierType_Noise: + return &RNA_NoiseGpencilModifier; + case eGpencilModifierType_Subdiv: + return &RNA_SubdivGpencilModifier; + case eGpencilModifierType_Simplify: + return &RNA_SimplifyGpencilModifier; + case eGpencilModifierType_Thick: + return &RNA_ThickGpencilModifier; + case eGpencilModifierType_Tint: + return &RNA_TintGpencilModifier; + case eGpencilModifierType_Color: + return &RNA_ColorGpencilModifier; + case eGpencilModifierType_Instance: + return &RNA_InstanceGpencilModifier; + case eGpencilModifierType_Build: + return &RNA_BuildGpencilModifier; + case eGpencilModifierType_Opacity: + return &RNA_OpacityGpencilModifier; + case eGpencilModifierType_Lattice: + return &RNA_LatticeGpencilModifier; + case eGpencilModifierType_Mirror: + return &RNA_MirrorGpencilModifier; + case eGpencilModifierType_Smooth: + return &RNA_SmoothGpencilModifier; + case eGpencilModifierType_Hook: + return &RNA_HookGpencilModifier; + case eGpencilModifierType_Offset: + return &RNA_OffsetGpencilModifier; + /* Default */ + case eGpencilModifierType_None: + case NUM_GREASEPENCIL_MODIFIER_TYPES: + return &RNA_GpencilModifier; + } + + return &RNA_GpencilModifier; +} + +static void rna_GpencilModifier_name_set(PointerRNA *ptr, const char *value) +{ + GpencilModifierData *gmd = ptr->data; + char oldname[sizeof(gmd->name)]; + + /* make a copy of the old name first */ + BLI_strncpy(oldname, gmd->name, sizeof(gmd->name)); + + /* copy the new name into the name slot */ + BLI_strncpy_utf8(gmd->name, value, sizeof(gmd->name)); + + /* make sure the name is truly unique */ + if (ptr->id.data) { + Object *ob = ptr->id.data; + BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, gmd); + } + + /* fix all the animation data which may link to this */ + BKE_animdata_fix_paths_rename_all(NULL, "grease_pencil_modifiers", oldname, gmd->name); +} + +static char *rna_GpencilModifier_path(PointerRNA *ptr) +{ + GpencilModifierData *gmd = ptr->data; + char name_esc[sizeof(gmd->name) * 2]; + + BLI_strescape(name_esc, gmd->name, sizeof(name_esc)); + return BLI_sprintfN("grease_pencil_modifiers[\"%s\"]", name_esc); +} + +static void rna_GpencilModifier_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA); + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ptr->id.data); +} + +static void rna_GpencilModifier_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + rna_GpencilModifier_update(bmain, scene, ptr); + DEG_relations_tag_update(bmain); +} + +/* Vertex Groups */ + +#define RNA_GP_MOD_VGROUP_NAME_SET(_type, _prop) \ +static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, const char *value) \ +{ \ + _type##GpencilModifierData *tmd = (_type##GpencilModifierData *)ptr->data; \ + rna_object_vgroup_name_set(ptr, value, tmd->_prop, sizeof(tmd->_prop)); \ +} + +RNA_GP_MOD_VGROUP_NAME_SET(Noise, vgname); +RNA_GP_MOD_VGROUP_NAME_SET(Thick, vgname); +RNA_GP_MOD_VGROUP_NAME_SET(Opacity, vgname); +RNA_GP_MOD_VGROUP_NAME_SET(Lattice, vgname); +RNA_GP_MOD_VGROUP_NAME_SET(Smooth, vgname); +RNA_GP_MOD_VGROUP_NAME_SET(Hook, vgname); +RNA_GP_MOD_VGROUP_NAME_SET(Offset, vgname); + +#undef RNA_GP_MOD_VGROUP_NAME_SET + +/* Objects */ + +static void greasepencil_modifier_object_set(Object *self, Object **ob_p, int type, PointerRNA value) +{ + Object *ob = value.data; + + if (!self || ob != self) { + if (!ob || type == OB_EMPTY || ob->type == type) { + id_lib_extern((ID *)ob); + *ob_p = ob; + } + } +} + +#define RNA_GP_MOD_OBJECT_SET(_type, _prop, _obtype) \ +static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, PointerRNA value) \ +{ \ + _type##GpencilModifierData *tmd = (_type##GpencilModifierData *)ptr->data; \ + greasepencil_modifier_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \ +} + +RNA_GP_MOD_OBJECT_SET(Lattice, object, OB_LATTICE); +RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY); + +#undef RNA_GP_MOD_OBJECT_SET + +static void rna_HookGpencilModifier_object_set(PointerRNA *ptr, PointerRNA value) +{ + HookGpencilModifierData *hmd = ptr->data; + Object *ob = (Object *)value.data; + + hmd->object = ob; + id_lib_extern((ID *)ob); + BKE_object_modifier_gpencil_hook_reset(ob, hmd); +} + +#else + +static void rna_def_modifier_gpencilnoise(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "NoiseGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Noise Modifier", "Noise effect modifier"); + RNA_def_struct_sdna(srna, "NoiseGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_RNDCURVE); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NoiseGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "factor"); + RNA_def_property_range(prop, 0, 30.0); + RNA_def_property_ui_text(prop, "Factor", "Amount of noise to apply"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "random", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_USE_RANDOM); + RNA_def_property_ui_text(prop, "Random", "Use random values"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_LOCATION); + RNA_def_property_ui_text(prop, "Affect Position", "The modifier affects the position of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_STRENGTH); + RNA_def_property_ui_text(prop, "Affect Strength", "The modifier affects the color strength of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_THICKNESS); + RNA_def_property_ui_text(prop, "Affect Thickness", "The modifier affects the thickness of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_uv", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOD_UV); + RNA_def_property_ui_text(prop, "Affect UV", "The modifier affects the UV rotation factor of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "full_stroke", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_FULL_STROKE); + RNA_def_property_ui_text(prop, "Full Stroke", "The noise moves the stroke as a whole, not point by point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "move_extreme", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_MOVE_EXTREME); + RNA_def_property_ui_text(prop, "Move Extremes", "The noise moves the stroke extreme points"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "step"); + RNA_def_property_range(prop, 1, 100); + RNA_def_property_ui_text(prop, "Step", "Number of frames before recalculate random values again"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilsmooth(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "SmoothGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Smooth Modifier", "Smooth effect modifier"); + RNA_def_struct_sdna(srna, "SmoothGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_SMOOTH); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_SmoothGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "factor"); + RNA_def_property_range(prop, 0, 2); + RNA_def_property_ui_text(prop, "Factor", "Amount of smooth to apply"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_LOCATION); + RNA_def_property_ui_text(prop, "Affect Position", "The modifier affects the position of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_STRENGTH); + RNA_def_property_ui_text(prop, "Affect Strength", "The modifier affects the color strength of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_THICKNESS); + RNA_def_property_ui_text(prop, "Affect Thickness", "The modifier affects the thickness of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "affect_uv", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_MOD_UV); + RNA_def_property_ui_text(prop, "Affect UV", "The modifier affects the UV rotation factor of the point"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "step"); + RNA_def_property_range(prop, 1, 10); + RNA_def_property_ui_text(prop, "Step", "Number of times to apply smooth (high numbers can reduce fps)"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SMOOTH_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilsubdiv(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "SubdivGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Subdivision Modifier", "Subdivide Stroke modifier"); + RNA_def_struct_sdna(srna, "SubdivGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_SUBSURF); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "level", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "level"); + RNA_def_property_range(prop, 0, 5); + RNA_def_property_ui_text(prop, "Level", "Number of subdivisions"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "simple", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_SIMPLE); + RNA_def_property_ui_text(prop, "Simple", "The modifier only add control points"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SUBDIV_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem prop_gpencil_simplify_mode_items[] = { + { GP_SIMPLIFY_FIXED, "FIXED", ICON_IPO_CONSTANT, "Fixed", + "Delete alternative vertices in the stroke, except extrems" }, + { GP_SIMPLIFY_ADAPTATIVE, "ADAPTATIVE", ICON_IPO_EASE_IN_OUT, "Adaptative", + "Use a RDP algorithm to simplify" }, + { 0, NULL, 0, NULL, NULL } + }; + + srna = RNA_def_struct(brna, "SimplifyGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Simplify Modifier", "Simplify Stroke modifier"); + RNA_def_struct_sdna(srna, "SimplifyGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_DECIM); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "factor"); + RNA_def_property_range(prop, 0, 100.0); + RNA_def_property_ui_range(prop, 0, 100.0, 1.0f, 3); + RNA_def_property_ui_text(prop, "Factor", "Factor of Simplify"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SIMPLIFY_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SIMPLIFY_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Mode */ + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_gpencil_simplify_mode_items); + RNA_def_property_ui_text(prop, "Mode", "How simplify the stroke"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "step", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "step"); + RNA_def_property_range(prop, 1, 50); + RNA_def_property_ui_text(prop, "Iterations", "Number of times to apply simplify"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilthick(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ThickGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Thick Modifier", "Subdivide and Smooth Stroke modifier"); + RNA_def_struct_sdna(srna, "ThickGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MAN_ROT); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ThickGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "thickness"); + RNA_def_property_range(prop, -100, 500); + RNA_def_property_ui_text(prop, "Thickness", "Factor of thickness change"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_CUSTOM_CURVE); + RNA_def_property_ui_text(prop, "Custom Curve", "Use a custom curve to define thickness changes"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "normalize_thickness", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_THICK_NORMALIZE); + RNA_def_property_ui_text(prop, "Normalize", "Normalize the full stroke to modifier thickness"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "curve_thickness"); + RNA_def_property_ui_text(prop, "Curve", "Custom Thickness Curve"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpenciloffset(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "OffsetGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Offset Modifier", "Offset Stroke modifier"); + RNA_def_struct_sdna(srna, "OffsetGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_DISPLACE); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_OffsetGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OFFSET_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "loc"); + RNA_def_property_ui_text(prop, "Location", "Values for change location"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER); + RNA_def_property_float_sdna(prop, NULL, "rot"); + RNA_def_property_ui_text(prop, "Rotation", "Values for chages in rotation"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); + RNA_def_property_float_sdna(prop, NULL, "scale"); + RNA_def_property_ui_text(prop, "Scale", "Values for changes in scale"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpenciltint(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "TintGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Tint Modifier", "Tint Stroke Color modifier"); + RNA_def_struct_sdna(srna, "TintGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_COLOR); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rgb"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Color", "Color used for tinting"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "factor"); + RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 3); + RNA_def_property_ui_text(prop, "Factor", "Factor for mixing color"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "create_colors", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_CREATE_COLORS); + RNA_def_property_ui_text(prop, "Create Colors", "When apply modifier, create new color in the palette"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilcolor(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ColorGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Hue/Saturation Modifier", "Change Hue/Saturation modifier"); + RNA_def_struct_sdna(srna, "ColorGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_GROUP_VCOL); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "hue", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 2.0); + RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3); + RNA_def_property_float_sdna(prop, NULL, "hsv[0]"); + RNA_def_property_ui_text(prop, "Hue", "Color Hue"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 2.0); + RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3); + RNA_def_property_float_sdna(prop, NULL, "hsv[1]"); + RNA_def_property_ui_text(prop, "Saturation", "Color Saturation"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, 0.0, 2.0); + RNA_def_property_ui_range(prop, 0.0, 2.0, 0.1, 3); + RNA_def_property_float_sdna(prop, NULL, "hsv[2]"); + RNA_def_property_ui_text(prop, "Value", "Color Value"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "create_colors", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_CREATE_COLORS); + RNA_def_property_ui_text(prop, "Create Colors", "When apply modifier, create new color in the palette"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilopacity(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "OpacityGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Opacity Modifier", "Opacity of Strokes modifier"); + RNA_def_struct_sdna(srna, "OpacityGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_MASK); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_OpacityGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "factor"); + RNA_def_property_ui_range(prop, 0, 2.0, 0.1, 3); + RNA_def_property_ui_text(prop, "Factor", "Factor of Opacity"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilinstance(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "InstanceGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Instance Modifier", "Create grid of duplicate instances"); + RNA_def_struct_sdna(srna, "InstanceGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_ARRAY); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "count", PROP_INT, PROP_XYZ); + RNA_def_property_range(prop, 1, INT_MAX); + RNA_def_property_ui_range(prop, 1, 1000, 1, -1); + RNA_def_property_ui_text(prop, "Count", "Number of items"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Offset parameters */ + prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "offset"); + RNA_def_property_ui_text(prop, "Offset", "Value for the distance between items"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "shift", PROP_FLOAT, PROP_TRANSLATION); + RNA_def_property_float_sdna(prop, NULL, "shift"); + RNA_def_property_ui_text(prop, "Shift", "Shiftness value"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "lock_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "lock_axis"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_lockshift_items); + //RNA_def_property_flag(prop, PROP_ENUM_FLAG); + RNA_def_property_ui_text(prop, "Axis", ""); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER); + RNA_def_property_float_sdna(prop, NULL, "rot"); + RNA_def_property_ui_text(prop, "Rotation", "Value for chages in rotation"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); + RNA_def_property_float_sdna(prop, NULL, "scale"); + RNA_def_property_ui_text(prop, "Scale", "Value for changes in scale"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "random_rot", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_INSTANCE_RANDOM_ROT); + RNA_def_property_ui_text(prop, "Random Rotation", "Use random factors for rotation"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "rot_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "rnd_rot"); + RNA_def_property_ui_text(prop, "Rotation Factor", "Random factor for rotation"); + RNA_def_property_range(prop, -10.0, 10.0); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "random_scale", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_INSTANCE_RANDOM_SIZE); + RNA_def_property_ui_text(prop, "Random Scale", "Use random factors for scale"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "scale_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "rnd_size"); + RNA_def_property_ui_text(prop, "Scale Factor", "Random factor for scale"); + RNA_def_property_range(prop, -10.0, 10.0); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_INSTANCE_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_INSTANCE_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_make_objects", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_INSTANCE_MAKE_OBJECTS); + RNA_def_property_ui_text(prop, "Make Objects", + "When applying this modifier, instances get created as separate objects"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilbuild(BlenderRNA *brna) +{ + static EnumPropertyItem prop_gpencil_build_mode_items[] = { + {GP_BUILD_MODE_SEQUENTIAL, "SEQUENTIAL", ICON_PARTICLE_POINT, "Sequential", + "Strokes appear/disappear one after the other, but only a single one changes at a time"}, + {GP_BUILD_MODE_CONCURRENT, "CONCURRENT", ICON_PARTICLE_TIP, "Concurrent", + "Multiple strokes appear/disappear at once"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem prop_gpencil_build_transition_items[] = { + {GP_BUILD_TRANSITION_GROW, "GROW", 0, "Grow", + "Show points in the order they occur in each stroke " + "(e.g. for animating lines being drawn)"}, + {GP_BUILD_TRANSITION_SHRINK, "SHRINK", 0, "Shrink", + "Hide points from the end of each stroke to the start " + "(e.g. for animating lines being erased)"}, + {GP_BUILD_TRANSITION_FADE, "FADE", 0, "Fade", + "Hide points in the order they occur in each stroke " + "(e.g. for animating ink fading or vanishing after getting drawn)"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem prop_gpencil_build_time_align_items[] = { + {GP_BUILD_TIMEALIGN_START, "START", 0, "Align Start", + "All strokes start at same time (i.e. short strokes finish earlier)"}, + {GP_BUILD_TIMEALIGN_END, "END", 0, "Align End", + "All strokes end at same time (i.e. short strokes start later)"}, + {0, NULL, 0, NULL, NULL} + }; + + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "BuildGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Build Modifier", "Animate strokes appearing and disappearing"); + RNA_def_struct_sdna(srna, "BuildGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD); + + /* Mode */ + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_gpencil_build_mode_items); + RNA_def_property_ui_text(prop, "Mode", "How many strokes are being animated at a time"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Direction */ + prop = RNA_def_property(srna, "transition", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_gpencil_build_transition_items); + RNA_def_property_ui_text(prop, "Transition", "How are strokes animated (i.e. are they appearing or disappearing)"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + + /* Transition Onset Delay + Length */ + prop = RNA_def_property(srna, "start_delay", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "start_delay"); + RNA_def_property_ui_text(prop, "Start Delay", "Number of frames after each GP keyframe before the modifier has any effect"); + RNA_def_property_range(prop, 0, MAXFRAMEF); + RNA_def_property_ui_range(prop, 0, 200, 1, -1); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "length"); + RNA_def_property_ui_text(prop, "Length", + "Maximum number of frames that the build effect can run for " + "(unless another GP keyframe occurs before this time has elapsed)"); + RNA_def_property_range(prop, 1, MAXFRAMEF); + RNA_def_property_ui_range(prop, 1, 1000, 1, -1); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + + /* Concurrent Mode Settings */ + prop = RNA_def_property(srna, "concurrent_time_alignment", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "time_alignment"); + RNA_def_property_enum_items(prop, prop_gpencil_build_time_align_items); + RNA_def_property_ui_text(prop, "Time Alignment", "When should strokes start to appear/disappear"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + + + /* Time Limits */ + prop = RNA_def_property(srna, "use_restrict_frame_range", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_RESTRICT_TIME); + RNA_def_property_ui_text(prop, "Restrict Frame Range", "Only modify strokes during the specified frame range"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "start_frame"); + RNA_def_property_ui_text(prop, "Start Frame", "Start Frame (when Restrict Frame Range is enabled)"); + RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "end_frame"); + RNA_def_property_ui_text(prop, "End Frame", "End Frame (when Restrict Frame Range is enabled)"); + RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + + /* Filters - Layer */ + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + /* Filters - Pass Index */ +#if 0 + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BUILD_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +#endif +} + +static void rna_def_modifier_gpencillattice(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "LatticeGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Lattice Modifier", "Change stroke using lattice to deform modifier"); + RNA_def_struct_sdna(srna, "LatticeGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_LATTICE); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_LatticeGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LATTICE_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "Object", "Lattice object to deform with"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_LatticeGpencilModifier_object_set", NULL, "rna_Lattice_object_poll"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 1, 10, 2); + RNA_def_property_ui_text(prop, "Strength", "Strength of modifier effect"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilmirror(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "MirrorGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Mirror Modifier", "Change stroke using lattice to deform modifier"); + RNA_def_struct_sdna(srna, "MirrorGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_MIRROR); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "Object", "Object used as center"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_MirrorGpencilModifier_object_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "clip", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_CLIPPING); + RNA_def_property_ui_text(prop, "Clip", "Clip points"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "x_axis", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_X); + RNA_def_property_ui_text(prop, "X", "Mirror this axis"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "y_axis", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_Y); + RNA_def_property_ui_text(prop, "Y", "Mirror this axis"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "z_axis", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MIRROR_AXIS_Z); + RNA_def_property_ui_text(prop, "Z", "Mirror this axis"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} + +static void rna_def_modifier_gpencilhook(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "HookGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Hook Modifier", "Hook modifier to modify the location of stroke points"); + RNA_def_struct_sdna(srna, "HookGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_HOOK); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_pointer_funcs(prop, NULL, "rna_HookGpencilModifier_object_set", NULL, NULL); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "subtarget", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "subtarget"); + RNA_def_property_ui_text(prop, "Sub-Target", + "Name of Parent Bone for hook (if applicable), also recalculates and clears offset"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "layername"); + RNA_def_property_ui_text(prop, "Layer", "Layer name"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for modulating the deform"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_HookGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "pass_index"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Pass", "Pass index"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_LAYER); + RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_pass", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_PASS); + RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "invert_vertex", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Inverse VertexGroup", "Inverse filter"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "force"); + RNA_def_property_range(prop, 0, 1); + RNA_def_property_ui_text(prop, "Strength", "Relative force of the hook"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, modifier_gphook_falloff_items); /* share the enum */ + RNA_def_property_ui_text(prop, "Falloff Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "falloff_radius", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "falloff"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 100, 100, 2); + RNA_def_property_ui_text(prop, "Radius", "If not zero, the distance from the hook where influence ends"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "curfalloff"); + RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "cent"); + RNA_def_property_ui_text(prop, "Hook Center", ""); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "parentinv"); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target"); + RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_falloff_uniform", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_HOOK_UNIFORM_SPACE); + RNA_def_property_ui_text(prop, "Uniform Falloff", "Compensate for non-uniform object scale"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); +} +void RNA_def_greasepencil_modifier(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* data */ + srna = RNA_def_struct(brna, "GpencilModifier", NULL); + RNA_def_struct_ui_text(srna, "GpencilModifier", "Modifier affecting the grease pencil object"); + RNA_def_struct_refine_func(srna, "rna_GpencilModifier_refine"); + RNA_def_struct_path_func(srna, "rna_GpencilModifier_path"); + RNA_def_struct_sdna(srna, "GpencilModifierData"); + + /* strings */ + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GpencilModifier_name_set"); + RNA_def_property_ui_text(prop, "Name", "Modifier name"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER | NA_RENAME, NULL); + RNA_def_struct_name_property(srna, prop); + + /* enums */ + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, rna_enum_object_greasepencil_modifier_type_items); + RNA_def_property_ui_text(prop, "Type", ""); + + /* flags */ + prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Realtime); + RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport"); + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0); + + prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Render); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_ui_text(prop, "Render", "Use modifier during render"); + RNA_def_property_ui_icon(prop, ICON_SCENE, 0); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Editmode); + RNA_def_property_ui_text(prop, "Edit Mode", "Display modifier in Edit mode"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0); + + prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eGpencilModifierMode_Expanded); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_ui_text(prop, "Expanded", "Set modifier expanded in the user interface"); + RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); + + /* types */ + rna_def_modifier_gpencilnoise(brna); + rna_def_modifier_gpencilsmooth(brna); + rna_def_modifier_gpencilsubdiv(brna); + rna_def_modifier_gpencilsimplify(brna); + rna_def_modifier_gpencilthick(brna); + rna_def_modifier_gpenciloffset(brna); + rna_def_modifier_gpenciltint(brna); + rna_def_modifier_gpencilcolor(brna); + rna_def_modifier_gpencilinstance(brna); + rna_def_modifier_gpencilbuild(brna); + rna_def_modifier_gpencilopacity(brna); + rna_def_modifier_gpencillattice(brna); + rna_def_modifier_gpencilmirror(brna); + rna_def_modifier_gpencilhook(brna); +} + +#endif diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 83d173de6c8..a88623e5b5b 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -153,6 +153,8 @@ void RNA_def_dynamic_paint(struct BlenderRNA *brna); void RNA_def_fluidsim(struct BlenderRNA *brna); void RNA_def_fcurve(struct BlenderRNA *brna); void RNA_def_gpencil(struct BlenderRNA *brna); +void RNA_def_greasepencil_modifier(struct BlenderRNA *brna); +void RNA_def_shader_fx(struct BlenderRNA *brna); void RNA_def_image(struct BlenderRNA *brna); void RNA_def_key(struct BlenderRNA *brna); void RNA_def_light(struct BlenderRNA *brna); @@ -283,6 +285,7 @@ void rna_TextureSlot_update(struct bContext *C, struct PointerRNA *ptr); bool rna_Armature_object_poll(struct PointerRNA *ptr, struct PointerRNA value); bool rna_Camera_object_poll(struct PointerRNA *ptr, struct PointerRNA value); bool rna_Curve_object_poll(struct PointerRNA *ptr, struct PointerRNA value); +bool rna_GPencil_object_poll(struct PointerRNA *ptr, struct PointerRNA value); bool rna_Light_object_poll(struct PointerRNA *ptr, struct PointerRNA value); bool rna_Lattice_object_poll(struct PointerRNA *ptr, struct PointerRNA value); bool rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value); @@ -291,6 +294,10 @@ bool rna_Mesh_object_poll(struct PointerRNA *ptr, struct PointerRNA value); bool rna_Action_id_poll(struct PointerRNA *ptr, struct PointerRNA value); bool rna_Action_actedit_assign_poll(struct PointerRNA *ptr, struct PointerRNA value); +/* Grease Pencil datablock polling functions - for filtering GP Object vs Annotation datablocks */ +bool rna_GPencil_datablocks_annotations_poll(struct PointerRNA *ptr, const struct PointerRNA value); +bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct PointerRNA value); + char *rna_TextureSlot_path(struct PointerRNA *ptr); char *rna_Node_ImageUser_path(struct PointerRNA *ptr); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index febe74f63c9..50aa3cb5b81 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -231,6 +231,9 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char case ID_LT: type = OB_LATTICE; break; + case ID_GD: + type = OB_GPENCIL; + break; case ID_AR: type = OB_ARMATURE; break; @@ -266,6 +269,11 @@ static Material *rna_Main_materials_new(Main *bmain, const char *name) return (Material *)id; } +static void rna_Main_materials_gpencil_data(Main *UNUSED(bmain), struct PointerRNA *ma) +{ + BKE_material_init_gpencil_settings((Material *)ma); +} + static const EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { return rna_node_tree_type_itemf(NULL, NULL, r_free); @@ -783,6 +791,11 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "create_gpencil_data", "rna_Main_materials_gpencil_data"); + RNA_def_function_ui_description(func, "Add grease pencil material settings"); + parm = RNA_def_pointer(func, "material", "Material", "", "Material"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the current blendfile"); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 0a8ea99b8fb..56f5a12516b 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -72,6 +72,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { #include "BKE_colorband.h" #include "BKE_context.h" #include "BKE_main.h" +#include "BKE_gpencil.h" #include "BKE_material.h" #include "BKE_texture.h" #include "BKE_node.h" @@ -85,6 +86,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { #include "ED_node.h" #include "ED_image.h" #include "ED_screen.h" +#include "ED_gpencil.h" static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -104,6 +106,30 @@ static void rna_Material_update_previews(Main *UNUSED(bmain), Scene *UNUSED(scen WM_main_add_notifier(NC_MATERIAL | ND_SHADING_PREVIEW, ma); } +static void rna_MaterialGpencil_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Material *ma = ptr->id.data; + PreviewImage *preview = ma->preview; + + rna_Material_update(bmain, scene, ptr); + + /* update previews (icon and thumbnail) */ + preview->flag[ICON_SIZE_ICON] |= PRV_CHANGED; + preview->flag[ICON_SIZE_PREVIEW] |= PRV_CHANGED; + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_PREVIEW, ma); + + WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma); +} + +static void rna_MaterialGpencil_nopreview_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Material *ma = ptr->id.data; + + rna_Material_update(bmain, scene, ptr); + + WM_main_add_notifier(NC_GPENCIL | ND_DATA, ma); +} + static void rna_Material_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Material *ma = ptr->id.data; @@ -243,6 +269,59 @@ void rna_mtex_texture_slots_clear(ID *self_id, struct bContext *C, ReportList *r WM_event_add_notifier(C, NC_TEXTURE, CTX_data_scene(C)); } +static bool rna_is_grease_pencil_get(PointerRNA *ptr) +{ + Material *ma = (Material *)ptr->data; + if (ma->gp_style != NULL) + return true; + + return false; +} + +static void rna_gpcolordata_uv_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + /* update all uv strokes of this color */ + Material *ma = ptr->id.data; + ED_gpencil_update_color_uv(bmain, ma); + + rna_MaterialGpencil_update(bmain, scene, ptr); +} + +static char *rna_GpencilColorData_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_sprintfN("grease_pencil"); +} + +static int rna_GpencilColorData_is_stroke_visible_get(PointerRNA *ptr) +{ + MaterialGPencilStyle *pcolor = ptr->data; + return (pcolor->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH); +} + +static int rna_GpencilColorData_is_fill_visible_get(PointerRNA *ptr) +{ + MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data; + return ((pcolor->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (pcolor->fill_style > 0)); +} + +static void rna_GpencilColorData_stroke_image_set(PointerRNA *ptr, PointerRNA value) +{ + MaterialGPencilStyle *pcolor = ptr->data; + ID *id = value.data; + + id_us_plus(id); + pcolor->sima = (struct Image *)id; +} + +static void rna_GpencilColorData_fill_image_set(PointerRNA *ptr, PointerRNA value) +{ + MaterialGPencilStyle *pcolor = (MaterialGPencilStyle *)ptr->data; + ID *id = value.data; + + id_us_plus(id); + pcolor->ima = (struct Image *)id; +} + #else static void rna_def_material_display(StructRNA *srna) @@ -296,6 +375,251 @@ static void rna_def_material_display(StructRNA *srna) RNA_def_property_update(prop, 0, "rna_Material_update"); } +static void rna_def_material_greasepencil(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* mode type styles */ + static EnumPropertyItem gpcolordata_mode_types_items[] = { + { GP_STYLE_MODE_LINE, "LINE", 0, "Line", "Draw strokes using a continuous line" }, + { GP_STYLE_MODE_DOTS, "DOTS", 0, "Dots", "Draw strokes using separated dots" }, + { GP_STYLE_MODE_BOX, "BOX", 0, "Boxes", "Draw strokes using separated rectangle boxes" }, + { 0, NULL, 0, NULL, NULL } + }; + + /* stroke styles */ + static EnumPropertyItem stroke_style_items[] = { + { GP_STYLE_STROKE_STYLE_SOLID, "SOLID", 0, "Solid", "Draw strokes with solid color" }, + { GP_STYLE_STROKE_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Draw strokes using texture" }, + { 0, NULL, 0, NULL, NULL } + }; + + /* fill styles */ + static EnumPropertyItem fill_style_items[] = { + { GP_STYLE_FILL_STYLE_SOLID, "SOLID", 0, "Solid", "Fill area with solid color" }, + { GP_STYLE_FILL_STYLE_GRADIENT, "GRADIENT", 0, "Gradient", "Fill area with gradient color" }, + { GP_STYLE_FILL_STYLE_CHESSBOARD, "CHESSBOARD", 0, "Checker Board", "Fill area with chessboard pattern" }, + { GP_STYLE_FILL_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Fill area with image texture" }, + { 0, NULL, 0, NULL, NULL } + }; + + static EnumPropertyItem fill_gradient_items[] = { + { GP_STYLE_GRADIENT_LINEAR, "LINEAR", 0, "Linear", "Fill area with gradient color" }, + { GP_STYLE_GRADIENT_RADIAL, "RADIAL", 0, "Radial", "Fill area with radial gradient" }, + { 0, NULL, 0, NULL, NULL } + }; + + srna = RNA_def_struct(brna, "MaterialGPencilStyle", NULL); + RNA_def_struct_sdna(srna, "MaterialGPencilStyle"); + RNA_def_struct_ui_text(srna, "Grease Pencil Color", ""); + RNA_def_struct_path_func(srna, "rna_GpencilColorData_path"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "stroke_rgba"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Color", ""); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Fill Drawing Color */ + prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "fill_rgba"); + RNA_def_property_array(prop, 4); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Secondary Drawing Color */ + prop = RNA_def_property(srna, "mix_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "mix_rgba"); + RNA_def_property_array(prop, 4); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Mix Color", "Color for mixing with primary filling color"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Mix factor */ + prop = RNA_def_property(srna, "mix_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "mix_factor"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Mix", "Mix Adjustment Factor"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Scale factor for uv coordinates */ + prop = RNA_def_property(srna, "pattern_scale", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "gradient_scale"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "Scale", "Scale Factor for UV coordinates"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Shift factor to move pattern filling in 2d space */ + prop = RNA_def_property(srna, "pattern_shift", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "gradient_shift"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "Shift", "Shift filling pattern in 2d space"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Gradient angle */ + prop = RNA_def_property(srna, "pattern_angle", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "gradient_angle"); + RNA_def_property_ui_text(prop, "Angle", "Pattern Orientation Angle"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Gradient radius */ + prop = RNA_def_property(srna, "pattern_radius", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "gradient_radius"); + RNA_def_property_range(prop, 0.0001f, 10.0f); + RNA_def_property_ui_text(prop, "Radius", "Pattern Radius"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Box size */ + prop = RNA_def_property(srna, "pattern_gridsize", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "pattern_gridsize"); + RNA_def_property_range(prop, 0.0001f, 10.0f); + RNA_def_property_ui_text(prop, "Size", "Box Size"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Texture angle */ + prop = RNA_def_property(srna, "texture_angle", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "texture_angle"); + RNA_def_property_ui_text(prop, "Angle", "Texture Orientation Angle"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Scale factor for texture */ + prop = RNA_def_property(srna, "texture_scale", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "texture_scale"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "Scale", "Scale Factor for Texture"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Shift factor to move texture in 2d space */ + prop = RNA_def_property(srna, "texture_offset", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "texture_offset"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "Offset", "Shift Texture in 2d Space"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Texture opacity size */ + prop = RNA_def_property(srna, "texture_opacity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "texture_opacity"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Opacity", "Texture Opacity"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* texture pixsize factor (used for UV along the stroke) */ + prop = RNA_def_property(srna, "pixel_size", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "texture_pixsize"); + RNA_def_property_range(prop, 1, 5000); + RNA_def_property_ui_text(prop, "UV Factor", "Texture Pixel Size factor along the stroke"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_gpcolordata_uv_update"); + + /* Flags */ + prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_HIDE); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1); + RNA_def_property_ui_text(prop, "Hide", "Set color Visibility"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update"); + + prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_LOCKED); + RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1); + RNA_def_property_ui_text(prop, "Locked", "Protect color from further editing and/or frame changes"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update"); + + prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_ONIONSKIN); + RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0); + RNA_def_property_ui_text(prop, "Show in Ghosts", "Display strokes using this color when showing onion skins"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update"); + + prop = RNA_def_property(srna, "texture_clamp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_TEX_CLAMP); + RNA_def_property_ui_text(prop, "Clamp", "Do not repeat texture and clamp to one instance only"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + prop = RNA_def_property(srna, "texture_mix", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_TEX_MIX); + RNA_def_property_ui_text(prop, "Mix Texture", "Mix texture image with filling colors"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + prop = RNA_def_property(srna, "flip", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_COLOR_FLIP_FILL); + RNA_def_property_ui_text(prop, "Flip", "Flip filling colors"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + prop = RNA_def_property(srna, "use_stroke_pattern", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_PATTERN); + RNA_def_property_ui_text(prop, "Pattern", "Use Stroke Texture as a pattern to apply color"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + prop = RNA_def_property(srna, "use_fill_pattern", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_PATTERN); + RNA_def_property_ui_text(prop, "Pattern", "Use Fill Texture as a pattern to apply color"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* pass index for future compositing and editing tools */ + prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "index"); + RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Color Index\" pass"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_nopreview_update"); + + /* mode type */ + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, gpcolordata_mode_types_items); + RNA_def_property_ui_text(prop, "Mode Type", "Select draw mode for stroke"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* stroke style */ + prop = RNA_def_property(srna, "stroke_style", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "stroke_style"); + RNA_def_property_enum_items(prop, stroke_style_items); + RNA_def_property_ui_text(prop, "Stroke Style", "Select style used to draw strokes"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* stroke image texture */ + prop = RNA_def_property(srna, "stroke_image", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "sima"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_GpencilColorData_stroke_image_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Image", ""); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* fill style */ + prop = RNA_def_property(srna, "fill_style", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "fill_style"); + RNA_def_property_enum_items(prop, fill_style_items); + RNA_def_property_ui_text(prop, "Fill Style", "Select style used to fill strokes"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* gradient type */ + prop = RNA_def_property(srna, "gradient_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "gradient_type"); + RNA_def_property_enum_items(prop, fill_gradient_items); + RNA_def_property_ui_text(prop, "Gradient Type", "Select type of gradient used to fill strokes"); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* fill image texture */ + prop = RNA_def_property(srna, "fill_image", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "ima"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_GpencilColorData_fill_image_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Image", ""); + RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); + + /* Read-only state props (for simpler UI code) */ + prop = RNA_def_property(srna, "is_stroke_visible", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_GpencilColorData_is_stroke_visible_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Is Stroke Visible", "True when opacity of stroke is set high enough to be visible"); + + prop = RNA_def_property(srna, "is_fill_visible", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_GpencilColorData_is_fill_visible_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Is Fill Visible", "True when opacity of fill is set high enough to be visible"); + +} + void RNA_def_material(BlenderRNA *brna) { StructRNA *srna; @@ -410,6 +734,19 @@ void RNA_def_material(BlenderRNA *brna) rna_def_material_display(srna); + /* grease pencil */ + prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "gp_style"); + RNA_def_property_ui_text(prop, "Grease Pencil Settings", "Grease pencil color settings for material"); + + prop = RNA_def_property(srna, "is_grease_pencil", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_is_grease_pencil_get", NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Is Grease Pencil", "True if this material has grease pencil data"); + + rna_def_material_greasepencil(brna); + + RNA_api_material(srna); } diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c index aded4229a3c..81c3c9b43b9 100644 --- a/source/blender/makesrna/intern/rna_movieclip.c +++ b/source/blender/makesrna/intern/rna_movieclip.c @@ -338,6 +338,7 @@ static void rna_def_movieclip(BlenderRNA *brna) prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this movie clip"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index b9a8f306baf..a6172bd9cc2 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -8358,6 +8358,7 @@ static void rna_def_nodetree(BlenderRNA *brna) prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block"); RNA_def_property_update(prop, NC_NODE, NULL); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index ac1a6d512c3..d84827210bf 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -37,6 +37,8 @@ #include "DNA_scene_types.h" #include "DNA_meta_types.h" #include "DNA_workspace_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_shader_fx_types.h" #include "BLI_utildefines.h" #include "BLI_listbase.h" @@ -71,7 +73,10 @@ const EnumPropertyItem rna_enum_object_mode_items[] = { {OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""}, {OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""}, {OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""}, - {OB_MODE_GPENCIL, "GPENCIL_EDIT", ICON_GREASEPENCIL, "Edit Strokes", "Edit Grease Pencil Strokes"}, + {OB_MODE_GPENCIL_EDIT, "GPENCIL_EDIT", ICON_EDITMODE_HLT, "Edit Mode", "Edit Grease Pencil Strokes"}, + {OB_MODE_GPENCIL_SCULPT, "GPENCIL_SCULPT", ICON_SCULPTMODE_HLT, "Sculpt Mode", "Sculpt Grease Pencil Strokes"}, + {OB_MODE_GPENCIL_PAINT, "GPENCIL_PAINT", ICON_GREASEPENCIL, "Draw", "Paint Grease Pencil Strokes"}, + {OB_MODE_GPENCIL_WEIGHT, "GPENCIL_WEIGHT", ICON_WPAINT_HLT, "Weight Paint", "Grease Pencil Weight Paint Strokes" }, {0, NULL, 0, NULL, NULL} }; @@ -87,6 +92,11 @@ const EnumPropertyItem rna_enum_object_empty_drawtype_items[] = { {0, NULL, 0, NULL, NULL} }; +const EnumPropertyItem rna_enum_object_gpencil_type_items[] = { + { GP_EMPTY, "EMPTY", ICON_OUTLINER_OB_GREASEPENCIL, "Blank", "Create an empty grease pencil object" }, + { GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object" }, + { 0, NULL, 0, NULL, NULL } +}; static const EnumPropertyItem parent_type_items[] = { {PAROBJECT, "OBJECT", 0, "Object", "The object is parented to an object"}, @@ -144,6 +154,7 @@ const EnumPropertyItem rna_enum_object_type_items[] = { {OB_ARMATURE, "ARMATURE", 0, "Armature", ""}, {OB_LATTICE, "LATTICE", 0, "Lattice", ""}, {OB_EMPTY, "EMPTY", 0, "Empty", ""}, + {OB_GPENCIL, "GPENCIL", 0, "GPencil", ""}, {0, "", 0, NULL, NULL}, {OB_CAMERA, "CAMERA", 0, "Camera", ""}, {OB_LAMP, "LIGHT", 0, "Light", ""}, @@ -175,6 +186,7 @@ const EnumPropertyItem rna_enum_object_axis_items[] = { #include "DNA_key_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_ID.h" #include "DNA_lattice_types.h" #include "DNA_node_types.h" @@ -383,10 +395,24 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr) case OB_ARMATURE: return &RNA_Armature; case OB_SPEAKER: return &RNA_Speaker; case OB_LIGHTPROBE: return &RNA_LightProbe; + case OB_GPENCIL: return &RNA_GreasePencil; default: return &RNA_ID; } } +static bool rna_Object_data_poll(PointerRNA *ptr, const PointerRNA value) +{ + Object *ob = (Object *)ptr->data; + + if (ob->type == OB_GPENCIL) { + /* GP Object - Don't allow using "Annotation" GP datablocks here */ + bGPdata *gpd = value.data; + return (gpd->flag & GP_DATA_ANNOTATIONS) == 0; + } + + return true; +} + static void rna_Object_parent_set(PointerRNA *ptr, PointerRNA value) { Object *ob = (Object *)ptr->data; @@ -942,6 +968,21 @@ static void rna_MaterialSlot_material_set(PointerRNA *ptr, PointerRNA value) assign_material(G_MAIN, ob, value.data, index + 1, BKE_MAT_ASSIGN_EXISTING); } +static bool rna_MaterialSlot_material_poll(PointerRNA *ptr, PointerRNA value) +{ + Object *ob = (Object *)ptr->id.data; + Material *ma = (Material *)value.data; + + if (ob->type == OB_GPENCIL) { + /* GP Materials only */ + return (ma->gp_style != NULL); + } + else { + /* Everything except GP materials */ + return (ma->gp_style == NULL); + } +} + static int rna_MaterialSlot_link_get(PointerRNA *ptr) { Object *ob = (Object *)ptr->id.data; @@ -1007,7 +1048,6 @@ static char *rna_MaterialSlot_path(PointerRNA *ptr) Object *ob = (Object *)ptr->id.data; int index = (Material **)ptr->data - ob->mat; - /* from armature... */ return BLI_sprintfN("material_slots[%d]", index); } @@ -1275,6 +1315,61 @@ bool rna_Object_modifiers_override_apply( return true; } +static GpencilModifierData *rna_Object_greasepencil_modifier_new( + Object *object, bContext *C, ReportList *reports, + const char *name, int type) +{ + return ED_object_gpencil_modifier_add(reports, CTX_data_main(C), CTX_data_scene(C), object, name, type); +} + +static void rna_Object_greasepencil_modifier_remove( + Object *object, bContext *C, ReportList *reports, PointerRNA *gmd_ptr) +{ + GpencilModifierData *gmd = gmd_ptr->data; + if (ED_object_gpencil_modifier_remove(reports, CTX_data_main(C), object, gmd) == false) { + /* error is already set */ + return; + } + + RNA_POINTER_INVALIDATE(gmd_ptr); + + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); +} + +static void rna_Object_greasepencil_modifier_clear(Object *object, bContext *C) +{ + ED_object_gpencil_modifier_clear(CTX_data_main(C), object); + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); +} + +/* shader fx */ +static ShaderFxData *rna_Object_shaderfx_new( + Object *object, bContext *C, ReportList *reports, + const char *name, int type) +{ + return ED_object_shaderfx_add(reports, CTX_data_main(C), CTX_data_scene(C), object, name, type); +} + +static void rna_Object_shaderfx_remove( + Object *object, bContext *C, ReportList *reports, PointerRNA *gmd_ptr) +{ + ShaderFxData *gmd = gmd_ptr->data; + if (ED_object_shaderfx_remove(reports, CTX_data_main(C), object, gmd) == false) { + /* error is already set */ + return; + } + + RNA_POINTER_INVALIDATE(gmd_ptr); + + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); +} + +static void rna_Object_shaderfx_clear(Object *object, bContext *C) +{ + ED_object_shaderfx_clear(CTX_data_main(C), object); + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object); +} + static void rna_Object_boundbox_get(PointerRNA *ptr, float *values) { Object *ob = (Object *)ptr->id.data; @@ -1453,6 +1548,11 @@ bool rna_Light_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value) return ((Object *)value.id.data)->type == OB_LAMP; } +bool rna_GPencil_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value) +{ + return ((Object *)value.id.data)->type == OB_GPENCIL; +} + int rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr) { SculptSession *ss = ((Object *)ptr->id.data)->sculpt; @@ -1601,7 +1701,7 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_editable_func(prop, "rna_MaterialSlot_material_editable"); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); - RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, NULL); + RNA_def_property_pointer_funcs(prop, "rna_MaterialSlot_material_get", "rna_MaterialSlot_material_set", NULL, "rna_MaterialSlot_material_poll"); RNA_def_property_ui_text(prop, "Material", "Material data-block used by this material slot"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update"); @@ -1715,6 +1815,88 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove all modifiers from the object"); } +/* object.grease_pencil_modifiers */ +static void rna_def_object_grease_pencil_modifiers(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "ObjectGpencilModifiers"); + srna = RNA_def_struct(brna, "ObjectGpencilModifiers", NULL); + RNA_def_struct_sdna(srna, "Object"); + RNA_def_struct_ui_text(srna, "Object Grease Pencil Modifiers", "Collection of object grease pencil modifiers"); + + /* add greasepencil modifier */ + func = RNA_def_function(srna, "new", "rna_Object_greasepencil_modifier_new"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, "Add a new greasepencil_modifier"); + parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the greasepencil_modifier"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* greasepencil_modifier to add */ + parm = RNA_def_enum(func, "type", rna_enum_object_greasepencil_modifier_type_items, 1, "", "Modifier type to add"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* return type */ + parm = RNA_def_pointer(func, "greasepencil_modifier", "GpencilModifier", "", "Newly created modifier"); + RNA_def_function_return(func, parm); + + /* remove greasepencil_modifier */ + func = RNA_def_function(srna, "remove", "rna_Object_greasepencil_modifier_remove"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, "Remove an existing greasepencil_modifier from the object"); + /* greasepencil_modifier to remove */ + parm = RNA_def_pointer(func, "greasepencil_modifier", "GpencilModifier", "", "Modifier to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + /* clear all greasepencil modifiers */ + func = RNA_def_function(srna, "clear", "rna_Object_greasepencil_modifier_clear"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Remove all grease pencil modifiers from the object"); +} + +/* object.shaderfxs */ +static void rna_def_object_shaderfxs(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "ObjectShaderFx"); + srna = RNA_def_struct(brna, "ObjectShaderFx", NULL); + RNA_def_struct_sdna(srna, "Object"); + RNA_def_struct_ui_text(srna, "Object Shader Effects", "Collection of object effects"); + + /* add shader_fx */ + func = RNA_def_function(srna, "new", "rna_Object_shaderfx_new"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, "Add a new shader fx"); + parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the effect"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* shader to add */ + parm = RNA_def_enum(func, "type", rna_enum_object_shaderfx_type_items, 1, "", "Effect type to add"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* return type */ + parm = RNA_def_pointer(func, "shader_fx", "ShaderFx", "", "Newly created effect"); + RNA_def_function_return(func, parm); + + /* remove shader_fx */ + func = RNA_def_function(srna, "remove", "rna_Object_shaderfx_remove"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, "Remove an existing effect from the object"); + /* shader to remove */ + parm = RNA_def_pointer(func, "shader_fx", "ShaderFx", "", "Effect to remove"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + /* clear all shader fx */ + func = RNA_def_function(srna, "clear", "rna_Object_shaderfx_clear"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Remove all effects from the object"); +} + /* object.particle_systems */ static void rna_def_object_particle_systems(BlenderRNA *brna, PropertyRNA *cprop) { @@ -1919,7 +2101,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "data", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "ID"); - RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", NULL); + RNA_def_property_pointer_funcs(prop, NULL, "rna_Object_data_set", "rna_Object_data_typef", "rna_Object_data_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_ui_text(prop, "Data", "Object data"); @@ -2017,7 +2199,8 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "active_material", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Material"); RNA_def_property_pointer_funcs(prop, "rna_Object_active_material_get", - "rna_Object_active_material_set", NULL, NULL); + "rna_Object_active_material_set", NULL, + "rna_MaterialSlot_material_poll"); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); RNA_def_property_editable_func(prop, "rna_Object_active_material_editable"); @@ -2211,6 +2394,20 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC | PROPOVERRIDE_STATIC_INSERTION); rna_def_object_modifiers(brna, prop); + /* Grease Pencil modifiers. */ + prop = RNA_def_property(srna, "grease_pencil_modifiers", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "greasepencil_modifiers", NULL); + RNA_def_property_struct_type(prop, "GpencilModifier"); + RNA_def_property_ui_text(prop, "Grease Pencil Modifiers", "Modifiers affecting the data of the grease pencil object"); + rna_def_object_grease_pencil_modifiers(brna, prop); + + /* Shader FX. */ + prop = RNA_def_property(srna, "shader_effects", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "shader_fx", NULL); + RNA_def_property_struct_type(prop, "ShaderFx"); + RNA_def_property_ui_text(prop, "Shader Effects", "Effects affecting display of object"); + rna_def_object_shaderfxs(brna, prop); + /* constraints */ prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "Constraint"); @@ -2482,12 +2679,15 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); /* Grease Pencil */ +#if 1 /* FIXME: Remove this code when all Open-Movie assets have been fixed */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_obdata_poll"); /* XXX */ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); - RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block"); + RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block (deprecated)"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); +#endif /* pose */ prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c index 4d6b94bf709..547cac9f38d 100644 --- a/source/blender/makesrna/intern/rna_palette.c +++ b/source/blender/makesrna/intern/rna_palette.c @@ -39,7 +39,6 @@ #include "BKE_paint.h" #include "BKE_report.h" - static PaletteColor *rna_Palette_color_new(Palette *palette) { PaletteColor *color = BKE_palette_color_add(palette); @@ -139,6 +138,7 @@ static void rna_def_palettecolor(BlenderRNA *brna) prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "rgb"); + RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Color", ""); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); @@ -153,6 +153,7 @@ static void rna_def_palettecolor(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "value"); RNA_def_property_ui_text(prop, "Weight", ""); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + } static void rna_def_palette(BlenderRNA *brna) @@ -167,6 +168,7 @@ static void rna_def_palette(BlenderRNA *brna) prop = RNA_def_property(srna, "colors", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "PaletteColor"); rna_def_palettecolors(brna, prop); + } void RNA_def_palette(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 915018612a1..9fde87be486 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -51,6 +51,7 @@ #include "BKE_paint.h" #include "ED_object.h" +#include "ED_gpencil.h" #include "GPU_extensions.h" @@ -530,6 +531,13 @@ static const EnumPropertyItem transform_orientation_items[] = { #include "FRS_freestyle.h" #endif +/* Grease Pencil update cache */ +static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + DEG_id_type_tag(bmain, ID_GD); + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); +} + /* Grease Pencil Interpolation settings */ static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr)) { @@ -551,110 +559,8 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value) { settings->custom_ipo = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); } -} - -/* Grease pencil Drawing Brushes */ -static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, bool setactive) -{ - bGPDbrush *brush = BKE_gpencil_brush_addnew(ts, name, setactive != 0); - - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return brush; -} - -static void rna_GPencil_brush_remove(ToolSettings *ts, ReportList *reports, PointerRNA *brush_ptr) -{ - bGPDbrush *brush = brush_ptr->data; - if (BLI_findindex(&ts->gp_brushes, brush) == -1) { - BKE_report(reports, RPT_ERROR, "Brush not found in grease pencil data"); - return; - } - - BKE_gpencil_brush_delete(ts, brush); - RNA_POINTER_INVALIDATE(brush_ptr); - - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -static PointerRNA rna_GPencilBrushes_active_get(PointerRNA *ptr) -{ - ToolSettings *ts = (ToolSettings *) ptr->data; - - bGPDbrush *brush; - - for (brush = ts->gp_brushes.first; brush; brush = brush->next) { - if (brush->flag & GP_BRUSH_ACTIVE) { - break; - } - } - - if (brush) { - return rna_pointer_inherit_refine(ptr, &RNA_GPencilBrush, brush); - } - - return rna_pointer_inherit_refine(ptr, NULL, NULL); -} - -static void rna_GPencilBrushes_active_set(PointerRNA *ptr, PointerRNA value) -{ - ToolSettings *ts = (ToolSettings *) ptr->data; - - bGPDbrush *brush; - - for (brush = ts->gp_brushes.first; brush; brush = brush->next) { - if (brush == value.data) { - brush->flag |= GP_BRUSH_ACTIVE; - } - else { - brush->flag &= ~GP_BRUSH_ACTIVE; - } - } - WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); -} - -static int rna_GPencilBrushes_index_get(PointerRNA *ptr) -{ - ToolSettings *ts = (ToolSettings *) ptr->data; - bGPDbrush *brush = BKE_gpencil_brush_getactive(ts); - return BLI_findindex(&ts->gp_brushes, brush); } - -static void rna_GPencilBrushes_index_set(PointerRNA *ptr, int value) -{ - ToolSettings *ts = (ToolSettings *) ptr->data; - - bGPDbrush *brush = BLI_findlink(&ts->gp_brushes, value); - - BKE_gpencil_brush_setactive(ts, brush); - WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); -} - -static void rna_GPencilBrushes_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) -{ - ToolSettings *ts = (ToolSettings *) ptr->data; - - *min = 0; - *max = max_ii(0, BLI_listbase_count(&ts->gp_brushes) - 1); - - *softmin = *min; - *softmax = *max; -} - -static void rna_GPencilBrush_name_set(PointerRNA *ptr, const char *value) -{ - ToolSettings *ts = ((Scene *) ptr->id.data)->toolsettings; - bGPDbrush *brush = ptr->data; - - /* copy the new name into the name slot */ - BLI_strncpy_utf8(brush->info, value, sizeof(brush->info)); - - BLI_uniquename(&ts->gp_brushes, brush, DATA_("GP_Brush"), '.', offsetof(bGPDbrush, info), sizeof(brush->info)); -} - -/* ----------------- end of Grease pencil drawing brushes ------------*/ - static void rna_ToolSettings_gizmo_flag_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { ToolSettings *ts = scene->toolsettings; @@ -2190,205 +2096,6 @@ static void rna_def_gpencil_interpolate(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); } -/* Grease Pencil Drawing Brushes */ -static void rna_def_gpencil_brush(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "GPencilBrush", NULL); - RNA_def_struct_sdna(srna, "bGPDbrush"); - RNA_def_struct_ui_text(srna, "Grease Pencil Brush", - "Collection of brushes being used to control the line style of new strokes"); - RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA); - - /* Name */ - prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); - RNA_def_property_string_sdna(prop, NULL, "info"); - RNA_def_property_ui_text(prop, "Name", "Brush name"); - RNA_def_property_string_funcs(prop, NULL, NULL, "rna_GPencilBrush_name_set"); - RNA_def_struct_name_property(srna, prop); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Line Thickness */ - prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL); - RNA_def_property_int_sdna(prop, NULL, "thickness"); - RNA_def_property_range(prop, 1, 300); - RNA_def_property_ui_range(prop, 1, 10, 1, 0); - RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Sensitivity factor for new strokes */ - prop = RNA_def_property(srna, "pen_sensitivity_factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "draw_sensitivity"); - RNA_def_property_range(prop, 0.1f, 3.0f); - RNA_def_property_ui_text(prop, "Sensitivity", "Pressure sensitivity factor for new strokes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Strength factor for new strokes */ - prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "draw_strength"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Strength", "Color strength for new strokes (affect alpha factor of color)"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Jitter factor for new strokes */ - prop = RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "draw_jitter"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Jitter", "Jitter factor for new strokes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Randomnes factor for sensitivity and strength */ - prop = RNA_def_property(srna, "random_press", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "draw_random_press"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Randomness", "Randomness factor for pressure and strength in new strokes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Randomnes factor for subdivision */ - prop = RNA_def_property(srna, "random_subdiv", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "draw_random_sub"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Random Subdivision", "Randomness factor for new strokes after subdivision"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Angle when brush is full size */ - prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); - RNA_def_property_float_sdna(prop, NULL, "draw_angle"); - RNA_def_property_range(prop, -M_PI_2, M_PI_2); - RNA_def_property_ui_text(prop, "Angle", - "Direction of the stroke at which brush gives maximal thickness " - "(0° for horizontal)"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Factor to change brush size depending of angle */ - prop = RNA_def_property(srna, "angle_factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "draw_angle_factor"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Angle Factor", - "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Smoothing factor for new strokes */ - prop = RNA_def_property(srna, "pen_smooth_factor", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "draw_smoothfac"); - RNA_def_property_range(prop, 0.0, 2.0f); - RNA_def_property_ui_text(prop, "Smooth", - "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Iterations of the Smoothing factor */ - prop = RNA_def_property(srna, "pen_smooth_steps", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "draw_smoothlvl"); - RNA_def_property_range(prop, 1, 3); - RNA_def_property_ui_text(prop, "Iterations", - "Number of times to smooth newly created strokes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Subdivision level for new strokes */ - prop = RNA_def_property(srna, "pen_subdivision_steps", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "sublevel"); - RNA_def_property_range(prop, 0, 3); - RNA_def_property_ui_text(prop, "Subdivision Steps", - "Number of times to subdivide newly created strokes, for less jagged strokes"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Curves for pressure */ - prop = RNA_def_property(srna, "curve_sensitivity", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "cur_sensitivity"); - RNA_def_property_struct_type(prop, "CurveMapping"); - RNA_def_property_ui_text(prop, "Curve Sensitivity", "Curve used for the sensitivity"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - prop = RNA_def_property(srna, "curve_strength", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "cur_strength"); - RNA_def_property_struct_type(prop, "CurveMapping"); - RNA_def_property_ui_text(prop, "Curve Strength", "Curve used for the strength"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - prop = RNA_def_property(srna, "curve_jitter", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "cur_jitter"); - RNA_def_property_struct_type(prop, "CurveMapping"); - RNA_def_property_ui_text(prop, "Curve Jitter", "Curve used for the jitter effect"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - /* Flags */ - prop = RNA_def_property(srna, "use_pressure", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_PRESSURE); - RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); - RNA_def_property_ui_text(prop, "Use Pressure", "Use tablet pressure"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - prop = RNA_def_property(srna, "use_strength_pressure", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_STENGTH_PRESSURE); - RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); - RNA_def_property_ui_text(prop, "Use Pressure Strength", "Use tablet pressure for color strength"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - prop = RNA_def_property(srna, "use_jitter_pressure", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_JITTER_PRESSURE); - RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); - RNA_def_property_ui_text(prop, "Use Pressure Jitter", "Use tablet pressure for jitter"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - prop = RNA_def_property(srna, "use_random_pressure", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_PRESSURE); - RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0); - RNA_def_property_ui_text(prop, "Random Pressure", "Use random value for pressure"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - - prop = RNA_def_property(srna, "use_random_strength", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_USE_RANDOM_STRENGTH); - RNA_def_property_ui_icon(prop, ICON_PARTICLES, 0); - RNA_def_property_ui_text(prop, "Random Strength", "Use random value for strength"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - -} - -/* Grease Pencil Drawing Brushes API */ -static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop) -{ - StructRNA *srna; - PropertyRNA *prop; - - FunctionRNA *func; - PropertyRNA *parm; - - RNA_def_property_srna(cprop, "GreasePencilBrushes"); - srna = RNA_def_struct(brna, "GreasePencilBrushes", NULL); - RNA_def_struct_sdna(srna, "ToolSettings"); - RNA_def_struct_ui_text(srna, "Grease Pencil Brushes", "Collection of grease pencil brushes"); - - func = RNA_def_function(srna, "new", "rna_GPencil_brush_new"); - RNA_def_function_ui_description(func, "Add a new grease pencil brush"); - parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush"); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created brush to the active brush"); - parm = RNA_def_pointer(func, "palette", "GPencilBrush", "", "The newly created brush"); - RNA_def_function_return(func, parm); - - func = RNA_def_function(srna, "remove", "rna_GPencil_brush_remove"); - RNA_def_function_ui_description(func, "Remove a grease pencil brush"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); - parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The brush to remove"); - RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); - RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); - - prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); - RNA_def_property_struct_type(prop, "GPencilBrush"); - RNA_def_property_pointer_funcs(prop, "rna_GPencilBrushes_active_get", "rna_GPencilBrushes_active_set", NULL, NULL); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Active Brush", "Current active brush"); - - prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, - "rna_GPencilBrushes_index_get", - "rna_GPencilBrushes_index_set", - "rna_GPencilBrushes_index_range"); - RNA_def_property_ui_text(prop, "Active Brush Index", "Index of active brush"); -} - static void rna_def_transform_orientation(BlenderRNA *brna) { StructRNA *srna; @@ -2446,21 +2153,20 @@ static void rna_def_tool_settings(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem gpencil_source_3d_items[] = { - {GP_TOOL_SOURCE_SCENE, "SCENE", 0, "Scene", - "Grease Pencil data attached to the current scene is used, " - "unless the active object already has Grease Pencil data (i.e. for old files)"}, - {GP_TOOL_SOURCE_OBJECT, "OBJECT", 0, "Object", - "Grease Pencil data-blocks attached to the active object are used " - "(required when using pre 2.73 add-ons, e.g. BSurfaces)"}, + static const EnumPropertyItem gpencil_stroke_placement_items[] = { + {GP_PROJECT_VIEWSPACE, "ORIGIN", ICON_OBJECT_ORIGIN, "Origin", "Draw stroke at Object origin"}, + {GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Draw stroke at 3D cursor location" }, + // {0, "VIEW", ICON_VISIBLE_IPO_ON, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */ + {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", ICON_FACESEL, "Surface", "Stick stroke to surfaces"}, + //{GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", ICON_GREASEPENCIL, "Stroke", "Stick stroke to other strokes"}, {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem gpencil_stroke_placement_items[] = { - {GP_PROJECT_VIEWSPACE, "CURSOR", 0, "Cursor", "Draw stroke at the 3D cursor"}, - {0, "VIEW", 0, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */ - {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", 0, "Surface", "Stick stroke to surfaces"}, - {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", 0, "Stroke", "Stick stroke to other strokes"}, + static const EnumPropertyItem annotation_stroke_placement_items[] = { + {GP_PROJECT_VIEWSPACE | GP_PROJECT_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Draw stroke at 3D cursor location" }, + {0, "VIEW", ICON_VISIBLE_IPO_ON, "View", "Stick stroke to the view "}, /* weird, GP_PROJECT_VIEWALIGN is inverted */ + {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_VIEW, "SURFACE", ICON_FACESEL, "Surface", "Stick stroke to surfaces"}, + {GP_PROJECT_VIEWSPACE | GP_PROJECT_DEPTH_STROKE, "STROKE", ICON_GREASEPENCIL, "Stroke", "Stick stroke to other strokes"}, {0, NULL, 0, NULL, NULL} }; @@ -2504,7 +2210,8 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Scene_update_active_object_data"); prop = RNA_def_property(srna, "vertex_paint", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "vpaint"); RNA_def_property_ui_text(prop, "Vertex Paint", ""); + RNA_def_property_pointer_sdna(prop, NULL, "vpaint"); + RNA_def_property_ui_text(prop, "Vertex Paint", ""); prop = RNA_def_property(srna, "weight_paint", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "wpaint"); @@ -2518,6 +2225,10 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "uvsculpt"); RNA_def_property_ui_text(prop, "UV Sculpt", ""); + prop = RNA_def_property(srna, "gpencil_paint", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "gp_paint"); + RNA_def_property_ui_text(prop, "Grease Pencil Paint", ""); + prop = RNA_def_property(srna, "particle_edit", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "particle"); RNA_def_property_ui_text(prop, "Particle Edit", ""); @@ -2695,12 +2406,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ToolSettings_gizmo_flag_update"); /* Grease Pencil */ - prop = RNA_def_property(srna, "use_gpencil_continuous_drawing", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_PAINTSESSIONS_ON); - RNA_def_property_ui_text(prop, "Use Continuous Drawing", - "Allow drawing multiple strokes at a time with Grease Pencil"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* xxx: need toolbar to be redrawn... */ - prop = RNA_def_property(srna, "use_gpencil_additive_drawing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_RETAIN_LAST); RNA_def_property_ui_text(prop, "Use Additive Drawing", @@ -2714,12 +2419,11 @@ static void rna_def_tool_settings(BlenderRNA *brna) "When draw new strokes, the new stroke is drawn below of all strokes in the layer"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "grease_pencil_source", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_src"); - RNA_def_property_enum_items(prop, gpencil_source_3d_items); - RNA_def_property_ui_text(prop, "Grease Pencil Source", - "Data-block where active Grease Pencil data is found from"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + prop = RNA_def_property(srna, "use_gpencil_thumbnail_list", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "gpencil_flags", GP_TOOL_FLAG_THUMBNAIL_LIST); + RNA_def_property_ui_text(prop, "Compact List", + "Show compact list of color instead of thumbnails"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt"); @@ -2733,13 +2437,6 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Grease Pencil Interpolate", "Settings for Grease Pencil Interpolation tools"); - /* Grease Pencil - Drawing brushes */ - prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE); - RNA_def_property_collection_sdna(prop, NULL, "gp_brushes", NULL); - RNA_def_property_struct_type(prop, "GPencilBrush"); - RNA_def_property_ui_text(prop, "Grease Pencil Brushes", "Grease Pencil drawing brushes"); - rna_def_gpencil_brushes(brna, prop); - /* Grease Pencil - 3D View Stroke Placement */ prop = RNA_def_property(srna, "gpencil_stroke_placement_view3d", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v3d_align"); @@ -2752,27 +2449,41 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - /* Grease Pencil - 2D Views Stroke Placement */ - prop = RNA_def_property(srna, "gpencil_stroke_placement_view2d", PROP_ENUM, PROP_NONE); + /* Annotations - 2D Views Stroke Placement */ + prop = RNA_def_property(srna, "annotation_stroke_placement_view2d", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_v2d_align"); - RNA_def_property_enum_items(prop, gpencil_stroke_placement_items); + RNA_def_property_enum_items(prop, annotation_stroke_placement_items); RNA_def_property_ui_text(prop, "Stroke Placement (2D View)", ""); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - /* Grease Pencil - Sequencer Preview Stroke Placement */ - prop = RNA_def_property(srna, "gpencil_stroke_placement_sequencer_preview", PROP_ENUM, PROP_NONE); + /* Annotations - Sequencer Preview Stroke Placement */ + prop = RNA_def_property(srna, "annotation_stroke_placement_sequencer_preview", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_seq_align"); - RNA_def_property_enum_items(prop, gpencil_stroke_placement_items); + RNA_def_property_enum_items(prop, annotation_stroke_placement_items); RNA_def_property_ui_text(prop, "Stroke Placement (Sequencer Preview)", ""); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); - /* Grease Pencil - Image Editor Stroke Placement */ - prop = RNA_def_property(srna, "gpencil_stroke_placement_image_editor", PROP_ENUM, PROP_NONE); + /* Annotations - Image Editor Stroke Placement */ + prop = RNA_def_property(srna, "annotation_stroke_placement_image_editor", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_ima_align"); - RNA_def_property_enum_items(prop, gpencil_stroke_placement_items); + RNA_def_property_enum_items(prop, annotation_stroke_placement_items); RNA_def_property_ui_text(prop, "Stroke Placement (Image Editor)", ""); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + /* Annotations - 3D View Stroke Placement */ + /* XXX: Do we need to decouple the stroke_endpoints setting too? */ + prop = RNA_def_property(srna, "annotation_stroke_placement_view3d", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "annotate_v3d_align"); + RNA_def_property_enum_items(prop, annotation_stroke_placement_items); + RNA_def_property_ui_text(prop, "Annotation Stroke Placement (3D View)", "How annotation strokes are orientated in 3D space"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + + /* Annotations - Stroke Thickness */ + prop = RNA_def_property(srna, "annotation_thickness", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "annotate_thickness"); + RNA_def_property_range(prop, 1, 10); + RNA_def_property_ui_text(prop, "Annotation Stroke Thickness", "Thickness of annotation strokes"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Auto Keying */ prop = RNA_def_property(srna, "use_keyframe_insert_auto", PROP_BOOLEAN, PROP_NONE); @@ -5474,6 +5185,32 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Simplify Child Particles", "Global child particles percentage during rendering"); RNA_def_property_update(prop, 0, "rna_Scene_simplify_update"); + /* Grease Pencil - Simplify Options */ + prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE); + RNA_def_property_ui_text(prop, "Simplify", "Simplify Grease Pencil Drawing"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "simplify_gpencil_onplay", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ON_PLAY); + RNA_def_property_ui_text(prop, "On Play", "Simplify Grease Pencil only when play animation"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "simplify_gpencil_view_fill", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FILL); + RNA_def_property_ui_text(prop, "Fill", "Do not fill strokes on viewport"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "simplify_gpencil_remove_lines", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE); + RNA_def_property_ui_text(prop, "Remove Lines", "Remove External Lines of Filling Strokes"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "simplify_gpencil_view_modifier", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER); + RNA_def_property_ui_text(prop, "Fill", "Do not apply modifiers on viewport"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + /* persistent data */ prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA); @@ -6550,8 +6287,9 @@ void RNA_def_scene(BlenderRNA *brna) prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); - RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil data-block"); + RNA_def_property_ui_text(prop, "Annotations", "Grease Pencil data-block used for annotations in the 3D view"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); /* active MovieClip */ @@ -6606,7 +6344,6 @@ void RNA_def_scene(BlenderRNA *brna) /* *** Non-Animated *** */ RNA_define_animate_sdna(false); rna_def_tool_settings(brna); - rna_def_gpencil_brush(brna); rna_def_gpencil_interpolate(brna); rna_def_unified_paint_settings(brna); rna_def_curve_paint_settings(brna); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 5b2a3c9c4f4..6a6c97b41ad 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -64,26 +64,29 @@ static const EnumPropertyItem particle_edit_hair_brush_items[] = { }; const EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = { - {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth stroke points"}, - {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", 0, "Thickness", "Adjust thickness of strokes"}, - { GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", 0, "Strength", "Adjust color strength of strokes" }, - { GP_EDITBRUSH_TYPE_GRAB, "GRAB", 0, "Grab", "Translate the set of points initially within the brush circle" }, - {GP_EDITBRUSH_TYPE_PUSH, "PUSH", 0, "Push", "Move points out of the way, as if combing them"}, - {GP_EDITBRUSH_TYPE_TWIST, "TWIST", 0, "Twist", "Rotate points around the midpoint of the brush"}, - {GP_EDITBRUSH_TYPE_PINCH, "PINCH", 0, "Pinch", "Pull points towards the midpoint of the brush"}, - {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", 0, "Randomize", "Introduce jitter/randomness into strokes"}, - //{GP_EDITBRUSH_TYPE_SUBDIVIDE, "SUBDIVIDE", 0, "Subdivide", "Increase point density for higher resolution strokes when zoomed in"}, - //{GP_EDITBRUSH_TYPE_SIMPLIFY, "SIMPLIFY", 0, "Simplify", "Reduce density of stroke points"}, - {GP_EDITBRUSH_TYPE_CLONE, "CLONE", 0, "Clone", "Paste copies of the strokes stored on the clipboard"}, + {GP_EDITBRUSH_TYPE_SMOOTH, "SMOOTH", ICON_GPBRUSH_SMOOTH, "Smooth", "Smooth stroke points"}, + {GP_EDITBRUSH_TYPE_THICKNESS, "THICKNESS", ICON_GPBRUSH_THICKNESS, "Thickness", "Adjust thickness of strokes"}, + {GP_EDITBRUSH_TYPE_STRENGTH, "STRENGTH", ICON_GPBRUSH_STRENGTH, "Strength", "Adjust color strength of strokes" }, + {GP_EDITBRUSH_TYPE_GRAB, "GRAB", ICON_GPBRUSH_GRAB, "Grab", "Translate the set of points initially within the brush circle" }, + {GP_EDITBRUSH_TYPE_PUSH, "PUSH", ICON_GPBRUSH_PUSH, "Push", "Move points out of the way, as if combing them"}, + {GP_EDITBRUSH_TYPE_TWIST, "TWIST", ICON_GPBRUSH_TWIST, "Twist", "Rotate points around the midpoint of the brush"}, + {GP_EDITBRUSH_TYPE_PINCH, "PINCH", ICON_GPBRUSH_PINCH, "Pinch", "Pull points towards the midpoint of the brush"}, + {GP_EDITBRUSH_TYPE_RANDOMIZE, "RANDOMIZE", ICON_GPBRUSH_RANDOMIZE, "Randomize", "Introduce jitter/randomness into strokes"}, + {GP_EDITBRUSH_TYPE_CLONE, "CLONE", ICON_GPBRUSH_CLONE, "Clone", "Paste copies of the strokes stored on the clipboard"}, + { 0, NULL, 0, NULL, NULL } +}; + +EnumPropertyItem rna_enum_gpencil_weight_brush_items[] = { + { GP_EDITBRUSH_TYPE_WEIGHT, "WEIGHT", ICON_GPBRUSH_WEIGHT, "Weight", "Weight Paint for Vertex Groups" }, { 0, NULL, 0, NULL, NULL } }; #ifndef RNA_RUNTIME static const EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = { - { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" }, - { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" }, - { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" }, - { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" }, + { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", ICON_UNLOCKED, "None", "" }, + { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", ICON_NDOF_DOM, "X", "Project strokes to plane locked to X" }, + { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", ICON_NDOF_DOM, "Y", "Project strokes to plane locked to Y" }, + { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", ICON_NDOF_DOM, "Z", "Project strokes to plane locked to Z" }, { 0, NULL, 0, NULL, NULL } }; #endif @@ -108,13 +111,16 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = { #include "BKE_pbvh.h" #include "BKE_pointcache.h" #include "BKE_object.h" +#include "BKE_gpencil.h" + #include "DEG_depsgraph.h" #include "ED_particle.h" -static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { + DEG_id_type_tag(bmain, ID_GD); WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } @@ -265,6 +271,8 @@ static bool rna_Brush_mode_poll(PointerRNA *ptr, PointerRNA value) mode = OB_MODE_VERTEX_PAINT; else if (ptr->data == ts->wpaint) mode = OB_MODE_WEIGHT_PAINT; + else if (ptr->data == ts->gp_paint) + mode = OB_MODE_GPENCIL_PAINT; return brush->ob_mode & mode; } @@ -346,6 +354,11 @@ static char *rna_UvSculpt_path(PointerRNA *UNUSED(ptr)) return BLI_strdup("tool_settings.uv_sculpt"); } +static char *rna_GpPaint_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("tool_settings.gp_paint"); +} + static char *rna_ParticleBrush_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.particle_edit.brush"); @@ -435,9 +448,14 @@ static PointerRNA rna_GPencilSculptSettings_brush_get(PointerRNA *ptr) GP_BrushEdit_Settings *gset = (GP_BrushEdit_Settings *)ptr->data; GP_EditBrush_Data *brush = NULL; - if ((gset->brushtype >= 0) && (gset->brushtype < TOT_GP_EDITBRUSH_TYPES)) - brush = &gset->brush[gset->brushtype]; - + if ((gset) && (gset->flag & GP_BRUSHEDIT_FLAG_WEIGHT_MODE)) { + if ((gset->weighttype >= GP_EDITBRUSH_TYPE_WEIGHT) && (gset->weighttype < TOT_GP_EDITBRUSH_TYPES)) + brush = &gset->brush[gset->weighttype]; + } + else { + if ((gset->brushtype >= 0) && (gset->brushtype < GP_EDITBRUSH_TYPE_WEIGHT)) + brush = &gset->brush[gset->brushtype]; + } return rna_pointer_inherit_refine(ptr, &RNA_GPencilSculptBrush, brush); } @@ -708,6 +726,14 @@ static void rna_def_uv_sculpt(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "UV Sculpting", ""); } +static void rna_def_gp_paint(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "GpPaint", "Paint"); + RNA_def_struct_path_func(srna, "rna_GpPaint_path"); + RNA_def_struct_ui_text(srna, "Grease Pencil Paint", ""); +} /* use for weight paint too */ static void rna_def_vertex_paint(BlenderRNA *brna) @@ -1059,8 +1085,8 @@ static void rna_def_particle_edit(BlenderRNA *brna) static void rna_def_gpencil_sculpt(BlenderRNA *brna) { static const EnumPropertyItem prop_direction_items[] = { - {0, "ADD", 0, "Add", "Add effect of brush"}, - {GP_EDITBRUSH_FLAG_INVERT, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"}, + {0, "ADD", ICON_ZOOMIN, "Add", "Add effect of brush"}, + {GP_EDITBRUSH_FLAG_INVERT, "SUBTRACT", ICON_ZOOMOUT, "Subtract", "Subtract effect of brush"}, {0, NULL, 0, NULL, NULL}}; StructRNA *srna; @@ -1076,86 +1102,148 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "brushtype"); RNA_def_property_enum_items(prop, rna_enum_gpencil_sculpt_brush_items); RNA_def_property_ui_text(prop, "Tool", ""); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "weight_tool", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "weighttype"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_weight_brush_items); + RNA_def_property_ui_text(prop, "Tool", "Tool for weight painting"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update"); prop = RNA_def_property(srna, "brush", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "GPencilSculptBrush"); RNA_def_property_pointer_funcs(prop, "rna_GPencilSculptSettings_brush_get", NULL, NULL, NULL); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_ui_text(prop, "Brush", ""); prop = RNA_def_property(srna, "use_select_mask", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_SELECT_MASK); RNA_def_property_ui_text(prop, "Selection Mask", "Only sculpt selected stroke points"); RNA_def_property_ui_icon(prop, ICON_VERTEXSEL, 0); // FIXME: this needs a custom icon + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "affect_position", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_POSITION); RNA_def_property_ui_text(prop, "Affect Position", "The brush affects the position of the point"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "affect_strength", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_STRENGTH); RNA_def_property_ui_text(prop, "Affect Strength", "The brush affects the color strength of the point"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "affect_thickness", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_THICKNESS); RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + prop = RNA_def_property(srna, "affect_uv", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_APPLY_UV); + RNA_def_property_ui_text(prop, "Affect UV", "The brush affects the UV rotation of the point"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "alpha"); - RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Alpha", "Alpha value for selected vertices"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update"); + prop = RNA_def_property(srna, "use_multiframe_falloff", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_FRAME_FALLOFF); + RNA_def_property_ui_text(prop, "Use Falloff", "Use falloff effect when edit in multiframe mode to compute brush effect by frame"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* custom falloff curve */ + prop = RNA_def_property(srna, "multiframe_falloff_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "cur_falloff"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Curve", + "Custom curve to control falloff of brush effect by Grease Pencil frames"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* lock axis */ prop = RNA_def_property(srna, "lockaxis", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "lock_axis"); RNA_def_property_enum_items(prop, rna_enum_gpencil_lockaxis_items); RNA_def_property_ui_text(prop, "Lock", ""); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* brush */ srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL); RNA_def_struct_sdna(srna, "GP_EditBrush_Data"); RNA_def_struct_path_func(srna, "rna_GPencilSculptBrush_path"); RNA_def_struct_ui_text(srna, "GPencil Sculpt Brush", "Stroke editing brush"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL); - RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS); - RNA_def_property_ui_range(prop, 1, 100, 10, 3); // XXX: too big + RNA_def_property_range(prop, 1, GP_MAX_BRUSH_PIXEL_RADIUS); + RNA_def_property_ui_range(prop, 1, 500, 10, 3); RNA_def_property_ui_text(prop, "Radius", "Radius of the brush in pixels"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.001, 1.0); RNA_def_property_ui_text(prop, "Strength", "Brush strength"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_USE_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); RNA_def_property_ui_text(prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "use_falloff", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_USE_FALLOFF); RNA_def_property_ui_text(prop, "Use Falloff", "Strength of brush decays with distance from cursor"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "affect_pressure", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE); RNA_def_property_ui_text(prop, "Affect Pressure", "Affect pressure values as well when smoothing strokes"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, prop_direction_items); RNA_def_property_ui_text(prop, "Direction", ""); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* Cursor Color */ + static float default_1[3] = { 1.0f, 0.6f, 0.6f }; + static float default_2[3] = { 0.6f, 0.6f, 1.0f }; + + prop = RNA_def_property(srna, "cursor_color_add", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "curcolor_add"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_array_default(prop, default_1); + RNA_def_property_ui_text(prop, "Cursor Add", "Color for the cursor for addition"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "cursor_color_sub", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_float_sdna(prop, NULL, "curcolor_sub"); + RNA_def_property_array(prop, 3); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_array_default(prop, default_2); + RNA_def_property_ui_text(prop, "Cursor Sub", "Color for the cursor for substration"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + + prop = RNA_def_property(srna, "use_cursor", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_EDITBRUSH_FLAG_ENABLE_CURSOR); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_ui_text(prop, "Enable Cursor", "Enable cursor on screen"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + } void RNA_def_sculpt_paint(BlenderRNA *brna) @@ -1166,6 +1254,7 @@ void RNA_def_sculpt_paint(BlenderRNA *brna) rna_def_paint(brna); rna_def_sculpt(brna); rna_def_uv_sculpt(brna); + rna_def_gp_paint(brna); rna_def_vertex_paint(brna); rna_def_image_paint(brna); rna_def_particle_edit(brna); diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c new file mode 100644 index 00000000000..4956333b202 --- /dev/null +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -0,0 +1,538 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/makesrna/intern/rna_shader_fx.c + * \ingroup RNA + */ + + +#include +#include +#include + +#include "DNA_shader_fx_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +#include "BLT_translation.h" + +#include "BKE_animsys.h" +#include "BKE_shader_fx.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "rna_internal.h" + +#include "WM_api.h" +#include "WM_types.h" + +const EnumPropertyItem rna_enum_object_shaderfx_type_items[] = { + {eShaderFxType_Blur, "FX_BLUR", ICON_SOLO_ON, "Blur", "Apply Gaussian Blur to object" }, + {eShaderFxType_Colorize, "FX_COLORIZE", ICON_SOLO_ON, "Colorize", "Apply different tint effects" }, + {eShaderFxType_Flip, "FX_FLIP", ICON_SOLO_ON, "Flip", "Flip image" }, + {eShaderFxType_Light, "FX_LIGHT", ICON_SOLO_ON, "Light", "Simulate ilumination" }, + {eShaderFxType_Pixel, "FX_PIXEL", ICON_SOLO_ON, "Pixelate", "Pixelate image"}, + {eShaderFxType_Rim, "FX_RIM", ICON_SOLO_ON, "Rim", "Add a rim to the image" }, + {eShaderFxType_Swirl, "FX_SWIRL", ICON_SOLO_ON, "Swirl", "Create a rotation distortion"}, + {eShaderFxType_Wave, "FX_WAVE", ICON_SOLO_ON, "Wave Distortion", "Apply sinusoidal deformation"}, + {0, NULL, 0, NULL, NULL} +}; + +const EnumPropertyItem rna_enum_shaderfx_rim_modes_items[] = { + {eShaderFxRimMode_Normal, "NORMAL", 0, "Normal", "" }, + {eShaderFxRimMode_Overlay, "OVERLAY", 0, "Overlay", "" }, + {eShaderFxRimMode_Add, "ADD", 0, "Add", "" }, + {eShaderFxRimMode_Subtract, "SUBTRACT", 0, "Subtract", "" }, + {eShaderFxRimMode_Multiply, "MULTIPLY", 0, "Multiply", "" }, + {eShaderFxRimMode_Divide, "DIVIDE", 0, "Divide", "" }, + {0, NULL, 0, NULL, NULL } +}; + +const EnumPropertyItem rna_enum_shaderfx_colorize_modes_items[] = { + {eShaderFxColorizeMode_GrayScale, "GRAYSCALE", 0, "Gray Scale", "" }, + {eShaderFxColorizeMode_Sepia, "SEPIA", 0, "Sepia", "" }, + {eShaderFxColorizeMode_BiTone, "BITONE", 0, "Bi-Tone", "" }, + {eShaderFxColorizeMode_Transparent, "TRANSPARENT", 0, "Transparent", "" }, + {eShaderFxColorizeMode_Custom, "CUSTOM", 0, "Custom", "" }, + {0, NULL, 0, NULL, NULL } +}; + +#ifdef RNA_RUNTIME + +#include "BKE_shader_fx.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +static StructRNA *rna_ShaderFx_refine(struct PointerRNA *ptr) +{ + ShaderFxData *md = (ShaderFxData *)ptr->data; + + switch ((ShaderFxType)md->type) { + case eShaderFxType_Blur: + return &RNA_ShaderFxBlur; + case eShaderFxType_Colorize: + return &RNA_ShaderFxColorize; + case eShaderFxType_Wave: + return &RNA_ShaderFxWave; + case eShaderFxType_Pixel: + return &RNA_ShaderFxPixel; + case eShaderFxType_Rim: + return &RNA_ShaderFxRim; + case eShaderFxType_Swirl: + return &RNA_ShaderFxSwirl; + case eShaderFxType_Flip: + return &RNA_ShaderFxFlip; + case eShaderFxType_Light: + return &RNA_ShaderFxLight; + /* Default */ + case eShaderFxType_None: + case NUM_SHADER_FX_TYPES: + return &RNA_ShaderFx; + } + + return &RNA_ShaderFx; +} + +static void rna_ShaderFx_name_set(PointerRNA *ptr, const char *value) +{ + ShaderFxData *gmd = ptr->data; + char oldname[sizeof(gmd->name)]; + + /* make a copy of the old name first */ + BLI_strncpy(oldname, gmd->name, sizeof(gmd->name)); + + /* copy the new name into the name slot */ + BLI_strncpy_utf8(gmd->name, value, sizeof(gmd->name)); + + /* make sure the name is truly unique */ + if (ptr->id.data) { + Object *ob = ptr->id.data; + BKE_shaderfx_unique_name(&ob->shader_fx, gmd); + } + + /* fix all the animation data which may link to this */ + BKE_animdata_fix_paths_rename_all(NULL, "shader_effects", oldname, gmd->name); +} + +static char *rna_ShaderFx_path(PointerRNA *ptr) +{ + ShaderFxData *gmd = ptr->data; + char name_esc[sizeof(gmd->name) * 2]; + + BLI_strescape(name_esc, gmd->name, sizeof(name_esc)); + return BLI_sprintfN("shader_effects[\"%s\"]", name_esc); +} + +static void rna_ShaderFx_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + DEG_id_tag_update(ptr->id.data, OB_RECALC_DATA); + WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NC_GPENCIL, ptr->id.data); +} + +static void rna_ShaderFx_dependency_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + rna_ShaderFx_update(bmain, scene, ptr); + DEG_relations_tag_update(bmain); +} + +/* Objects */ + +static void shaderfx_object_set(Object *self, Object **ob_p, int type, PointerRNA value) +{ + Object *ob = value.data; + + if (!self || ob != self) { + if (!ob || type == OB_EMPTY || ob->type == type) { + id_lib_extern((ID *)ob); + *ob_p = ob; + } + } +} + +#define RNA_FX_OBJECT_SET(_type, _prop, _obtype) \ +static void rna_##_type##ShaderFx_##_prop##_set(PointerRNA *ptr, PointerRNA value) \ +{ \ + _type##ShaderFxData *tmd = (_type##ShaderFxData *)ptr->data; \ + shaderfx_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \ +} + +RNA_FX_OBJECT_SET(Light, object, OB_EMPTY); +RNA_FX_OBJECT_SET(Swirl, object, OB_EMPTY); + +#undef RNA_FX_OBJECT_SET + +#else + +static void rna_def_shader_fx_blur(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ShaderFxBlur", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Gaussian Blur Effect", "Gaussian Blur effect"); + RNA_def_struct_sdna(srna, "BlurShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "factor", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "radius"); + RNA_def_property_range(prop, 0, INT_MAX); + RNA_def_property_ui_text(prop, "Factor", "Factor of Blur"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "samples"); + RNA_def_property_range(prop, 0, 32); + RNA_def_property_ui_range(prop, 0, 32, 2, -1); + RNA_def_property_int_default(prop, 4); + RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "coc", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "coc"); + RNA_def_property_range(prop, 0.001f, 1.0f); + RNA_def_property_float_default(prop, 0.025f); + RNA_def_property_ui_text(prop, "Precision", "Define circle of confusion for depth of field"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "use_dof_mode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_BLUR_DOF_MODE); + RNA_def_property_ui_text(prop, "Lock Focal Plane", "Blur using focal plane distance as factor to simulate depth of field effect (only in camera view)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); +} + +static void rna_def_shader_fx_colorize(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ShaderFxColorize", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Colorize Effect", "Colorize effect"); + RNA_def_struct_sdna(srna, "ColorizeShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "factor"); + RNA_def_property_range(prop, 0, 1.0); + RNA_def_property_ui_text(prop, "Factor", "Mix factor"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "low_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "low_color"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Low color", "First color used for effect"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "high_color"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Hight color", "Second color used for effect"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, rna_enum_shaderfx_colorize_modes_items); + RNA_def_property_ui_text(prop, "Mode", "Effect mode"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); +} + +static void rna_def_shader_fx_wave(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem prop_shaderfx_wave_type_items[] = { + { 0, "HORIZONTAL", 0, "Horizontal", "" }, + { 1, "VERTICAL", 0, "Vertical", "" }, + { 0, NULL, 0, NULL, NULL } + }; + + srna = RNA_def_struct(brna, "ShaderFxWave", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Wave Deformation Effect", "Wave Deformation effect"); + RNA_def_struct_sdna(srna, "WaveShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "orientation", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "orientation"); + RNA_def_property_enum_items(prop, prop_shaderfx_wave_type_items); + RNA_def_property_ui_text(prop, "Orientation", "Direction of the wave"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "amplitude"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of Wave"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "period"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_text(prop, "Period", "Period of Wave"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "phase"); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_text(prop, "Phase", "Phase Shift of Wave"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); +} + +static void rna_def_shader_fx_pixel(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ShaderFxPixel", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Pixelate Effect", "Pixelate effect"); + RNA_def_struct_sdna(srna, "PixelShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "size"); + RNA_def_property_range(prop, 1, INT_MAX); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "Size", "Pixel size"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rgba"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Color", "Color used for lines"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "use_lines", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_PIXEL_USE_LINES); + RNA_def_property_ui_text(prop, "Lines", "Display lines between pixels"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); +} + +static void rna_def_shader_fx_rim(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ShaderFxRim", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Rim Effect", "Rim effect"); + RNA_def_struct_sdna(srna, "RimShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "offset", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "offset"); + RNA_def_property_range(prop, -INT_MAX, INT_MAX); + RNA_def_property_ui_text(prop, "Offset", "Offset of the rim"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "rim_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "rim_rgb"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Rim Color", "Color used for Rim"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "mask_color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_float_sdna(prop, NULL, "mask_rgb"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Mask Color", "Color that must be keept"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, rna_enum_shaderfx_rim_modes_items); + RNA_def_property_ui_text(prop, "Mode", "Blend mode"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "blur", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "blur"); + RNA_def_property_range(prop, 0, INT_MAX); + RNA_def_property_ui_text(prop, "Blur", "Number of pixels for bluring rim (set to 0 to disable)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "samples", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "samples"); + RNA_def_property_range(prop, 0, 32); + RNA_def_property_ui_range(prop, 0, 32, 2, -1); + RNA_def_property_int_default(prop, 4); + RNA_def_property_ui_text(prop, "Samples", "Number of Blur Samples (zero, disable blur)"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); +} + +static void rna_def_shader_fx_swirl(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ShaderFxSwirl", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Swirl Effect", "Swirl effect"); + RNA_def_struct_sdna(srna, "SwirlShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "radius", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "radius"); + RNA_def_property_range(prop, 0, INT_MAX); + RNA_def_property_ui_text(prop, "Radius", "Radius to apply"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "angle"); + RNA_def_property_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360)); + RNA_def_property_ui_range(prop, DEG2RAD(-5 * 360), DEG2RAD(5 * 360), 5, 2); + RNA_def_property_ui_text(prop, "Angle", "Angle of rotation"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "transparent", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_SWIRL_MAKE_TRANSPARENT); + RNA_def_property_ui_text(prop, "Transparent", "Make image transparent outside of radius"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "Object", "Object to determine center location"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_SwirlShaderFx_object_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update"); +} + +static void rna_def_shader_fx_flip(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ShaderFxFlip", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Flip Effect", "Flip effect"); + RNA_def_struct_sdna(srna, "FlipShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "flip_horizontal", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_HORIZONTAL); + RNA_def_property_ui_text(prop, "Horizontal", "Flip image horizontally"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "flip_vertical", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FX_FLIP_VERTICAL); + RNA_def_property_ui_text(prop, "Vertical", "Flip image vertically"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); +} + +static void rna_def_shader_fx_light(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ShaderFxLight", "ShaderFx"); + RNA_def_struct_ui_text(srna, "Light Effect", "Light effect"); + RNA_def_struct_sdna(srna, "LightShaderFxData"); + RNA_def_struct_ui_icon(srna, ICON_SOLO_ON); + + prop = RNA_def_property(srna, "energy", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "energy"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 1, FLT_MAX, 1, 2); + RNA_def_property_ui_text(prop, "Energy", "Strength of light source"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "ambient", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "ambient"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, 2); + RNA_def_property_ui_text(prop, "Ambient", "Strength of ambient light source"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "Object", "Object to determine light source location"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_LightShaderFx_object_set", NULL, NULL); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update"); +} + +void RNA_def_shader_fx(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* data */ + srna = RNA_def_struct(brna, "ShaderFx", NULL); + RNA_def_struct_ui_text(srna, "ShaderFx", "Effect affecting the grease pencil object"); + RNA_def_struct_refine_func(srna, "rna_ShaderFx_refine"); + RNA_def_struct_path_func(srna, "rna_ShaderFx_path"); + RNA_def_struct_sdna(srna, "ShaderFxData"); + + /* strings */ + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShaderFx_name_set"); + RNA_def_property_ui_text(prop, "Name", "Effect name"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER | NA_RENAME, NULL); + RNA_def_struct_name_property(srna, prop); + + /* enums */ + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, rna_enum_object_shaderfx_type_items); + RNA_def_property_ui_text(prop, "Type", ""); + + /* flags */ + prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Realtime); + RNA_def_property_ui_text(prop, "Realtime", "Display effect in viewport"); + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0); + + prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Render); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_ui_text(prop, "Render", "Use effect during render"); + RNA_def_property_ui_icon(prop, ICON_SCENE, 0); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL); + + prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Editmode); + RNA_def_property_ui_text(prop, "Edit Mode", "Display effect in Edit mode"); + RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); + RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0); + + prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Expanded); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_ui_text(prop, "Expanded", "Set effect expanded in the user interface"); + RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); + + /* types */ + rna_def_shader_fx_blur(brna); + rna_def_shader_fx_colorize(brna); + rna_def_shader_fx_wave(brna); + rna_def_shader_fx_pixel(brna); + rna_def_shader_fx_rim(brna); + rna_def_shader_fx_swirl(brna); + rna_def_shader_fx_flip(brna); + rna_def_shader_fx_light(brna); +} + +#endif diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 2f009238851..56491fd70e4 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -40,6 +40,7 @@ #include "BLI_math.h" #include "DNA_action_types.h" +#include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -288,6 +289,7 @@ static const EnumPropertyItem buttons_context_items[] = { {BCONTEXT_PARTICLE, "PARTICLES", ICON_PARTICLES, "Particles", "Particle"}, {BCONTEXT_PHYSICS, "PHYSICS", ICON_PHYSICS, "Physics", "Physics"}, {BCONTEXT_WORKSPACE, "WORKSPACE", ICON_SPLITSCREEN, "Workspace", "Workspace"}, + {BCONTEXT_SHADERFX, "SHADERFX", ICON_SOLO_ON, "Effects", "Object visual effects" }, {0, NULL, 0, NULL, NULL} }; @@ -308,6 +310,14 @@ const EnumPropertyItem rna_enum_file_sort_items[] = { {0, NULL, 0, NULL, NULL} }; +static const EnumPropertyItem rna_enum_gpencil_grid_axis_items[] = { + {V3D_GP_GRID_AXIS_LOCK, "LOCK", 0, "Lock", "Use current drawing locked axis" }, + {V3D_GP_GRID_AXIS_X, "X", 0, "X", ""}, + {V3D_GP_GRID_AXIS_Y, "Y", 0, "Y", ""}, + {V3D_GP_GRID_AXIS_Z, "Z", 0, "Z", ""}, + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include "DNA_anim_types.h" @@ -475,6 +485,17 @@ static void rna_Space_view2d_sync_update(Main *UNUSED(bmain), Scene *UNUSED(scen } } +static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) +{ + /* need set all caches as dirty to recalculate onion skinning */ + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + if (ob->type == OB_GPENCIL) { + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + } + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); +} + /* Space 3D View */ static void rna_SpaceView3D_camera_update(Main *bmain, Scene *scene, PointerRNA *ptr) { @@ -1338,6 +1359,10 @@ static const EnumPropertyItem *rna_SpaceProperties_context_itemf( RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_MODIFIER); } + if (sbuts->pathflag & (1 << BCONTEXT_SHADERFX)) { + RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_SHADERFX); + } + if (sbuts->pathflag & (1 << BCONTEXT_DATA)) { RNA_enum_items_add_value(&item, &totitem, buttons_context_items, BCONTEXT_DATA); (item + totitem - 1)->icon = sbuts->dataicon; @@ -2613,7 +2638,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag2", V3D_RENDER_OVERRIDE); RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays like gizmos and outlines"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); prop = RNA_def_property(srna, "show_floor", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gridflag", V3D_SHOW_FLOOR); @@ -2831,6 +2856,86 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Weight Paint Opacity", "Opacity of the weight paint mode overlay"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + /* grease pencil paper settings */ + prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_ANNOTATION); + RNA_def_property_ui_text(prop, "Show Annotation", + "Show annotations for this view"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "use_gpencil_paper", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_PAPER); + RNA_def_property_ui_text(prop, "Use Paper", + "Cover all viewport with a full color layer to improve visibility while drawing over complex scenes"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "use_gpencil_grid", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_GRID); + RNA_def_property_ui_text(prop, "Use Grid", + "Draw a grid over grease pencil paper"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "gpencil_grid_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_scale"); + RNA_def_property_range(prop, 0.01f, FLT_MAX); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Scale", "Grid scale"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "gpencil_grid_lines", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "overlay.gpencil_grid_lines"); + RNA_def_property_range(prop, 1, INT_MAX); + RNA_def_property_int_default(prop, GP_DEFAULT_GRID_LINES); + RNA_def_property_ui_text(prop, "Subdivisions", "Number of subdivisions in each side of symmetry line"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "gpencil_grid_axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "overlay.gpencil_grid_axis"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_grid_axis_items); + RNA_def_property_ui_text(prop, "Axis", "Axis to display grid"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + prop = RNA_def_property(srna, "gpencil_grid_opacity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_grid_opacity"); + RNA_def_property_range(prop, 0.1f, 1.0f); + RNA_def_property_float_default(prop, 0.9f); + RNA_def_property_ui_text(prop, "Opacity", "Grid opacity"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + /* Paper opacity factor */ + prop = RNA_def_property(srna, "gpencil_paper_opacity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_paper_opacity"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_ui_text(prop, "Opacity", "Paper opacity"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + /* show edit lines */ + prop = RNA_def_property(srna, "use_gpencil_edit_lines", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_EDIT_LINES); + RNA_def_property_ui_text(prop, "Edit Lines", "Show edit lines when edit strokes"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_gpencil_multiedit_line_only", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_MULTIEDIT_LINES); + RNA_def_property_ui_text(prop, "Lines Only", "Show only edit lines for additional frames"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); + + /* main grease pencil onion switch */ + prop = RNA_def_property(srna, "use_gpencil_onion_skin", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_GP_SHOW_ONION_SKIN); + RNA_def_property_ui_text(prop, "Onion Skins", "Show ghosts of the frames before and after the current frame"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); + + /* vertex opacity */ + prop = RNA_def_property(srna, "vertex_opacity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "vertex_opacity"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Vertex Opacity", "Opacity for edit vertices"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update"); + } static void rna_def_space_view3d(BlenderRNA *brna) @@ -2957,12 +3062,6 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_GPENCIL); - RNA_def_property_ui_text(prop, "Show Grease Pencil", - "Show grease pencil for this view"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); - prop = RNA_def_property(srna, "show_textured_solid", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SOLID_TEX); RNA_def_property_ui_text(prop, "Textured Solid", "Display face-assigned textures in solid view"); @@ -3143,6 +3242,8 @@ static void rna_def_space_view3d(BlenderRNA *brna) {"show_object_viewport_lattice", "show_object_select_lattice"}}, {"Empty", (1 << OB_EMPTY), {"show_object_viewport_empty", "show_object_select_empty"}}, + {"Grease Pencil", (1 << OB_GPENCIL), + {"show_object_viewport_grease_pencil", "show_object_select_grease_pencil"}}, {"Camera", (1 << OB_CAMERA), {"show_object_viewport_camera", "show_object_select_camera"}}, {"Light", (1 << OB_LAMP), @@ -3382,10 +3483,10 @@ static void rna_def_space_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Draw Repeated", "Draw the image repeated outside of the main view"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); - prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_SHOW_GPENCIL); - RNA_def_property_ui_text(prop, "Show Grease Pencil", - "Show grease pencil for this view"); + RNA_def_property_ui_text(prop, "Show Annotation", + "Show annotations for this view"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); prop = RNA_def_property(srna, "draw_channels", PROP_ENUM, PROP_NONE); @@ -3434,6 +3535,7 @@ static void rna_def_space_image(BlenderRNA *brna) prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL); @@ -3587,10 +3689,10 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); - prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_GPENCIL); - RNA_def_property_ui_text(prop, "Show Grease Pencil", - "Show grease pencil for this view"); + RNA_def_property_ui_text(prop, "Show Annotation", + "Show annotations for this view"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "display_channel", PROP_INT, PROP_NONE); @@ -3629,8 +3731,9 @@ static void rna_def_space_sequencer(BlenderRNA *brna) prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); - RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space"); + RNA_def_property_ui_text(prop, "Grease Pencil", "Grease Pencil data for this Preview region"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "overlay_type", PROP_ENUM, PROP_NONE); @@ -4734,10 +4837,10 @@ static void rna_def_space_node(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Backdrop", "Use active Viewer Node output as backdrop for compositing nodes"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, "rna_SpaceNodeEditor_show_backdrop_update"); - prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_SHOW_GPENCIL); - RNA_def_property_ui_text(prop, "Show Grease Pencil", - "Show grease pencil for this view"); + RNA_def_property_ui_text(prop, "Show Annotation", + "Show annotations for this view"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE_VIEW, NULL); prop = RNA_def_property(srna, "use_auto_render", PROP_BOOLEAN, PROP_NONE); @@ -4802,8 +4905,8 @@ static void rna_def_space_clip(BlenderRNA *brna) }; static const EnumPropertyItem gpencil_source_items[] = { - {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show grease pencil data-block which belongs to movie clip"}, - {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show grease pencil data-block which belongs to active track"}, + {SC_GPENCIL_SRC_CLIP, "CLIP", 0, "Clip", "Show annotation data-block which belongs to movie clip"}, + {SC_GPENCIL_SRC_TRACK, "TRACK", 0, "Track", "Show annotation data-block which belongs to active track"}, {0, NULL, 0, NULL, NULL} }; @@ -4953,11 +5056,11 @@ static void rna_def_space_clip(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Manual Calibration", "Use manual calibration helpers"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL); - /* show grease pencil */ - prop = RNA_def_property(srna, "show_grease_pencil", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_GPENCIL); - RNA_def_property_ui_text(prop, "Show Grease Pencil", - "Show grease pencil for this view"); + /* show annotation */ + prop = RNA_def_property(srna, "show_annotation", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SC_SHOW_ANNOTATION); + RNA_def_property_ui_text(prop, "Show Annotation", + "Show annotations for this view"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL); /* show filters */ diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 5da49ac5957..4c5af755b13 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1480,6 +1480,7 @@ static void rna_def_trackingTrack(BlenderRNA *brna) prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gpd"); RNA_def_property_struct_type(prop, "GreasePencil"); + RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_GPencil_datablocks_annotations_poll"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this track"); RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index c9ce9ae7961..a5deb0a32f1 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -759,6 +759,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_string(func, "unlink", NULL, 0, "", "Operator identifier to unlink the ID block"); RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL, "", "Optionally limit the items which can be selected"); + RNA_def_boolean(func, "live_icon", false, "", "Show preview instead of fixed icon"); func = RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); @@ -831,6 +832,31 @@ void RNA_api_ui_layout(StructRNA *srna) parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "template_greasepencil_modifier", "uiTemplateGpencilModifier"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Generates the UI layout for grease pencil modifiers"); + parm = RNA_def_pointer(func, "data", "GpencilModifier", "", "Modifier data"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "template_shaderfx", "uiTemplateShaderFx"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Generates the UI layout for shader effect"); + parm = RNA_def_pointer(func, "data", "ShaderFx", "", "Shader data"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "template_greasepencil_color", "uiTemplateGpencilColorPreview"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX); + RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX); + RNA_def_float(func, "scale", 1.0f, 0.1f, 1.5f, "Scale of the image thumbnails", "", 0.5f, 1.0f); + RNA_def_enum(func, "filter", id_template_filter_items, UI_TEMPLATE_ID_FILTER_ALL, + "", "Optionally limit the items which can be selected"); + func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); RNA_def_function_ui_description(func, "Generates the UI layout for constraints"); parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 3c92b6c143b..4c3074bba4f 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -4371,6 +4371,14 @@ static void rna_def_userdef_system(BlenderRNA *brna) "Enable OpenGL multi-sampling, only for systems that support it, requires restart"); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); + /* grease pencil anti-aliasing */ + prop = RNA_def_property(srna, "gpencil_multi_sample", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "gpencil_multisamples"); + RNA_def_property_enum_items(prop, multi_sample_levels); + RNA_def_property_ui_text(prop, "Gpencil MultiSample", + "Enable Grease Pencil OpenGL multi-sampling, only for systems that support it"); + RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); + prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP); RNA_def_property_ui_text(prop, "Region Overlap", diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 5c3f510ffca..0b27cadd086 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -739,6 +739,9 @@ int RE_engine_render(Render *re, int do_all) type->render(engine, engine->depsgraph); + /* grease pencil render over previous render result */ + DRW_render_gpencil(engine, engine->depsgraph); + engine_depsgraph_free(engine); } FOREACH_VIEW_LAYER_TO_RENDER_END; diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt new file mode 100644 index 00000000000..2b33c9817c3 --- /dev/null +++ b/source/blender/shader_fx/CMakeLists.txt @@ -0,0 +1,64 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2018, Blender Foundation +# All rights reserved. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + intern + ../blenkernel + ../blenlib + ../blenfont + ../depsgraph + ../makesdna + ../makesrna + ../bmesh + ../render/extern/include + ../../../intern/elbeem/extern + ../../../intern/guardedalloc + ../../../intern/eigen +) + +set(INC_SYS + ${ZLIB_INCLUDE_DIRS} +) + +set(SRC + intern/FX_shader_util.h + + intern/FX_shader_util.c + intern/FX_shader_blur.c + intern/FX_shader_colorize.c + intern/FX_shader_flip.c + intern/FX_shader_light.c + intern/FX_shader_pixel.c + intern/FX_shader_rim.c + intern/FX_shader_swirl.c + intern/FX_shader_wave.c + + FX_shader_types.h +) + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +add_definitions(${GL_DEFINITIONS}) + +blender_add_lib(bf_shader_fx "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/shader_fx/FX_shader_types.h b/source/blender/shader_fx/FX_shader_types.h new file mode 100644 index 00000000000..b8d8f04e07f --- /dev/null +++ b/source/blender/shader_fx/FX_shader_types.h @@ -0,0 +1,47 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ben Batt + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file FX_shader_types.h + * \ingroup shader_fx + */ + +#ifndef __FX_SHADER_TYPES_H__ +#define __FX_SHADER_TYPES_H__ + +#include "BKE_shader_fx.h" + +/* ****************** Type structures for all effects ****************** */ + +extern ShaderFxTypeInfo shaderfx_Type_None; +extern ShaderFxTypeInfo shaderfx_Type_Blur; +extern ShaderFxTypeInfo shaderfx_Type_Colorize; +extern ShaderFxTypeInfo shaderfx_Type_Flip; +extern ShaderFxTypeInfo shaderfx_Type_Light; +extern ShaderFxTypeInfo shaderfx_Type_Pixel; +extern ShaderFxTypeInfo shaderfx_Type_Rim; +extern ShaderFxTypeInfo shaderfx_Type_Swirl; +extern ShaderFxTypeInfo shaderfx_Type_Wave; + +/* FX_shaderfx_util.c */ +void shaderfx_type_init(ShaderFxTypeInfo *types[]); + +#endif /* __FX_SHADER_TYPES_H__ */ diff --git a/source/blender/shader_fx/intern/FX_shader_blur.c b/source/blender/shader_fx/intern/FX_shader_blur.c new file mode 100644 index 00000000000..128ebba8875 --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_blur.c @@ -0,0 +1,66 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_blur.c + * \ingroup shader_fx + */ + +#include + +#include "BLI_utildefines.h" + +#include "FX_shader_types.h" + +static void initData(ShaderFxData *fx) +{ + BlurShaderFxData *gpfx = (BlurShaderFxData *)fx; + ARRAY_SET_ITEMS(gpfx->radius, 1, 1); + gpfx->samples = 4; + gpfx->coc = 0.025f; +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +ShaderFxTypeInfo shaderfx_Type_Blur = { + /* name */ "Blur", + /* structName */ "BlurShaderFxData", + /* structSize */ sizeof(BlurShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ eShaderFxTypeFlag_Single, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/shader_fx/intern/FX_shader_colorize.c b/source/blender/shader_fx/intern/FX_shader_colorize.c new file mode 100644 index 00000000000..edf276b842c --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_colorize.c @@ -0,0 +1,69 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_colorize.c + * \ingroup shader_fx + */ + +#include + +#include "DNA_shader_fx_types.h" + +#include "BLI_utildefines.h" + +#include "FX_shader_types.h" + +static void initData(ShaderFxData *fx) +{ + ColorizeShaderFxData *gpfx = (ColorizeShaderFxData *)fx; + ARRAY_SET_ITEMS(gpfx->low_color, 0.0f, 0.0f, 0.0f, 1.0f); + ARRAY_SET_ITEMS(gpfx->high_color, 1.0f, 1.0f, 1.0f, 1.0f); + gpfx->mode = eShaderFxColorizeMode_GrayScale; + gpfx->factor = 0.5f; +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +ShaderFxTypeInfo shaderfx_Type_Colorize = { + /* name */ "Colorize", + /* structName */ "ColorizeShaderFxData", + /* structSize */ sizeof(ColorizeShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ 0, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c new file mode 100644 index 00000000000..404e2f8160e --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_flip.c @@ -0,0 +1,69 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_flip.c + * \ingroup shader_fx + */ + +#include + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" + +#include "BLI_math_base.h" +#include "BLI_utildefines.h" + +#include "FX_shader_types.h" + +static void initData(ShaderFxData *fx) +{ + FlipShaderFxData *gpfx = (FlipShaderFxData *)fx; + gpfx->flag |= FX_FLIP_HORIZONTAL; +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +ShaderFxTypeInfo shaderfx_Type_Flip = { + /* name */ "Flip", + /* structName */ "FlipShaderFxData", + /* structSize */ sizeof(FlipShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ eShaderFxTypeFlag_Single, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/shader_fx/intern/FX_shader_light.c b/source/blender/shader_fx/intern/FX_shader_light.c new file mode 100644 index 00000000000..9a17ea8ae5f --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_light.c @@ -0,0 +1,104 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_light.c + * \ingroup shader_fx + */ + +#include + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" + +#include "BLI_math_base.h" +#include "BLI_utildefines.h" + +#include "BKE_library_query.h" +#include "BKE_modifier.h" +#include "BKE_shader_fx.h" + +#include "FX_shader_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +static void initData(ShaderFxData *fx) +{ + LightShaderFxData *gpfx = (LightShaderFxData *)fx; + gpfx->energy = 10.0f; + gpfx->ambient = 5.0f; + gpfx->object = NULL; +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +static void updateDepsgraph(ShaderFxData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + LightShaderFxData *fxd = (LightShaderFxData *)md; + if (fxd->object != NULL) { + DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_GEOMETRY, "Light ShaderFx"); + DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx"); + } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Light ShaderFx"); +} + +static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams)) +{ + LightShaderFxData *fxd = (LightShaderFxData *)fx; + + return !fxd->object; +} + +static void foreachObjectLink( + ShaderFxData *fx, Object *ob, + ShaderFxObjectWalkFunc walk, void *userData) +{ + LightShaderFxData *fxd = (LightShaderFxData *)fx; + + walk(userData, ob, &fxd->object, IDWALK_CB_NOP); +} + +ShaderFxTypeInfo shaderfx_Type_Light = { + /* name */ "Light", + /* structName */ "LightShaderFxData", + /* structSize */ sizeof(LightShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ 0, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/shader_fx/intern/FX_shader_pixel.c b/source/blender/shader_fx/intern/FX_shader_pixel.c new file mode 100644 index 00000000000..a3ffd3a9b0d --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_pixel.c @@ -0,0 +1,66 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_pixel.c + * \ingroup shader_fx + */ + +#include + +#include "BLI_utildefines.h" + +#include "FX_shader_types.h" + +static void initData(ShaderFxData *fx) +{ + PixelShaderFxData *gpfx = (PixelShaderFxData *)fx; + ARRAY_SET_ITEMS(gpfx->size, 5, 5); + ARRAY_SET_ITEMS(gpfx->rgba, 0.0f, 0.0f, 0.0f, 0.9f); + gpfx->flag |= FX_PIXEL_USE_LINES; +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +ShaderFxTypeInfo shaderfx_Type_Pixel = { + /* name */ "Pixelate", + /* structName */ "PixelShaderFxData", + /* structSize */ sizeof(PixelShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ eShaderFxTypeFlag_Single, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/shader_fx/intern/FX_shader_rim.c b/source/blender/shader_fx/intern/FX_shader_rim.c new file mode 100644 index 00000000000..611e6f91bf7 --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_rim.c @@ -0,0 +1,70 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_rim.c + * \ingroup shader_fx + */ + +#include + +#include "DNA_shader_fx_types.h" + +#include "BLI_utildefines.h" + +#include "FX_shader_types.h" + +static void initData(ShaderFxData *fx) +{ + RimShaderFxData *gpfx = (RimShaderFxData *)fx; + ARRAY_SET_ITEMS(gpfx->offset, 50, -100); + ARRAY_SET_ITEMS(gpfx->rim_rgb, 1.0f, 1.0f, 0.5f, 0.9f); + ARRAY_SET_ITEMS(gpfx->mask_rgb, 0.0f, 0.0f, 0.0f, 1.0f); + gpfx->mode = eShaderFxRimMode_Multiply; + ARRAY_SET_ITEMS(gpfx->blur, 0, 0); +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +ShaderFxTypeInfo shaderfx_Type_Rim = { + /* name */ "Rim", + /* structName */ "RimShaderFxData", + /* structSize */ sizeof(RimShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ 0, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/shader_fx/intern/FX_shader_swirl.c b/source/blender/shader_fx/intern/FX_shader_swirl.c new file mode 100644 index 00000000000..9667f466eec --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_swirl.c @@ -0,0 +1,103 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_swirl.c + * \ingroup shader_fx + */ + +#include + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" + +#include "BLI_math_base.h" +#include "BLI_utildefines.h" + +#include "BKE_library_query.h" +#include "BKE_modifier.h" +#include "BKE_shader_fx.h" + +#include "FX_shader_types.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +static void initData(ShaderFxData *md) +{ + SwirlShaderFxData *gpmd = (SwirlShaderFxData *)md; + gpmd->radius = 100; + gpmd->angle = M_PI_2; +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +static void updateDepsgraph(ShaderFxData *fx, const ModifierUpdateDepsgraphContext *ctx) +{ + SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; + if (fxd->object != NULL) { + DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_GEOMETRY, "Swirl ShaderFx"); + DEG_add_object_relation(ctx->node, fxd->object, DEG_OB_COMP_TRANSFORM, "Swirl ShaderFx"); + } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Swirl ShaderFx"); +} + +static bool isDisabled(ShaderFxData *fx, int UNUSED(userRenderParams)) +{ + SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; + + return !fxd->object; +} + +static void foreachObjectLink( + ShaderFxData *fx, Object *ob, + ShaderFxObjectWalkFunc walk, void *userData) +{ + SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; + + walk(userData, ob, &fxd->object, IDWALK_CB_NOP); +} + +ShaderFxTypeInfo shaderfx_Type_Swirl = { + /* name */ "Swirl", + /* structName */ "SwirlShaderFxData", + /* structSize */ sizeof(SwirlShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ 0, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/shader_fx/intern/FX_shader_util.c b/source/blender/shader_fx/intern/FX_shader_util.c new file mode 100644 index 00000000000..c55b9304503 --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_util.c @@ -0,0 +1,56 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/shader_fx/intern/FX_shader_util.c + * \ingroup shader_fx + */ + + +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_shader_fx.h" + +#include "FX_shader_types.h" +#include "FX_shader_util.h" + +void shaderfx_type_init(ShaderFxTypeInfo *types[]) +{ +#define INIT_FX_TYPE(typeName) (types[eShaderFxType_##typeName] = &shaderfx_Type_##typeName) + INIT_FX_TYPE(Blur); + INIT_FX_TYPE(Colorize); + INIT_FX_TYPE(Flip); + INIT_FX_TYPE(Light); + INIT_FX_TYPE(Pixel); + INIT_FX_TYPE(Rim); + INIT_FX_TYPE(Swirl); + INIT_FX_TYPE(Wave); +#undef INIT_FX_TYPE +} + diff --git a/source/blender/shader_fx/intern/FX_shader_util.h b/source/blender/shader_fx/intern/FX_shader_util.h new file mode 100644 index 00000000000..e2fdcd6fb4c --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_util.h @@ -0,0 +1,36 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/shader_fx/intern/FX_shader_util.h + * \ingroup shader_fx + */ + + +#ifndef __FX_SHADER_UTIL_H__ +#define __FX_SHADER_UTIL_H__ + +#endif /* __FX_SHADER_UTIL_H__ */ diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c new file mode 100644 index 00000000000..ea4563a00e1 --- /dev/null +++ b/source/blender/shader_fx/intern/FX_shader_wave.c @@ -0,0 +1,71 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/shader_fx/intern/FX_shader_wave.c + * \ingroup shader_fx + */ + +#include + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" + +#include "BLI_utildefines.h" + +#include "FX_shader_types.h" + +static void initData(ShaderFxData *fx) +{ + WaveShaderFxData *gpfx = (WaveShaderFxData *)fx; + gpfx->amplitude = 10.0f; + gpfx->period = 20.0f; + gpfx->phase = 0.0f; + gpfx->orientation = 1; +} + +static void copyData(const ShaderFxData *md, ShaderFxData *target) +{ + BKE_shaderfx_copyData_generic(md, target); +} + +ShaderFxTypeInfo shaderfx_Type_Wave = { + /* name */ "Wave Distorsion", + /* structName */ "WaveShaderFxData", + /* structSize */ sizeof(WaveShaderFxData), + /* type */ eShaderFxType_GpencilType, + /* flags */ eShaderFxTypeFlag_Single, + + /* copyData */ copyData, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, +}; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index df869ba6b68..76a1482ac7c 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -440,7 +440,7 @@ static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr switch (GS(((ID *)ptr->id.data)->name)) { case ID_SCE: { - CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C)); + CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_Brush, ptr, CTX_data_active_gpencil_brush(C)); CTX_TEST_PTR_ID(C, "scene", ptr->id.data); break; } diff --git a/source/creator/creator.c b/source/creator/creator.c index 18396149342..914211afd56 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -63,7 +63,9 @@ #include "BKE_global.h" #include "BKE_material.h" #include "BKE_modifier.h" +#include "BKE_gpencil_modifier.h" #include "BKE_node.h" +#include "BKE_shader_fx.h" #include "BKE_sound.h" #include "BKE_image.h" #include "BKE_particle.h" @@ -371,6 +373,8 @@ int main( BKE_cachefiles_init(); BKE_images_init(); BKE_modifier_init(); + BKE_gpencil_modifier_init(); + BKE_shaderfx_init(); DEG_register_node_types(); BKE_brush_system_init(); -- cgit v1.2.3 From f6300030e01609a8f80645fd8c6603aa75da80d5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 19:07:56 +1000 Subject: Cleanup: trailing space --- .../gpencil/shaders/fx/gpencil_fx_blur_frag.glsl | 6 +++--- .../shaders/fx/gpencil_fx_colorize_frag.glsl | 8 ++++---- .../gpencil/shaders/fx/gpencil_fx_flip_frag.glsl | 2 +- .../gpencil/shaders/fx/gpencil_fx_light_frag.glsl | 22 +++++++++++----------- .../gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl | 6 +++--- .../shaders/fx/gpencil_fx_rim_prepare_frag.glsl | 6 +++--- .../shaders/fx/gpencil_fx_rim_resolve_frag.glsl | 18 +++++++++--------- .../gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl | 10 +++++----- source/blender/editors/gpencil/gpencil_edit.c | 4 ++-- source/blender/editors/gpencil/gpencil_paint.c | 2 +- .../blender/editors/interface/interface_layout.c | 2 +- source/blender/editors/interface/resources.c | 2 +- source/blender/makesrna/intern/rna_shader_fx.c | 4 ++-- 13 files changed, 46 insertions(+), 46 deletions(-) (limited to 'source') diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl index 1d66ba3d4d4..1bf1d025430 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl @@ -21,10 +21,10 @@ void main() ivec2 uv = ivec2(gl_FragCoord.xy); vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); - + float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) : (noffset[0] / defaultpixsize); float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) : (noffset[1] / defaultpixsize); - + /* apply blurring, using a 9-tap filter with predefined gaussian weights */ /* depth */ float outdepth = 0; @@ -42,7 +42,7 @@ void main() gl_FragDepth = outdepth; - /* color */ + /* color */ vec4 outcolor = vec4(0.0); outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416; outcolor += texelFetch(strokeColor, ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy), 0) * 0.118318; diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl index 7d0ce4a804e..33b249ac09b 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl @@ -28,12 +28,12 @@ void main() vec4 src_pixel= texelFetch(strokeColor, uv.xy, 0); float luminance = get_luminance(src_pixel); vec4 outcolor; - - /* is transparent */ + + /* is transparent */ if (src_pixel.a == 0.0f) { discard; } - + switch(mode) { case MODE_GRAYSCALE: { @@ -78,7 +78,7 @@ void main() { outcolor = src_pixel; } - + } gl_FragDepth = stroke_depth; diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl index 94fb3405c79..43589461cd1 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl @@ -27,7 +27,7 @@ void main() if (mode[1] > 0) { uv.y = wsize.y - uv.y; } - + ivec2 iuv = ivec2(uv.x, uv.y); stroke_depth = texelFetch(strokeDepth, iuv, 0).r; outcolor = texelFetch(strokeColor, iuv, 0); diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl index f3026c32fc8..6dcd0499baf 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl @@ -23,11 +23,11 @@ vec2 toScreenSpace(vec4 vertex) { /* need to calculate ndc because this is not done by vertex shader */ vec3 ndc = vec3(vertex).xyz / vertex.w; - + vec2 sc; sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x; sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y; - + return sc; } @@ -35,20 +35,20 @@ void main() { float stroke_depth; vec4 objcolor; - - vec4 light_loc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); + + vec4 light_loc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); vec2 light2d = toScreenSpace(light_loc); /* calc pixel scale */ float pxscale = (ProjectionMatrix[3][3] == 0.0) ? (10.0 / (light_loc.z * defaultpixsize)) : (10.0 / defaultpixsize); pxscale = max(pxscale, 0.000001); - /* the height over plane is received in the w component of the loc + /* the height over plane is received in the w component of the loc * and needs a factor to adapt to pixels */ float peak = height * 10.0 * pxscale; - vec3 light3d = vec3(light2d.x, light2d.y, peak); - + vec3 light3d = vec3(light2d.x, light2d.y, peak); + vec2 uv = vec2(gl_FragCoord.xy); vec3 frag_loc = vec3(uv.x, uv.y, 0); vec3 norm = vec3(0, 0, 1.0); /* always z-up */ @@ -56,15 +56,15 @@ void main() ivec2 iuv = ivec2(uv.x, uv.y); stroke_depth = texelFetch(strokeDepth, iuv, 0).r; objcolor = texelFetch(strokeColor, iuv, 0); - + /* diffuse light */ vec3 lightdir = normalize(light3d - frag_loc); float diff = max(dot(norm, lightdir), 0.0); float dist = length(light3d - frag_loc) / pxscale; - float factor = diff * ((energy * 100.0) / (dist * dist)); - + float factor = diff * ((energy * 100.0) / (dist * dist)); + vec3 result = factor * max(ambient, 0.1) * vec3(objcolor); - + gl_FragDepth = stroke_depth; FragColor = vec4(result.r, result.g, result.b, objcolor.a); } diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl index d1a57a9a1b6..0b25dbbd012 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl @@ -23,15 +23,15 @@ void main() { vec2 uv = vec2(gl_FragCoord.xy); vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); - + float dx = (ProjectionMatrix[3][3] == 0.0) ? (nsize[0] / (nloc.z * defaultpixsize)) : (nsize[0] / defaultpixsize); float dy = (ProjectionMatrix[3][3] == 0.0) ? (nsize[1] / (nloc.z * defaultpixsize)) : (nsize[1] / defaultpixsize); dx = max(abs(dx), 3.0); dy = max(abs(dy), 3.0); - + vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy)); - + float stroke_depth = texelFetch(strokeDepth, ivec2(coord), 0).r; vec4 outcolor = texelFetch(strokeColor, ivec2(coord), 0); diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl index fe35d3832e1..6ea4faf11fd 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl @@ -26,7 +26,7 @@ void main() { vec2 uv = vec2(gl_FragCoord.xy); vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); - + float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) : (noffset[0] / defaultpixsize); float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) : (noffset[1] / defaultpixsize); @@ -35,7 +35,7 @@ void main() vec4 offset_pixel= texelFetch(strokeColor, ivec2(uv.x - dx, uv.y - dy), 0); vec4 outcolor; - /* is transparent */ + /* is transparent */ if (src_pixel.a == 0.0f) { discard; } @@ -56,7 +56,7 @@ void main() } else { outcolor = vec4(rim_color, 1.0); - } + } } gl_FragDepth = stroke_depth; diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl index 5e5edbd8325..20d6b8a91f8 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl @@ -19,14 +19,14 @@ out vec4 FragColor; float overlay_color(float a, float b) { - float rtn; + float rtn; if (a < 0.5) { rtn = 2.0 * a * b; } else { rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b); } - + return rtn; } @@ -53,16 +53,16 @@ vec4 get_blend_color(int mode, vec4 src_color, vec4 mix_color) else if (mode == MODE_DIVIDE) { outcolor = src_color / mix_color; } - else { + else { outcolor = mix_color; } - + /* use always the alpha of source color */ - + outcolor.a = src_color.a; /* use alpha to calculate the weight of the mixed color */ outcolor = mix(src_color, outcolor, mix_color.a); - + return outcolor; } @@ -75,8 +75,8 @@ void main() vec4 rim_pixel= texelFetch(strokeRim, uv.xy, 0); vec4 outcolor = src_pixel; - - /* is transparent */ + + /* is transparent */ if (src_pixel.a == 0.0f) { discard; } @@ -92,7 +92,7 @@ void main() outcolor = get_blend_color(mode, src_pixel, rim_pixel); } } - + gl_FragDepth = stroke_depth; FragColor = outcolor; } diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl index 6ce64350b3d..78aacafdcb7 100644 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl +++ b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl @@ -23,11 +23,11 @@ vec2 toScreenSpace(vec4 vertex) { /* need to calculate ndc because this is not done by vertex shader */ vec3 ndc = vec3(vertex).xyz / vertex.w; - + vec2 sc; sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x; sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y; - + return sc; } @@ -37,15 +37,15 @@ void main() vec2 uv = vec2(gl_FragCoord.xy); float stroke_depth; vec4 outcolor; - - vec4 center3d = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); + + vec4 center3d = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); vec2 center = toScreenSpace(center3d); vec2 tc = uv - center; float dist = length(tc); float pxradius = (ProjectionMatrix[3][3] == 0.0) ? (radius / (loc.z * defaultpixsize)) : (radius / defaultpixsize); pxradius = max(pxradius, 1); - + if (dist <= pxradius) { float percent = (pxradius - dist) / pxradius; float theta = percent * percent * angle * 8.0; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 4264645b52e..4a603e97615 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1785,13 +1785,13 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke /* Copy over the relevant point data */ new_stroke->points = MEM_callocN(sizeof(bGPDspoint) * new_stroke->totpoints, "gp delete stroke fragment"); memcpy(new_stroke->points, gps->points + island->start_idx, sizeof(bGPDspoint) * new_stroke->totpoints); - + /* Copy over vertex weight data (if available) */ if (new_stroke->dvert != NULL) { /* Copy over the relevant vertex-weight points */ new_stroke->dvert = MEM_callocN(sizeof(MDeformVert) * new_stroke->totpoints, "gp delete stroke fragment weight"); memcpy(new_stroke->dvert, gps->dvert + island->start_idx, sizeof(MDeformVert) * new_stroke->totpoints); - + /* Copy weights */ int e = island->start_idx; for (int i = 0; i < new_stroke->totpoints; i++) { diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 995ab91ff8b..fd5b2803650 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1690,7 +1690,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) break; } - + /* unsupported views */ default: { diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 89e1a8caec8..f143d418fe3 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1245,7 +1245,7 @@ void uiItemsFullEnumO( if (ui_layout_is_radial(layout)) { /* XXX: While "_all()" guarantees spatial stability, it's bad when an enum has > 8 items total, - * but only a small subset will ever be shown at once (e.g. Mode Switch menu, after the + * but only a small subset will ever be shown at once (e.g. Mode Switch menu, after the * introduction of GP editing modes) */ #if 0 diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index e6422c423b9..72023ebf2ae 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1573,7 +1573,7 @@ void init_userdef_do_versions(Main *bmain) for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) { memcpy(btheme, &U_theme_default, sizeof(*btheme)); } - + /* Annotations - new layer color * Replace anything that used to be set if it looks like was left * on the old default (i.e. black), which most users used diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index 4956333b202..950aef9a8dd 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -443,7 +443,7 @@ static void rna_def_shader_fx_light(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; - + srna = RNA_def_struct(brna, "ShaderFxLight", "ShaderFx"); RNA_def_struct_ui_text(srna, "Light Effect", "Light effect"); RNA_def_struct_sdna(srna, "LightShaderFxData"); @@ -517,7 +517,7 @@ void RNA_def_shader_fx(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Edit Mode", "Display effect in Edit mode"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0); - + prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", eShaderFxMode_Expanded); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); -- cgit v1.2.3 From a823f58dfd039291fe14bdf7d281ecaa0311292e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 31 Jul 2018 11:17:51 +0200 Subject: Subsurf: Disable oprtion for now Committed by accident, is too early for this yet. --- source/blender/modifiers/intern/MOD_subsurf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 7c605dd4f78..08dc7c92693 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -57,7 +57,7 @@ #include "intern/CCGSubSurf.h" -#define USE_OPENSUBDIV +// #define USE_OPENSUBDIV static void initData(ModifierData *md) { -- cgit v1.2.3 From ad5b611953b6c2b510982e25218552a12d70437c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 19:21:04 +1000 Subject: Cleanup: style --- source/blender/blenkernel/intern/rigidbody.c | 6 ++-- source/blender/blenkernel/intern/subdiv_mesh.c | 36 +++++++++++++--------- source/blender/blenloader/intern/versioning_280.c | 4 ++- .../editors/interface/interface_templates.c | 14 --------- source/blender/gpu/intern/gpu_context.cpp | 2 +- source/blender/windowmanager/intern/wm_window.c | 2 +- 6 files changed, 30 insertions(+), 34 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index e6b8312734f..c542c3f927d 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -717,9 +717,9 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool /* --------------------- */ static void rigidbody_constraint_init_spring( - RigidBodyCon *rbc, void (*set_spring)(rbConstraint*,int,int), - void (*set_stiffness)(rbConstraint*,int,float), void (*set_damping)(rbConstraint*,int,float) -) { + RigidBodyCon *rbc, void (*set_spring)(rbConstraint *, int, int), + void (*set_stiffness)(rbConstraint *, int, float), void (*set_damping)(rbConstraint *, int, float)) +{ set_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X); set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x); set_damping(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x); diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 40c95964fb3..895d527ea5c 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -764,7 +764,8 @@ static void subdiv_evaluate_corner_vertices_regular( const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner]; if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, - coarse_loop->v)) { + coarse_loop->v)) + { continue; } const MVert *coarse_vert = &coarse_mvert[coarse_loop->v]; @@ -798,7 +799,8 @@ static void subdiv_evaluate_corner_vertices_special( const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner]; if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_vertices_used_map, - coarse_loop->v)) { + coarse_loop->v)) + { continue; } const MVert *coarse_vert = &coarse_mvert[coarse_loop->v]; @@ -847,7 +849,8 @@ static void subdiv_evaluate_edge_vertices_regular( const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner]; if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, - coarse_loop->e)) { + coarse_loop->e)) + { continue; } vertex_interpolation_from_ptex(ctx, @@ -860,8 +863,8 @@ static void subdiv_evaluate_edge_vertices_regular( ctx->vertices_edge_offset + coarse_loop->e * num_subdiv_vertices_per_coarse_edge]; for (int vertex_index = 0; - vertex_index < num_subdiv_vertices_per_coarse_edge; - vertex_index++, subdiv_vert++) + vertex_index < num_subdiv_vertices_per_coarse_edge; + vertex_index++, subdiv_vert++) { float fac = (vertex_index + 1) * inv_resolution_1; if (flip) { @@ -918,7 +921,8 @@ static void subdiv_evaluate_edge_vertices_special( const MLoop *coarse_loop = &coarse_mloop[coarse_poly->loopstart + corner]; if (BLI_BITMAP_TEST_AND_SET_ATOMIC(ctx->coarse_edges_used_map, - coarse_loop->e)) { + coarse_loop->e)) + { continue; } vertex_interpolation_from_ptex(ctx, @@ -936,8 +940,8 @@ static void subdiv_evaluate_edge_vertices_special( veretx_delta = -1; } for (int vertex_index = 1; - vertex_index < num_vertices_per_ptex_edge; - vertex_index++, subdiv_vert += veretx_delta) + vertex_index < num_vertices_per_ptex_edge; + vertex_index++, subdiv_vert += veretx_delta) { float u = vertex_index * inv_ptex_resolution_1; subdiv_vertex_data_interpolate(ctx, @@ -953,8 +957,8 @@ static void subdiv_evaluate_edge_vertices_special( const int next_ptex_face_index = ptex_face_start_index + (corner + 1) % coarse_poly->totloop; for (int vertex_index = 1; - vertex_index < num_vertices_per_ptex_edge - 1; - vertex_index++, subdiv_vert += veretx_delta) + vertex_index < num_vertices_per_ptex_edge - 1; + vertex_index++, subdiv_vert += veretx_delta) { float v = 1.0f - vertex_index * inv_ptex_resolution_1; subdiv_vertex_data_interpolate(ctx, @@ -1416,7 +1420,8 @@ static void subdiv_create_edges_all_patches_special( subdiv_copy_edge_data(ctx, subdiv_edge, NULL); if (flip) { subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3); - } else { + } + else { subdiv_edge->v1 = start_edge_vertex + i; } subdiv_edge->v2 = side_start_index + i; @@ -1433,7 +1438,8 @@ static void subdiv_create_edges_all_patches_special( subdiv_copy_edge_data(ctx, subdiv_edge, NULL); if (flip) { subdiv_edge->v1 = start_edge_vertex + (resolution - i - 3); - } else { + } + else { subdiv_edge->v1 = start_edge_vertex + i; } subdiv_edge->v2 = side_start_index + @@ -1762,7 +1768,8 @@ static void subdiv_create_loops_regular(SubdivMeshContext *ctx, e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge + num_subdiv_edges_per_coarse_edge - i - 1; - } else { + } + else { e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge + i; @@ -2040,7 +2047,8 @@ static void subdiv_create_loops_special(SubdivMeshContext *ctx, e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge + num_subdiv_edges_per_coarse_edge - i - 1; - } else { + } + else { e0 = ctx->edge_boundary_offset + coarse_loop->e * num_subdiv_edges_per_coarse_edge + i; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 7339f1977ff..93577315b1c 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1645,7 +1645,9 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { if (sl->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)sl; - v3d->shading.background_type = (v3d->flag3 & V3D_SHOW_WORLD)? V3D_SHADING_BACKGROUND_WORLD: V3D_SHADING_BACKGROUND_THEME; + v3d->shading.background_type = ( + (v3d->flag3 & V3D_SHOW_WORLD) ? + V3D_SHADING_BACKGROUND_WORLD : V3D_SHADING_BACKGROUND_THEME); copy_v3_fl(v3d->shading.background_color, 0.05f); } } diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 513bfd32191..07d259dd047 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -4296,20 +4296,6 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs( PointerRNA ptr; struct uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = flag}; - - -#if 0 -static bool template_operator_redo_property_buts_poll(PointerRNA *UNUSED(ptr), PropertyRNA *prop) -{ -} -#endif - - - - - - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); uiLayoutSetPropSep(layout, true); diff --git a/source/blender/gpu/intern/gpu_context.cpp b/source/blender/gpu/intern/gpu_context.cpp index 3f2ce958332..8d8f4d12b04 100644 --- a/source/blender/gpu/intern/gpu_context.cpp +++ b/source/blender/gpu/intern/gpu_context.cpp @@ -23,7 +23,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/gpu/intern/gpu_vertex_array_id.cpp +/** \file blender/gpu/intern/gpu_context.cpp * \ingroup gpu * * Manage GL vertex array IDs in a thread-safe way diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index dd4013efdf2..3083607b8a9 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -2169,7 +2169,7 @@ ViewLayer *WM_window_get_active_view_layer(const wmWindow *win) view_layer = BKE_view_layer_default_view(scene); if (view_layer) { - WM_window_set_active_view_layer((wmWindow*)win, view_layer); + WM_window_set_active_view_layer((wmWindow *)win, view_layer); } return view_layer; -- cgit v1.2.3 From 75f1fb6d86225c9b764f3909e83accc07685b009 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 31 Jul 2018 11:32:38 +0200 Subject: Depsgraph: Fix crash on undo of new bone added Pose is not brought up to date for until exit of edit mode, so can not use. --- source/blender/blenkernel/intern/armature_update.c | 3 ++- source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 26fbd22c67e..03d370f6e7c 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -688,7 +688,8 @@ void BKE_pose_bone_done(struct Depsgraph *depsgraph, invert_m4_m4(imat, pchan->bone->arm_mat); mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat); } - if (DEG_is_active(depsgraph)) { + bArmature *arm = (bArmature *)ob->data; + if (DEG_is_active(depsgraph) && arm->edbo == NULL) { bPoseChannel *pchan_orig = pchan->orig_pchan; copy_m4_m4(pchan_orig->pose_mat, pchan->pose_mat); copy_m4_m4(pchan_orig->chan_mat, pchan->chan_mat); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index ee814e11d40..22c1167de2a 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -548,9 +548,13 @@ void update_special_pointers(const Depsgraph *depsgraph, object_cow->runtime.mesh_orig = (Mesh *)object_cow->data; } if (object_cow->type == OB_ARMATURE) { - BKE_pose_remap_bone_pointers((bArmature *)object_cow->data, - object_cow->pose); - update_pose_orig_pointers(object_orig->pose, object_cow->pose); + const bArmature *armature_orig = (bArmature *)object_orig->data; + bArmature *armature_cow = (bArmature *)object_cow->data; + BKE_pose_remap_bone_pointers(armature_cow, object_cow->pose); + if (armature_orig->edbo == NULL) { + update_pose_orig_pointers(object_orig->pose, + object_cow->pose); + } } update_particle_system_orig_pointers(object_orig, object_cow); break; -- cgit v1.2.3 From 1fd27c2332a2d74d16cc8f339dd68fe1d06874a7 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 31 Jul 2018 11:38:10 +0200 Subject: Respect ID user count when creating pose on object copy This solves wrong user counter of custom shape when duplicating bone few times and then undoing all the duplications. --- source/blender/blenkernel/BKE_armature.h | 2 +- source/blender/blenkernel/intern/armature.c | 6 +++--- source/blender/blenkernel/intern/library.c | 2 +- source/blender/blenkernel/intern/object.c | 10 ++++++---- source/blender/blenkernel/intern/scene.c | 2 +- .../blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc | 2 +- source/blender/editors/armature/armature_utils.c | 2 +- source/blender/editors/object/object_add.c | 2 +- source/blender/editors/object/object_relations.c | 2 +- source/blender/makesrna/intern/rna_object.c | 2 +- 10 files changed, 17 insertions(+), 15 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 21d880cf2a7..9e100eb9111 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -100,7 +100,7 @@ void BKE_armature_where_is(struct bArmature *arm); void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); void BKE_pose_clear_pointers(struct bPose *pose); void BKE_pose_remap_bone_pointers(struct bArmature *armature, struct bPose *pose); -void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm); +void BKE_pose_rebuild(struct Main *bmain, struct Object *ob, struct bArmature *arm, const bool do_id_user); void BKE_pose_where_is(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 6be4574a62e..cea81a82f4b 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1960,7 +1960,7 @@ void BKE_pose_remap_bone_pointers(bArmature *armature, bPose *pose) * * \param bmain May be NULL, only used to tag depsgraph as being dirty... */ -void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm) +void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm, const bool do_id_user) { Bone *bone; bPose *pose; @@ -1989,7 +1989,7 @@ void BKE_pose_rebuild(Main *bmain, Object *ob, bArmature *arm) for (pchan = pose->chanbase.first; pchan; pchan = next) { next = pchan->next; if (pchan->bone == NULL) { - BKE_pose_channel_free(pchan); + BKE_pose_channel_free_ex(pchan, do_id_user); BKE_pose_channels_hash_free(pose); BLI_freelinkN(&pose->chanbase, pchan); } @@ -2291,7 +2291,7 @@ void BKE_pose_where_is(struct Depsgraph *depsgraph, Scene *scene, Object *ob) return; if ((ob->pose == NULL) || (ob->pose->flag & POSE_RECALC)) { /* WARNING! passing NULL bmain here means we won't tag depsgraph's as dirty - hopefully this is OK. */ - BKE_pose_rebuild(NULL, ob, arm); + BKE_pose_rebuild(NULL, ob, arm, true); } ctime = BKE_scene_frame_get(scene); /* not accurate... */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 1d70d9db1e9..8922cd75618 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -2465,7 +2465,7 @@ void BKE_library_make_local( * Try "make all local" in 04_01_H.lighting.blend from Agent327 without this, e.g. */ for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->data != NULL && ob->type == OB_ARMATURE && ob->pose != NULL && ob->pose->flag & POSE_RECALC) { - BKE_pose_rebuild(bmain, ob, ob->data); + BKE_pose_rebuild(bmain, ob, ob->data, true); } } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index c88de006eba..9c7ce7698f7 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1281,8 +1281,10 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con if (ob_src->pose) { copy_object_pose(ob_dst, ob_src, flag_subdata); /* backwards compat... non-armatures can get poses in older files? */ - if (ob_src->type == OB_ARMATURE) - BKE_pose_rebuild(bmain, ob_dst, ob_dst->data); + if (ob_src->type == OB_ARMATURE) { + const bool do_pose_id_user = (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0; + BKE_pose_rebuild(bmain, ob_dst, ob_dst->data, do_pose_id_user); + } } defgroup_copy_list(&ob_dst->defbase, &ob_src->defbase); BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps); @@ -1536,7 +1538,7 @@ void BKE_object_make_proxy(Main *bmain, Object *ob, Object *target, Object *cob) if (target->type == OB_ARMATURE) { copy_object_pose(ob, target, 0); /* data copy, object pointers in constraints */ BKE_pose_rest(ob->pose); /* clear all transforms in channels */ - BKE_pose_rebuild(bmain, ob, ob->data); /* set all internal links */ + BKE_pose_rebuild(bmain, ob, ob->data, true); /* set all internal links */ armature_set_id_extern(ob); } @@ -2807,7 +2809,7 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph, * on file load */ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */ - BKE_pose_rebuild(NULL, ob, ob->data); + BKE_pose_rebuild(NULL, ob, ob->data, true); } } } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 7085b515ec1..ba25fc14ac9 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -1336,7 +1336,7 @@ static void scene_armature_depsgraph_workaround(Main *bmain, Depsgraph *depsgrap for (ob = bmain->object.first; ob; ob = ob->id.next) { if (ob->type == OB_ARMATURE && ob->adt && ob->adt->recalc & ADT_RECALC_ANIM) { if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(bmain, ob, ob->data); + BKE_pose_rebuild(bmain, ob, ob->data, true); } } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 043148a0f70..88996dc1f56 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -162,7 +162,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object) /* Rebuild pose if not up to date. */ if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */ - BKE_pose_rebuild(NULL, object, armature); + BKE_pose_rebuild(NULL, object, armature, true); /* XXX: Without this animation gets lost in certain circumstances * after loading file. Need to investigate further since it does * not happen with simple scenes.. diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index c93bfb5d8c3..2b28b76bcf6 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -681,7 +681,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm) /* so all users of this armature should get rebuilt */ for (obt = bmain->object.first; obt; obt = obt->id.next) { if (obt->data == arm) { - BKE_pose_rebuild(bmain, obt, arm); + BKE_pose_rebuild(bmain, obt, arm, true); } } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 87eddc2674c..d3181441168 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2332,7 +2332,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, ViewLayer ID_NEW_REMAP_US2(obn->data) else { obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); - BKE_pose_rebuild(bmain, obn, obn->data); + BKE_pose_rebuild(bmain, obn, obn->data, true); didit = 1; } id_us_min(id); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index a6751ee12a4..874b36ef42e 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1789,7 +1789,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer case OB_ARMATURE: DEG_id_tag_update(&ob->id, OB_RECALC_DATA); ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); - BKE_pose_rebuild(bmain, ob, ob->data); + BKE_pose_rebuild(bmain, ob, ob->data, true); break; case OB_SPEAKER: ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index d84827210bf..36c249228de 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -372,7 +372,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) BKE_curve_type_test(ob); } else if (ob->type == OB_ARMATURE) { - BKE_pose_rebuild(G_MAIN, ob, ob->data); + BKE_pose_rebuild(G_MAIN, ob, ob->data, true); } } } -- cgit v1.2.3 From d273f3ff7125ce5fe6366b7b55461951f7ce57e7 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 31 Jul 2018 11:30:24 +0200 Subject: Cleanup: fix compiler warnings. --- source/blender/editors/gpencil/gpencil_edit.c | 15 +++++++-------- source/blender/editors/gpencil/gpencil_fill.c | 4 +--- 2 files changed, 8 insertions(+), 11 deletions(-) (limited to 'source') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 4a603e97615..93cf2f18233 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -2454,7 +2454,6 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, int id float pressure, float strength, float deltatime) { bGPDspoint *newpoint; - MDeformVert *dvert, *newdvert; gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1)); if (gps->dvert != NULL) { @@ -2463,11 +2462,6 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, int id gps->totpoints++; newpoint = &gps->points[gps->totpoints - 1]; - if (gps->dvert != NULL) { - dvert = &gps->dvert[idx]; - newdvert = &gps->dvert[gps->totpoints - 1]; - } - newpoint->x = point->x * delta[0]; newpoint->y = point->y * delta[1]; newpoint->z = point->z * delta[2]; @@ -2476,8 +2470,13 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, int id newpoint->strength = strength; newpoint->time = point->time + deltatime; - newdvert->totweight = dvert->totweight; - newdvert->dw = MEM_dupallocN(dvert->dw); + if (gps->dvert != NULL) { + MDeformVert *dvert = &gps->dvert[idx]; + MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1]; + + newdvert->totweight = dvert->totweight; + newdvert->dw = MEM_dupallocN(dvert->dw); + } } /* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */ diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index b768ac2c44f..a0626dd69b1 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -911,9 +911,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) /* Helper: Draw status message while the user is running the operator */ static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf)) { - char status_str[UI_MAX_DRAW_STR]; - - BLI_snprintf(status_str, sizeof(status_str), IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back")); + const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back"); ED_workspace_status_text(C, status_str); } -- cgit v1.2.3 From b2193e020bc0c1a9ef9969440ece453e49f8012c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 31 Jul 2018 11:45:15 +0200 Subject: Fix crash opening .blend files with palettes. Palettes were incorrectly set as having animation data. --- source/blender/blenkernel/intern/anim_sys.c | 1 - 1 file changed, 1 deletion(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 7dfedfe6c06..b02b6b6ce15 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -104,7 +104,6 @@ bool id_type_can_have_animdata(const short id_type) case ID_MSK: case ID_GD: case ID_CF: - case ID_PAL: return true; /* no AnimData */ -- cgit v1.2.3 From f06884b18ab5b619975689a0670f8f0f14f9c318 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 20:11:55 +1000 Subject: Cleanup: style, duplicate includes --- source/blender/blenkernel/BKE_gpencil_modifier.h | 2 +- source/blender/blenkernel/intern/gpencil.c | 6 +- .../blender/blenkernel/intern/gpencil_modifier.c | 6 +- source/blender/blenkernel/intern/object.c | 34 +++----- source/blender/blenkernel/intern/subdiv_mesh.c | 4 +- source/blender/blenloader/intern/versioning_280.c | 6 +- source/blender/depsgraph/DEG_depsgraph.h | 6 +- .../intern/builder/deg_builder_relations.cc | 18 ++-- .../draw/engines/gpencil/gpencil_cache_utils.c | 5 +- .../draw/engines/gpencil/gpencil_draw_cache_impl.c | 72 +++++++++------- .../draw/engines/gpencil/gpencil_draw_utils.c | 23 ++--- .../blender/draw/engines/gpencil/gpencil_engine.c | 98 ++++++++++++---------- .../blender/draw/engines/gpencil/gpencil_engine.h | 10 ++- .../blender/draw/engines/gpencil/gpencil_render.c | 19 +++-- .../draw/engines/gpencil/gpencil_shader_fx.c | 20 +++-- .../editors/animation/anim_channels_defines.c | 2 - source/blender/editors/animation/anim_filter.c | 2 +- source/blender/editors/gpencil/annotate_draw.c | 7 +- source/blender/editors/gpencil/drawgpencil.c | 2 +- source/blender/editors/gpencil/gpencil_brush.c | 9 +- source/blender/editors/gpencil/gpencil_data.c | 15 ++-- source/blender/editors/gpencil/gpencil_edit.c | 8 +- source/blender/editors/gpencil/gpencil_fill.c | 46 +++++----- source/blender/editors/gpencil/gpencil_intern.h | 14 ++-- source/blender/editors/gpencil/gpencil_ops.c | 12 +-- source/blender/editors/gpencil/gpencil_paint.c | 41 ++++----- source/blender/editors/gpencil/gpencil_primitive.c | 22 +++-- source/blender/editors/gpencil/gpencil_utils.c | 14 ++-- source/blender/editors/include/UI_interface.h | 2 +- .../editors/interface/interface_templates.c | 13 +-- source/blender/editors/object/object_add.c | 3 +- source/blender/editors/object/object_modes.c | 2 +- source/blender/editors/object/object_modifier.c | 19 +++-- .../blender/editors/space_buttons/space_buttons.c | 2 +- .../editors/space_view3d/view3d_gizmo_ruler.c | 1 - .../blender/editors/space_view3d/view3d_select.c | 17 ++-- source/blender/editors/transform/transform.c | 2 - .../editors/transform/transform_snap_object.c | 6 +- .../gpencil_modifiers/MOD_gpencil_modifiertypes.h | 10 +-- .../gpencil_modifiers/intern/MOD_gpencil_util.c | 2 +- .../gpencil_modifiers/intern/MOD_gpencil_util.h | 2 +- .../gpencil_modifiers/intern/MOD_gpencilbuild.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilcolor.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilhook.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilinstance.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencillattice.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilmirror.c | 10 +-- .../gpencil_modifiers/intern/MOD_gpencilnoise.c | 2 +- .../gpencil_modifiers/intern/MOD_gpenciloffset.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilopacity.c | 6 +- .../gpencil_modifiers/intern/MOD_gpencilsimplify.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilsmooth.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilsubdiv.c | 4 +- .../gpencil_modifiers/intern/MOD_gpencilthick.c | 4 +- .../gpencil_modifiers/intern/MOD_gpenciltint.c | 4 +- .../blender/makesdna/DNA_gpencil_modifier_types.h | 8 +- source/blender/makesdna/DNA_shader_fx_types.h | 8 +- source/blender/makesrna/intern/rna_gpencil.c | 5 +- .../blender/makesrna/intern/rna_gpencil_modifier.c | 1 - source/blender/makesrna/intern/rna_shader_fx.c | 1 - 60 files changed, 354 insertions(+), 335 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index cd6b6540012..be27560bbf2 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -22,7 +22,7 @@ #ifndef __BKE_GPENCIL_MODIFIER_H__ #define __BKE_GPENCIL_MODIFIER_H__ -/** \file BKE_greasepencil_modifier.h +/** \file BKE_gpencil_modifier.h * \ingroup bke */ diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index de3f891f9f9..c86f39f1d55 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -546,7 +546,7 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d } BLI_assert(gps_src->totpoints == gps_dst->totpoints); - if ((gps_src->dvert == NULL) || (gps_dst->dvert == NULL)){ + if ((gps_src->dvert == NULL) || (gps_dst->dvert == NULL)) { return; } @@ -1050,7 +1050,7 @@ Material *BKE_gpencil_get_material_from_brush(Brush *brush) Material *ma = NULL; if ((brush != NULL) && (brush->gpencil_settings != NULL) && - (brush->gpencil_settings->material != NULL)) + (brush->gpencil_settings->material != NULL)) { ma = brush->gpencil_settings->material; } @@ -1076,7 +1076,7 @@ Material *BKE_gpencil_material_ensure(Main *bmain, Object *ob) assign_material(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_EXISTING); } else if (ma->gp_style == NULL) { - BKE_material_init_gpencil_settings(ma); + BKE_material_init_gpencil_settings(ma); } return ma; diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 2ba738902a0..3c2196afb18 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -384,8 +384,7 @@ void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *g const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) - { + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); if (GPENCIL_MODIFIER_EDIT(md, is_edit)) { @@ -407,8 +406,7 @@ void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); for (md = ob->greasepencil_modifiers.first; md; md = md->next) { - if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) - { + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); if (GPENCIL_MODIFIER_EDIT(md, is_edit)) { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 9c7ce7698f7..41c23c46c44 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -3821,24 +3821,18 @@ bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md) /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */ if (adt->action) { - for (fcu = (FCurve *)adt->action->curves.first; - fcu != NULL; - fcu = (FCurve *)fcu->next) - { - if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) { return true; + } } } - /* This here allows modifier properties to get driven and still update properly - * - */ - for (fcu = (FCurve *)adt->drivers.first; - fcu != NULL; - fcu = (FCurve *)fcu->next) - { - if (fcu->rna_path && strstr(fcu->rna_path, pattern)) + /* This here allows modifier properties to get driven and still update properly */ + for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) { + if (fcu->rna_path && strstr(fcu->rna_path, pattern)) { return true; + } } } @@ -3862,22 +3856,14 @@ bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx) /* action - check for F-Curves with paths containing string[' */ if (adt->action) { - for (fcu = (FCurve *)adt->action->curves.first; - fcu != NULL; - fcu = (FCurve *)fcu->next) - { + for (fcu = adt->action->curves.first; fcu != NULL; fcu = fcu->next) { if (fcu->rna_path && strstr(fcu->rna_path, pattern)) return true; } } - /* This here allows properties to get driven and still update properly - * - */ - for (fcu = (FCurve *)adt->drivers.first; - fcu != NULL; - fcu = (FCurve *)fcu->next) - { + /* This here allows properties to get driven and still update properly */ + for (fcu = adt->drivers.first; fcu != NULL; fcu = fcu->next) { if (fcu->rna_path && strstr(fcu->rna_path, pattern)) return true; } diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 895d527ea5c..db7366a2414 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -277,7 +277,7 @@ static void subdiv_mesh_ctx_init_offsets(SubdivMeshContext *ctx) num_ptex_faces_per_poly * (num_inner_edges_per_ptex_face_get( no_quad_patch_resolution - 1) + - (no_quad_patch_resolution - 2) + + (no_quad_patch_resolution - 2) + num_subdiv_vertices_per_coarse_edge); if (no_quad_patch_resolution >= 3) { edge_offset += coarse_poly->totloop; @@ -2193,7 +2193,7 @@ static void subdiv_copy_poly_data(const SubdivMeshContext *ctx, static void subdiv_create_polys(SubdivMeshContext *ctx, int poly_index) { const int resolution = ctx->settings->resolution; - const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; + const int start_poly_index = ctx->subdiv_polygon_offset[poly_index]; /* Base/coarse mesh information. */ const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 93577315b1c..d2a1cc1f4f1 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -846,7 +846,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) if (ntree->type == NTREE_SHADER) { for (bNode *node = ntree->nodes.first; node; node = node->next) { if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ && - STREQ(node->idname, "ShaderNodeOutputMetallic")) + STREQ(node->idname, "ShaderNodeOutputMetallic")) { BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname)); error |= NTREE_DOVERSION_NEED_OUTPUT; @@ -858,14 +858,14 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } else if (node->type == 196 /* SH_NODE_OUTPUT_EEVEE_MATERIAL */ && - STREQ(node->idname, "ShaderNodeOutputEeveeMaterial")) + STREQ(node->idname, "ShaderNodeOutputEeveeMaterial")) { node->type = SH_NODE_OUTPUT_MATERIAL; BLI_strncpy(node->idname, "ShaderNodeOutputMaterial", sizeof(node->idname)); } else if (node->type == 194 /* SH_NODE_EEVEE_METALLIC */ && - STREQ(node->idname, "ShaderNodeEeveeMetallic")) + STREQ(node->idname, "ShaderNodeEeveeMetallic")) { node->type = SH_NODE_BSDF_PRINCIPLED; BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname)); diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 2e566752a6f..7d827f48f9c 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -239,9 +239,9 @@ void DEG_make_inactive(struct Depsgraph *depsgraph); void DEG_debug_print_begin(struct Depsgraph *depsgraph); void DEG_debug_print_eval(struct Depsgraph *depsgraph, - const char* function_name, - const char* object_name, - const void* object_address); + const char *function_name, + const char *object_name, + const void *object_address); void DEG_debug_print_eval_subdata(struct Depsgraph *depsgraph, const char *function_name, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index c9a00b0bf0f..1d01b3e987b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2005,22 +2005,22 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) TimeSourceKey time_key; ComponentKey geometry_key(obdata, DEG_NODE_TYPE_GEOMETRY); add_relation(time_key, - geometry_key, - "GP Frame Change"); + geometry_key, + "GP Frame Change"); /* Geometry cache also needs to be recalculated when Material - * settings change (e.g. when fill.opacity changes on/off, - * we need to rebuild the bGPDstroke->triangles caches) - */ + * settings change (e.g. when fill.opacity changes on/off, + * we need to rebuild the bGPDstroke->triangles caches) + */ for (int i = 0; i < gpd->totcol; i++) { Material *ma = gpd->mat[i]; if ((ma != NULL) && (ma->gp_style != NULL)) { OperationKey material_key(&ma->id, - DEG_NODE_TYPE_SHADING, - DEG_OPCODE_MATERIAL_UPDATE); + DEG_NODE_TYPE_SHADING, + DEG_OPCODE_MATERIAL_UPDATE); add_relation(material_key, - geometry_key, - "Material -> GP Data"); + geometry_key, + "Material -> GP Data"); } } break; diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 4e01c42d33d..e8bb27b2724 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -38,8 +38,9 @@ #include "draw_cache_impl.h" /* add a gpencil object to cache to defer drawing */ -tGPencilObjectCache *gpencil_object_cache_add(tGPencilObjectCache *cache_array, Object *ob, bool is_temp, - int *gp_cache_size, int *gp_cache_used) +tGPencilObjectCache *gpencil_object_cache_add( + tGPencilObjectCache *cache_array, Object *ob, bool is_temp, + int *gp_cache_size, int *gp_cache_used) { const DRWContextState *draw_ctx = DRW_context_state_get(); tGPencilObjectCache *cache_elem = NULL; diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c index dd5db85f3f4..83a52e077ca 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c @@ -158,36 +158,42 @@ GPUBatch *DRW_gpencil_get_stroke_geom(bGPDframe *gpf, bGPDstroke *gps, short thi /* first point for adjacency (not drawn) */ if (i == 0) { if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { - gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[totpoints - 1], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + gpencil_set_stroke_point( + vbo, gpf->runtime.viewmatrix, &points[totpoints - 1], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } else { - gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[1], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + gpencil_set_stroke_point( + vbo, gpf->runtime.viewmatrix, &points[1], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } } /* set point */ - gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, pt, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + gpencil_set_stroke_point( + vbo, gpf->runtime.viewmatrix, pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { /* draw line to first point to complete the cycle */ - gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[0], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + gpencil_set_stroke_point( + vbo, gpf->runtime.viewmatrix, &points[0], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; /* now add adjacency point (not drawn) */ - gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[1], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + gpencil_set_stroke_point( + vbo, gpf->runtime.viewmatrix, &points[1], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); idx++; } /* last adjacency point (not drawn) */ else { - gpencil_set_stroke_point(vbo, gpf->runtime.viewmatrix, &points[totpoints - 2], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + gpencil_set_stroke_point( + vbo, gpf->runtime.viewmatrix, &points[totpoints - 2], idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, ink); } return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); @@ -237,30 +243,35 @@ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, float matrix[4][4], s if (i == 0) { if (totpoints > 1) { ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2); - gpencil_set_stroke_point(vbo, matrix, &pt2, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + gpencil_set_stroke_point( + vbo, matrix, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } else { - gpencil_set_stroke_point(vbo, matrix, &pt, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + gpencil_set_stroke_point( + vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } idx++; } /* set point */ - gpencil_set_stroke_point(vbo, matrix, &pt, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + gpencil_set_stroke_point( + vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); idx++; } /* last adjacency point (not drawn) */ if (totpoints > 2) { ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2); - gpencil_set_stroke_point(vbo, matrix, &pt2, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + gpencil_set_stroke_point( + vbo, matrix, &pt2, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } else { - gpencil_set_stroke_point(vbo, matrix, &pt, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); + gpencil_set_stroke_point( + vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor); } return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); @@ -307,9 +318,10 @@ GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, float matrix[4][4], sh ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); /* set point */ - gpencil_set_stroke_point(vbo, matrix, &pt, idx, - pos_id, color_id, thickness_id, uvdata_id, - thickness, gpd->runtime.scolor); + gpencil_set_stroke_point( + vbo, matrix, &pt, idx, + pos_id, color_id, thickness_id, uvdata_id, + thickness, gpd->runtime.scolor); idx++; } @@ -600,9 +612,10 @@ GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED( return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); } -static void set_grid_point(GPUVertBuf *vbo, int idx, float col_grid[4], - uint pos_id, uint color_id, - float v1, float v2, int axis) +static void set_grid_point( + GPUVertBuf *vbo, int idx, float col_grid[4], + uint pos_id, uint color_id, + float v1, float v2, int axis) { GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid); @@ -618,8 +631,7 @@ static void set_grid_point(GPUVertBuf *vbo, int idx, float col_grid[4], pos[1] = v2; pos[2] = 0.0f; } - else - { + else { pos[0] = v1; pos[1] = 0.0f; pos[2] = v2; diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index 76cb1405a71..04399d1cad7 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -63,8 +63,9 @@ #define PATTERN 5 /* Helper for doing all the checks on whether a stroke can be drawn */ -static bool gpencil_can_draw_stroke(struct MaterialGPencilStyle *gp_style, const bGPDstroke *gps, - const bool onion, const bool is_mat_preview) +static bool gpencil_can_draw_stroke( + struct MaterialGPencilStyle *gp_style, const bGPDstroke *gps, + const bool onion, const bool is_mat_preview) { /* skip stroke if it doesn't have any valid data */ if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) @@ -77,8 +78,8 @@ static bool gpencil_can_draw_stroke(struct MaterialGPencilStyle *gp_style, const /* check if the color is visible */ if ((gp_style == NULL) || - (gp_style->flag & GP_STYLE_COLOR_HIDE) || - (onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) + (gp_style->flag & GP_STYLE_COLOR_HIDE) || + (onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) { return false; } @@ -656,8 +657,8 @@ static void gpencil_add_editpoints_shgroup( } if (cache->batch_edlin[cache->cache_idx]) { if ((obact) && (obact == ob) && - ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (v3d->flag3 & V3D_GP_SHOW_EDIT_LINES)) + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->flag3 & V3D_GP_SHOW_EDIT_LINES)) { DRW_shgroup_call_add( stl->g_data->shgrps_edit_line, @@ -947,7 +948,7 @@ void DRW_gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data, void *vedata, T stl->storage->unit_matrix); if ((gpd->runtime.sbuffer_size >= 3) && (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) && - ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0)) + ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0)) { /* if not solid, fill is simulated with solid color */ if (gpd->runtime.bfill_style > 0) { @@ -1229,12 +1230,12 @@ void DRW_gpencil_populate_datablock(GPENCIL_e_data *e_data, void *vedata, Scene /* draw onion skins */ if ((gpd->flag & GP_DATA_SHOW_ONIONSKINS) && - (!no_onion) && (overlay) && - (gpl->onion_flag & GP_LAYER_ONIONSKIN) && - ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) + (!no_onion) && (overlay) && + (gpl->onion_flag & GP_LAYER_ONIONSKIN) && + ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) { if ((!stl->storage->is_render) || - ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) + ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) { gpencil_draw_onionskins(cache, e_data, vedata, ob, gpd, gpl, gpf); } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 71c99b2bcdf..d81cf8b7752 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -87,10 +87,11 @@ void DRW_gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h txl->multisample_depth = GPU_texture_create_2D_multisample( rect_w, rect_h, GPU_DEPTH24_STENCIL8, NULL, samples, NULL); } - GPU_framebuffer_ensure_config(&fbl->multisample_fb, { - GPU_ATTACHMENT_TEXTURE(txl->multisample_depth), - GPU_ATTACHMENT_TEXTURE(txl->multisample_color) - }); + GPU_framebuffer_ensure_config( + &fbl->multisample_fb, { + GPU_ATTACHMENT_TEXTURE(txl->multisample_depth), + GPU_ATTACHMENT_TEXTURE(txl->multisample_color) + }); if (!GPU_framebuffer_check_valid(fbl->multisample_fb, NULL)) { GPU_framebuffer_free(fbl->multisample_fb); } @@ -121,39 +122,49 @@ static void GPENCIL_create_framebuffers(void *vedata) &draw_engine_gpencil_type); e_data.temp_color_tx_a = DRW_texture_pool_query_2D(size[0], size[1], fb_format, &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config(&fbl->temp_fb_a, { - GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_a), - GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a) - }); - - e_data.temp_depth_tx_b = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - e_data.temp_color_tx_b = DRW_texture_pool_query_2D(size[0], size[1], fb_format, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config(&fbl->temp_fb_b, { - GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_b), - GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b) - }); + GPU_framebuffer_ensure_config( + &fbl->temp_fb_a, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_a), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_a) + }); + + e_data.temp_depth_tx_b = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + e_data.temp_color_tx_b = DRW_texture_pool_query_2D( + size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->temp_fb_b, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_b), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_b) + }); /* used for rim FX effect */ - e_data.temp_depth_tx_rim = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - e_data.temp_color_tx_rim = DRW_texture_pool_query_2D(size[0], size[1], fb_format, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config(&fbl->temp_fb_rim, { - GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_rim), - GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_rim), - }); + e_data.temp_depth_tx_rim = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + e_data.temp_color_tx_rim = DRW_texture_pool_query_2D( + size[0], size[1], fb_format, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->temp_fb_rim, { + GPU_ATTACHMENT_TEXTURE(e_data.temp_depth_tx_rim), + GPU_ATTACHMENT_TEXTURE(e_data.temp_color_tx_rim), + }); /* background framebuffer to speed up drawing process (always 16 bits) */ - e_data.background_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - e_data.background_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA32F, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config(&fbl->background_fb, { - GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx), - GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx) - }); + e_data.background_depth_tx = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + e_data.background_color_tx = DRW_texture_pool_query_2D( + size[0], size[1], GPU_RGBA32F, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->background_fb, { + GPU_ATTACHMENT_TEXTURE(e_data.background_depth_tx), + GPU_ATTACHMENT_TEXTURE(e_data.background_color_tx) + }); } } @@ -358,7 +369,7 @@ void GPENCIL_cache_init(void *vedata) (stl->storage->playing == 0)) { if (((obact_gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) && - (obact_gpd->runtime.sbuffer_size > 1)) + (obact_gpd->runtime.sbuffer_size > 1)) { stl->g_data->session_flag = GP_DRW_PAINT_PAINTING; } @@ -485,8 +496,9 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) } /* allocate memory for saving gp objects for drawing later */ - stl->g_data->gp_object_cache = gpencil_object_cache_add(stl->g_data->gp_object_cache, ob, false, - &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used); + stl->g_data->gp_object_cache = gpencil_object_cache_add( + stl->g_data->gp_object_cache, ob, false, + &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used); /* generate instances as separate cache objects for instance modifiers * with the "Make as Objects" option enabled @@ -500,9 +512,9 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) /* grid */ if ((v3d) && - ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (v3d->flag3 & V3D_GP_SHOW_GRID) && - (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact)) + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->flag3 & V3D_GP_SHOW_GRID) && + (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact)) { stl->g_data->batch_grid = DRW_gpencil_get_grid(); DRW_shgroup_call_add(stl->g_data->shgrps_grid, @@ -631,8 +643,8 @@ void GPENCIL_draw_scene(void *ved) /* paper pass to display a confortable area to draw over complex scenes with geometry */ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (v3d->flag3 & V3D_GP_SHOW_PAPER) && - (stl->g_data->gp_cache_used > 0)) + (v3d->flag3 & V3D_GP_SHOW_PAPER) && + (stl->g_data->gp_cache_used > 0)) { DRW_draw_pass(psl->paper_pass); } @@ -655,7 +667,7 @@ void GPENCIL_draw_scene(void *ved) /* grid pass */ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (v3d->flag3 & V3D_GP_SHOW_GRID)) + (v3d->flag3 & V3D_GP_SHOW_GRID)) { DRW_draw_pass(psl->grid_pass); } @@ -744,7 +756,7 @@ void GPENCIL_draw_scene(void *ved) /* grid pass */ if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { if (((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (v3d->flag3 & V3D_GP_SHOW_GRID)) + (v3d->flag3 & V3D_GP_SHOW_GRID)) { DRW_draw_pass(psl->grid_pass); } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 24a627f1012..5d276490663 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -279,8 +279,9 @@ typedef struct GpencilBatchCache { } GpencilBatchCache; /* general drawing functions */ -struct DRWShadingGroup *DRW_gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, struct DRWPass *pass, struct GPUShader *shader, - struct Object *ob, struct bGPdata *gpd, struct MaterialGPencilStyle *gp_style, int id, bool onion); +struct DRWShadingGroup *DRW_gpencil_shgroup_stroke_create( + struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, struct DRWPass *pass, struct GPUShader *shader, + struct Object *ob, struct bGPdata *gpd, struct MaterialGPencilStyle *gp_style, int id, bool onion); void DRW_gpencil_populate_datablock(struct GPENCIL_e_data *e_data, void *vedata, struct Scene *scene, struct Object *ob, struct bGPdata *gpd); void DRW_gpencil_populate_buffer_strokes(struct GPENCIL_e_data *e_data, void *vedata, struct ToolSettings *ts, struct Object *ob); void DRW_gpencil_populate_multiedit(struct GPENCIL_e_data *e_data, void *vedata, struct Scene *scene, struct Object *ob, struct bGPdata *gpd); @@ -300,8 +301,9 @@ struct GPUBatch *DRW_gpencil_get_buffer_point_geom(struct bGPdata *gpd, float ma struct GPUBatch *DRW_gpencil_get_grid(void); /* object cache functions */ -struct tGPencilObjectCache *gpencil_object_cache_add(struct tGPencilObjectCache *cache_array, struct Object *ob, - bool is_temp, int *gp_cache_size, int *gp_cache_used); +struct tGPencilObjectCache *gpencil_object_cache_add( + struct tGPencilObjectCache *cache_array, struct Object *ob, + bool is_temp, int *gp_cache_size, int *gp_cache_used); /* geometry batch cache functions */ void gpencil_batch_cache_check_free_slots(struct Object *ob); diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index d76ea56894f..0b90de88ec1 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -84,14 +84,17 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra DRW_gpencil_multisample_ensure(vedata, rect_w, rect_h); } - vedata->render_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_DEPTH24_STENCIL8, - &draw_engine_gpencil_type); - vedata->render_color_tx = DRW_texture_pool_query_2D(size[0], size[1], GPU_RGBA32F, - &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config(&fbl->main, { - GPU_ATTACHMENT_TEXTURE(vedata->render_depth_tx), - GPU_ATTACHMENT_TEXTURE(vedata->render_color_tx) - }); + vedata->render_depth_tx = DRW_texture_pool_query_2D( + size[0], size[1], GPU_DEPTH24_STENCIL8, + &draw_engine_gpencil_type); + vedata->render_color_tx = DRW_texture_pool_query_2D( + size[0], size[1], GPU_RGBA32F, + &draw_engine_gpencil_type); + GPU_framebuffer_ensure_config( + &fbl->main, { + GPU_ATTACHMENT_TEXTURE(vedata->render_depth_tx), + GPU_ATTACHMENT_TEXTURE(vedata->render_color_tx) + }); /* Alloc transient data. */ if (!stl->g_data) { diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index e453224020d..827f2e9344b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -211,8 +211,9 @@ static void DRW_gpencil_fx_blur( struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, - psl->fx_shader_pass_blend); + fx_shgrp = DRW_shgroup_create( + e_data->gpencil_fx_blur_sh, + psl->fx_shader_pass_blend); DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); @@ -389,8 +390,9 @@ static void DRW_gpencil_fx_rim( struct GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); /* prepare pass */ - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_prepare_sh, - psl->fx_shader_pass_blend); + fx_shgrp = DRW_shgroup_create( + e_data->gpencil_fx_rim_prepare_sh, + psl->fx_shader_pass_blend); DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); @@ -408,8 +410,9 @@ static void DRW_gpencil_fx_rim( fxd->runtime.fx_sh = fx_shgrp; /* blur pass */ - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, - psl->fx_shader_pass_blend); + fx_shgrp = DRW_shgroup_create( + e_data->gpencil_fx_blur_sh, + psl->fx_shader_pass_blend); DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_rim); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_rim); @@ -423,8 +426,9 @@ static void DRW_gpencil_fx_rim( fxd->runtime.fx_sh_b = fx_shgrp; /* resolve pass */ - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_resolve_sh, - psl->fx_shader_pass_blend); + fx_shgrp = DRW_shgroup_create( + e_data->gpencil_fx_rim_resolve_sh, + psl->fx_shader_pass_blend); DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 2431bd50e1b..79b7c7988fd 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -84,8 +84,6 @@ #include "BIF_gl.h" -#include "DEG_depsgraph.h" - #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 1981814eb02..54590c5f66c 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -2615,7 +2615,7 @@ static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data /* grease pencil */ if ((ob->type == OB_GPENCIL) && - (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) + (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode); } diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index dad5af7379c..4f6e2004197 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -787,9 +787,10 @@ static void gp_draw_data_layers( * It should also be noted that sbuffer contains temporary point types * i.e. tGPspoints NOT bGPDspoints */ - gp_draw_stroke_buffer(gpd->runtime.sbuffer, - gpd->runtime.sbuffer_size, lthick, - dflag, gpd->runtime.sbuffer_sflag, ink); + gp_draw_stroke_buffer( + gpd->runtime.sbuffer, + gpd->runtime.sbuffer_size, lthick, + dflag, gpd->runtime.sbuffer_sflag, ink); } } } diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 5c56877cbe6..2c0b3e9900a 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1047,7 +1047,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) (gp_style->fill_rgba[3] > 0.0f) && ((gps->flag & GP_STROKE_NOFILL) == 0)) { - continue; + continue; } /* calculate thickness */ diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 52642fb2570..0fadef55b9d 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -755,10 +755,11 @@ static bool gp_brush_randomize_apply( const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f; const float fac = BLI_rng_get_float(gso->rng) * inf; /* need one flag enabled by default */ - if ((gso->settings->flag & (GP_BRUSHEDIT_FLAG_APPLY_POSITION | - GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | - GP_BRUSHEDIT_FLAG_APPLY_THICKNESS | - GP_BRUSHEDIT_FLAG_APPLY_UV)) == 0) + if ((gso->settings->flag & + (GP_BRUSHEDIT_FLAG_APPLY_POSITION | + GP_BRUSHEDIT_FLAG_APPLY_STRENGTH | + GP_BRUSHEDIT_FLAG_APPLY_THICKNESS | + GP_BRUSHEDIT_FLAG_APPLY_UV)) == 0) { gso->settings->flag |= GP_BRUSHEDIT_FLAG_APPLY_POSITION; } diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index dd1852ca8ce..c58c45b3117 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -67,7 +67,6 @@ #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_library.h" -#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_material.h" @@ -462,8 +461,7 @@ void GPENCIL_OT_frame_duplicate(wmOperatorType *ot) { GP_FRAME_DUP_ACTIVE, "ACTIVE", 0, "Active", "Duplicate frame in active layer only" }, { GP_FRAME_DUP_ALL, "ALL", 0, "All", "Duplicate active frames in all layers" }, { 0, NULL, 0, NULL, NULL } - }; - + }; /* identifiers */ ot->name = "Duplicate Frame"; @@ -1401,8 +1399,8 @@ static bool gpencil_vertex_group_poll(bContext *C) if ((ob) && (ob->type == OB_GPENCIL)) { if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) { if (ELEM(ob->mode, - OB_MODE_GPENCIL_EDIT, - OB_MODE_GPENCIL_SCULPT)) + OB_MODE_GPENCIL_EDIT, + OB_MODE_GPENCIL_SCULPT)) { return true; } @@ -1418,8 +1416,7 @@ static bool gpencil_vertex_group_weight_poll(bContext *C) if ((ob) && (ob->type == OB_GPENCIL)) { if (!ID_IS_LINKED(ob) && !ID_IS_LINKED(ob->data) && ob->defbase.first) { - if (ob->mode == OB_MODE_GPENCIL_WEIGHT) - { + if (ob->mode == OB_MODE_GPENCIL_WEIGHT) { return true; } } @@ -1807,8 +1804,8 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) { if (base->object->type == OB_GPENCIL) { if ((base->object->rot[0] != 0) || - (base->object->rot[1] != 0) || - (base->object->rot[2] != 0)) + (base->object->rot[1] != 0) || + (base->object->rot[2] != 0)) { BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 93cf2f18233..fdeadcc648a 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -62,7 +62,6 @@ #include "BKE_gpencil.h" #include "BKE_paint.h" #include "BKE_library.h" -#include "BKE_main.h" #include "BKE_material.h" #include "BKE_object.h" #include "BKE_report.h" @@ -861,8 +860,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) { if (ED_gpencil_stroke_can_use(C, gps)) { ma = give_current_material(ob, gps->mat_nr + 1); - if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, &gps->mat_nr) == false) - { + if (BLI_ghash_haskey(gp_strokes_copypastebuf_colors, &gps->mat_nr) == false) { BLI_ghash_insert(gp_strokes_copypastebuf_colors, &gps->mat_nr, ma); } } @@ -2153,7 +2151,7 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) } DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); - DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE); + DEG_id_tag_update(&obact->id, DEG_TAG_COPY_ON_WRITE); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -2757,7 +2755,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; + RegionView3D *rv3d = ar->regiondata; View3D *v3d = sa->spacedata.first; GP_SpaceConversion gsc = {NULL}; diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index a0626dd69b1..20db5c1504f 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -125,8 +125,9 @@ typedef struct tGPDfill { /* draw a given stroke using same thickness and color for all points */ -static void gp_draw_basic_stroke(tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4], - bool cyclic, float ink[4], int flag, float thershold) +static void gp_draw_basic_stroke( + tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4], + bool cyclic, float ink[4], int flag, float thershold) { bGPDspoint *points = gps->points; @@ -228,8 +229,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, float ink[4]) } /* check if the color is visible */ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); - if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) - { + if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) { continue; } @@ -247,7 +247,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, float ink[4]) /* normal strokes */ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) || - (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) + (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) { ED_gp_draw_fill(&tgpw); @@ -255,7 +255,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, float ink[4]) /* 3D Lines with basic shapes and invisible lines */ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) || - (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) + (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) { gp_draw_basic_stroke(tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink, tgpf->flag, tgpf->fill_threshold); @@ -313,8 +313,9 @@ static void gp_render_offscreen(tGPDfill *tgpf) glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ED_view3d_update_viewmat(tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, - NULL, winmat, NULL); + ED_view3d_update_viewmat( + tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar, + NULL, winmat, NULL); /* set for opengl */ GPU_matrix_projection_set(tgpf->rv3d->winmat); GPU_matrix_set(tgpf->rv3d->viewmat); @@ -531,8 +532,7 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) if (true) { /* Was: 'rgba' */ /* check if no border(red) or already filled color(green) */ - if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) - { + if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) { /* fill current pixel */ set_pixel(ibuf, v, fill_col); @@ -627,7 +627,7 @@ static void gpencil_get_outline_points(tGPDfill *tgpf) int backtracked_co[2]; int current_check_co[2]; int prev_check_co[2]; - int backtracked_offset[1][2] = { { 0,0 } }; + int backtracked_offset[1][2] = {{0, 0}}; // bool boundary_found = false; bool start_found = false; const int NEIGHBOR_COUNT = 8; @@ -667,12 +667,11 @@ static void gpencil_get_outline_points(tGPDfill *tgpf) } } - while (true && start_found) - { + while (start_found) { int cur_back_offset = -1; for (int i = 0; i < NEIGHBOR_COUNT; i++) { if (backtracked_offset[0][0] == offset[i][0] && - backtracked_offset[0][1] == offset[i][1]) + backtracked_offset[0][1] == offset[i][1]) { /* Finding the bracktracked pixel offset index */ cur_back_offset = i; @@ -706,7 +705,7 @@ static void gpencil_get_outline_points(tGPDfill *tgpf) } /* current pixel is equal to starting pixel */ if (boundary_co[0] == start_co[0] && - boundary_co[1] == start_co[1]) + boundary_co[1] == start_co[1]) { BLI_stack_pop(tgpf->stack, &v); // boundary_found = true; @@ -753,8 +752,10 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) { copy_v2_v2_int(mval, &ptc->x); - if ((ED_view3d_autodist_depth(tgpf->ar, mval, depth_margin, tgpf->depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg(tgpf->ar, mval, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) + if ((ED_view3d_autodist_depth( + tgpf->ar, mval, depth_margin, tgpf->depth_arr + i) == 0) && + (i && (ED_view3d_autodist_depth_seg( + tgpf->ar, mval, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) { interp_depth = true; } @@ -849,7 +850,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) gps->flag |= GP_STROKE_RECALC_CACHES; /* add stroke to frame */ - if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)){ + if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) { BLI_addhead(&tgpf->gpf->strokes, gps); } else { @@ -862,10 +863,11 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) point2D = (tGPspoint *)tgpf->sbuffer; for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++, dvert++) { /* convert screen-coordinates to 3D coordinates */ - gp_stroke_convertcoords_tpoint(tgpf->scene, tgpf->ar, tgpf->v3d, tgpf->ob, - tgpf->gpl, point2D, - tgpf->depth_arr ? tgpf->depth_arr + i : NULL, - &pt->x); + gp_stroke_convertcoords_tpoint( + tgpf->scene, tgpf->ar, tgpf->v3d, tgpf->ob, + tgpf->gpl, point2D, + tgpf->depth_arr ? tgpf->depth_arr + i : NULL, + &pt->x); pt->pressure = 1.0f; pt->strength = 1.0f;; diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 0218530be4e..a51f9e7a065 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -216,10 +216,11 @@ void gp_apply_parent_point(struct Depsgraph *depsgraph, struct Object *obact, bG bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, struct Scene *scene, const float screen_co[2], float r_out[3]); /* helper to convert 2d to 3d */ -void gp_stroke_convertcoords_tpoint(struct Scene *scene, struct ARegion *ar, - struct View3D *v3d, struct Object *ob, - bGPDlayer *gpl, const struct tGPspoint *point2D, - float *depth, float out[3]); +void gp_stroke_convertcoords_tpoint( + struct Scene *scene, struct ARegion *ar, + struct View3D *v3d, struct Object *ob, + bGPDlayer *gpl, const struct tGPspoint *point2D, + float *depth, float out[3]); /* Poll Callbacks ------------------------------------ */ /* gpencil_utils.c */ @@ -239,8 +240,9 @@ struct GHash *gp_copybuf_validate_colormap(struct bContext *C); /* Stroke Editing ------------------------------------ */ -void gp_stroke_delete_tagged_points(bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, - int tag_flags, bool select); +void gp_stroke_delete_tagged_points( + bGPDframe *gpf, bGPDstroke *gps, bGPDstroke *next_stroke, + int tag_flags, bool select); int gp_delete_selected_point_wrap(bContext *C); bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 991bfb622b7..e5ebfcecdf8 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -128,8 +128,8 @@ static bool gp_stroke_paintmode_draw_poll(bContext *C) bGPdata *gpd = CTX_data_gpencil_data(C); ToolSettings *ts = CTX_data_tool_settings(C); Brush *brush = BKE_brush_getactive_gpencil(ts); - return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) - && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW)); + return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) && + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW)); } /* Poll callback for stroke painting (erase brush) */ @@ -139,8 +139,8 @@ static bool gp_stroke_paintmode_erase_poll(bContext *C) bGPdata *gpd = CTX_data_gpencil_data(C); ToolSettings *ts = CTX_data_tool_settings(C); Brush *brush = BKE_brush_getactive_gpencil(ts); - return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) - && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)); + return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) && + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)); } /* Poll callback for stroke painting (fill) */ @@ -150,8 +150,8 @@ static bool gp_stroke_paintmode_fill_poll(bContext *C) bGPdata *gpd = CTX_data_gpencil_data(C); ToolSettings *ts = CTX_data_tool_settings(C); Brush *brush = BKE_brush_getactive_gpencil(ts); - return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) - && (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_FILL)); + return (gpd && (gpd->flag & GP_DATA_STROKE_PAINTMODE) && (brush) && + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_FILL)); } /* Poll callback for stroke sculpting mode */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index fd5b2803650..0c411db57b4 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -61,8 +61,6 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_gpencil.h" -#include "BKE_main.h" -#include "BKE_paint.h" #include "BKE_report.h" #include "BKE_layer.h" #include "BKE_material.h" @@ -624,7 +622,7 @@ static short gp_stroke_addpoint( } /* apply randomness to pressure */ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && - (brush->gpencil_settings->draw_random_press > 0.0f)) + (brush->gpencil_settings->draw_random_press > 0.0f)) { float curvef = curvemapping_evaluateF(brush->gpencil_settings->curve_sensitivity, 0, pressure); float tmp_pressure = curvef * brush->gpencil_settings->draw_sensitivity; @@ -672,7 +670,7 @@ static short gp_stroke_addpoint( /* apply randomness to color strength */ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && - (brush->gpencil_settings->draw_random_strength > 0.0f)) + (brush->gpencil_settings->draw_random_strength > 0.0f)) { if (BLI_rng_get_float(p->rng) > 0.5f) { pt->strength -= pt->strength * brush->gpencil_settings->draw_random_strength * BLI_rng_get_float(p->rng); @@ -1381,13 +1379,13 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* 2) Tag any point with overly low influence for removal in the next pass */ if ((pt1->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) || - (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) + (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) { pt1->flag |= GP_SPOINT_TAG; do_cull = true; } if ((pt2->pressure < cull_thresh) || (p->flags & GP_PAINTFLAG_HARD_ERASER) || - (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) + (eraser->gpencil_settings->eraser_mode == GP_BRUSH_ERASER_HARD)) { pt2->flag |= GP_SPOINT_TAG; do_cull = true; @@ -1500,14 +1498,14 @@ static Brush *gp_get_default_eraser(Main *bmain, ToolSettings *ts) Brush *brush_old = paint->brush; for (Brush *brush = bmain->brush.first; brush; brush = brush->id.next) { if ((brush->ob_mode == OB_MODE_GPENCIL_PAINT) && - (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) { /* save first eraser to use later if no default */ if (brush_dft == NULL) { brush_dft = brush; } /* found default */ - if(brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) { + if (brush->gpencil_settings->flag & GP_BRUSH_DEFAULT_ERASER) { return brush; } } @@ -2201,7 +2199,7 @@ static void gpencil_draw_cursor_set(tGPsdata *p) { Brush *brush = p->brush; if ((p->paintmode == GP_PAINTMODE_ERASER) || - (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) + (brush->gpencil_settings->brush_type == GP_BRUSH_TYPE_ERASE)) { WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */ } @@ -2218,17 +2216,20 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) #if 0 /* FIXME, this never runs! */ switch (p->paintmode) { - case GP_PAINTMODE_DRAW_POLY: - /* Provide usage tips, since this is modal, and unintuitive without hints */ - ED_workspace_status_text(C, IFACE_("Annotation Create Poly: LMB click to place next stroke vertex | " - "ESC/Enter to end (or click outside this area)")); - break; - default: - /* Do nothing - the others are self explanatory, exit quickly once the mouse is released - * Showing any text would just be annoying as it would flicker. - */ - break; - } + case GP_PAINTMODE_DRAW_POLY: + /* Provide usage tips, since this is modal, and unintuitive without hints */ + ED_workspace_status_text( + C, IFACE_( + "Annotation Create Poly: LMB click to place next stroke vertex | " + "ESC/Enter to end (or click outside this area)" + )); + break; + default: + /* Do nothing - the others are self explanatory, exit quickly once the mouse is released + * Showing any text would just be annoying as it would flicker. + */ + break; + } #endif case GP_STATUS_IDLING: diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index ef09c5c3f76..9dbec666cc4 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -230,23 +230,27 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi } else { if (tgpi->flag == IN_PROGRESS) { - BLI_snprintf(status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, (int)tgpi->tot_edges, - tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]); + BLI_snprintf( + status_str, sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, (int)tgpi->tot_edges, + tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]); } else { - BLI_snprintf(status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, (int)tgpi->tot_edges, - tgpi->bottom[0], tgpi->bottom[1]); + BLI_snprintf( + status_str, sizeof(status_str), "%s: %d (%d, %d)", msg_str, (int)tgpi->tot_edges, + tgpi->bottom[0], tgpi->bottom[1]); } } } else { if (tgpi->flag == IN_PROGRESS) { - BLI_snprintf(status_str, sizeof(status_str), "%s: (%d, %d) (%d, %d)", msg_str, - tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]); + BLI_snprintf( + status_str, sizeof(status_str), "%s: (%d, %d) (%d, %d)", msg_str, + tgpi->top[0], tgpi->top[1], tgpi->bottom[0], tgpi->bottom[1]); } else { - BLI_snprintf(status_str, sizeof(status_str), "%s: (%d, %d)", msg_str, - tgpi->bottom[0], tgpi->bottom[1]); + BLI_snprintf( + status_str, sizeof(status_str), "%s: (%d, %d)", msg_str, + tgpi->bottom[0], tgpi->bottom[1]); } } ED_workspace_status_text(C, status_str); @@ -467,7 +471,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) if (tgpi->type == GP_STROKE_CIRCLE) { RNA_int_set(op->ptr, "edges", 32); } - else if(tgpi->type == GP_STROKE_BOX) { + else if (tgpi->type == GP_STROKE_BOX) { RNA_int_set(op->ptr, "edges", 4); } else { /* LINE */ diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 7262c537321..cd352579b4a 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -1426,9 +1426,9 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata) * The decision was to use a fix size, instead of paintbrush->thickness value. */ if ((gp_style) && (GPENCIL_PAINT_MODE(gpd)) && - ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && - ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) && - (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW)) + ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) && + ((paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) && + (paintbrush->gpencil_settings->brush_type == GP_BRUSH_TYPE_DRAW)) { radius = 2.0f; copy_v3_v3(color, gp_style->stroke_rgba); @@ -1491,7 +1491,7 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata) /* Draw line for lazy mouse */ if ((last_mouse_position) && - (paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP)) + (paintbrush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP)) { glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); @@ -1501,8 +1501,10 @@ static void gp_brush_drawcursor(bContext *C, int x, int y, void *customdata) immBegin(GPU_PRIM_LINES, 2); immVertex2f(pos, x, y); - immVertex2f(pos, last_mouse_position[0] + ar->winrct.xmin, - last_mouse_position[1] + ar->winrct.ymin); + immVertex2f( + pos, + last_mouse_position[0] + ar->winrct.xmin, + last_mouse_position[1] + ar->winrct.ymin); immEnd(); glDisable(GL_BLEND); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index fc3dd3f9968..d174a78ee23 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1023,7 +1023,7 @@ void uiTemplateHeader(uiLayout *layout, struct bContext *C); void uiTemplateID( uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, - int filter, const bool live_icon); + int filter, const bool live_icon); void uiTemplateIDBrowse( uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int filter); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 07d259dd047..e81ad1428d1 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -174,7 +174,7 @@ static uiBlock *template_common_search_menu( uiButSearchFunc search_func, void *search_arg, uiButHandleFunc handle_func, void *active_item, const int preview_rows, const int preview_cols, - float scale) + float scale) { static char search[256]; wmWindow *win = CTX_wm_window(C); @@ -644,7 +644,7 @@ static uiBut *template_id_def_new_but( static void template_ID( bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag, const char *newop, const char *openop, const char *unlinkop, - const bool live_icon) + const bool live_icon) { uiBut *but; uiBlock *block; @@ -875,7 +875,7 @@ static void ui_template_id( PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int flag, int prv_rows, int prv_cols, int filter, bool use_tabs, - float scale, bool live_icon) + float scale, bool live_icon) { TemplateID *template_ui; PropertyRNA *prop; @@ -933,7 +933,7 @@ static void ui_template_id( void uiTemplateID( uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, - int filter, const bool live_icon) + int filter, const bool live_icon) { ui_template_id( layout, C, ptr, propname, @@ -1569,8 +1569,9 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) /************************ Grease Pencil Modifier Template *************************/ -static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, - GpencilModifierData *md) +static uiLayout *gpencil_draw_modifier( + uiLayout *layout, Object *ob, + GpencilModifierData *md) { const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); PointerRNA ptr; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index d3181441168..1ae441ee2f4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1005,7 +1005,8 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) * for them to end up aligned oddly, but only for Monkey */ if ((RNA_struct_property_is_set(op->ptr, "view_align") == false) && - (type == GP_MONKEY)) { + (type == GP_MONKEY)) + { RNA_boolean_set(op->ptr, "view_align", true); } diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index 261f7f42bc0..b9bfb44f680 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -118,7 +118,7 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) break; case OB_GPENCIL: if (mode & (OB_MODE_EDIT | OB_MODE_GPENCIL_EDIT | OB_MODE_GPENCIL_PAINT | - OB_MODE_GPENCIL_SCULPT | OB_MODE_GPENCIL_WEIGHT)) + OB_MODE_GPENCIL_SCULPT | OB_MODE_GPENCIL_WEIGHT)) { return true; } diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index f83c6af08ee..43f651b0532 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -204,9 +204,10 @@ static bool object_has_modifier(const Object *ob, const ModifierData *exclude, * If the callback ever returns true, iteration will stop and the * function value will be true. Otherwise the function returns false. */ -bool ED_object_iter_other(Main *bmain, Object *orig_ob, const bool include_orig, - bool (*callback)(Object *ob, void *callback_data), - void *callback_data) +bool ED_object_iter_other( + Main *bmain, Object *orig_ob, const bool include_orig, + bool (*callback)(Object *ob, void *callback_data), + void *callback_data) { ID *ob_data_id = orig_ob->data; int users = ob_data_id->us; @@ -220,10 +221,10 @@ bool ED_object_iter_other(Main *bmain, Object *orig_ob, const bool include_orig, int totfound = include_orig ? 0 : 1; for (ob = bmain->object.first; ob && totfound < users; - ob = ob->id.next) + ob = ob->id.next) { if (((ob != orig_ob) || include_orig) && - (ob->data == orig_ob->data)) + (ob->data == orig_ob->data)) { if (callback(ob, callback_data)) return true; @@ -318,7 +319,7 @@ static bool object_modifier_remove(Main *bmain, Object *ob, ModifierData *md, } if (ELEM(md->type, eModifierType_Softbody, eModifierType_Cloth) && - BLI_listbase_is_empty(&ob->particlesystem)) + BLI_listbase_is_empty(&ob->particlesystem)) { ob->mode &= ~OB_MODE_PARTICLE_EDIT; } @@ -681,8 +682,8 @@ int ED_object_modifier_apply( return 0; } else if ((ob->mode & OB_MODE_SCULPT) && - (find_multires_modifier_before(scene, md)) && - (modifier_isSameTopology(md) == false)) + (find_multires_modifier_before(scene, md)) && + (modifier_isSameTopology(md) == false)) { BKE_report(reports, RPT_ERROR, "Constructive modifier cannot be applied to multi-res data in sculpt mode"); return 0; @@ -1525,7 +1526,7 @@ static int skin_root_mark_exec(bContext *C, wmOperator *UNUSED(op)) BM_ITER_MESH (bm_vert, &bm_iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(bm_vert, BM_ELEM_SELECT) && - BLI_gset_add(visited, bm_vert)) + BLI_gset_add(visited, bm_vert)) { MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(bm_vert, cd_vert_skin_offset); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 62115aea11d..98ff2f67b58 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -527,7 +527,7 @@ static void buttons_area_listener( } break; case NC_GPENCIL: - switch(wmn->data) { + switch (wmn->data) { case ND_DATA: if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) ED_area_tag_redraw(sa); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index d5ef7cdf441..fb335d5f922 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -37,7 +37,6 @@ #include "BKE_object.h" #include "BKE_unit.h" #include "BKE_material.h" -#include "BKE_main.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index afff5eb7f66..2f65ad1fde4 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1683,22 +1683,23 @@ static bool ed_object_select_pick( The grease pencil modes are not real modes, but a hack to make the interface consistent, so need some tricks to keep UI synchronized */ // XXX: This stuff neeeds reviewing (Aligorith) -#if 0 - if (((oldbasact) && oldbasact->object->type == OB_GPENCIL) || (basact->object->type == OB_GPENCIL)) { + if (false && + (((oldbasact) && oldbasact->object->type == OB_GPENCIL) || + (basact->object->type == OB_GPENCIL))) + { /* set cursor */ - if (ELEM(basact->object->mode == OB_MODE_GPENCIL_PAINT, - OB_MODE_GPENCIL_SCULPT, - OB_MODE_GPENCIL_WEIGHT)) { + if (ELEM(basact->object->mode, + OB_MODE_GPENCIL_PAINT, + OB_MODE_GPENCIL_SCULPT, + OB_MODE_GPENCIL_WEIGHT)) + { ED_gpencil_toggle_brush_cursor(C, true, NULL); } else { /* TODO: maybe is better use restore */ ED_gpencil_toggle_brush_cursor(C, false, NULL); } - /* set workspace mode */ - BKE_workspace_object_mode_set(CTX_wm_workspace(C), scene, basact->object->mode); } -#endif } DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 9ad80f2ab12..b0de996ee0e 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -103,8 +103,6 @@ #include "transform.h" -#include "DEG_depsgraph.h" - /* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */ // #define USE_NUM_NO_ZERO diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index bc35e6e6b89..6dfcfe11af2 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -2282,9 +2282,9 @@ static short snapObject( break; case OB_GPENCIL: retval = snapEmpty( - snapdata, ob, obmat, - dist_px, - r_loc, r_no, r_index); + snapdata, ob, obmat, + dist_px, + r_loc, r_no, r_index); break; case OB_CAMERA: retval = snapCamera( diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h index ca941017ff9..73386601d10 100644 --- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h +++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h @@ -15,17 +15,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor(s): Ben Batt - * * ***** END GPL LICENSE BLOCK ***** */ -/** \file MOD_modifiertypes.h +/** \file MOD_gpencil_modifiertypes.h * \ingroup modifiers */ -#ifndef __MOD_GP_MODIFIERTYPES_H__ -#define __MOD_GP_MODIFIERTYPES_H__ +#ifndef __MOD_GPENCIL_MODIFIERTYPES_H__ +#define __MOD_GPENCIL_MODIFIERTYPES_H__ #include "BKE_gpencil_modifier.h" @@ -50,4 +48,4 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Offset; /* MOD_gpencil_util.c */ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]); -#endif /* __MOD_GP_MODIFIERTYPES_H__ */ +#endif /* __MOD_GPENCIL_MODIFIERTYPES_H__ */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 97d28863095..664f4b6976c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -23,7 +23,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/modifiers/intern/MOD_gpencil_util.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencil_util.c * \ingroup bke */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index 50ac557042d..39a4947573e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/modifiers/intern/MOD_gpencil_util.h +/** \file blender/gpencil_modifiers/intern/MOD_gpencil_util.h * \ingroup modifiers */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index 6b959659a60..945afec002d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilbuild.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilbuild.c * \ingroup modifiers */ @@ -519,7 +519,7 @@ static void generateStrokes( */ #if 0 static void bakeModifier( - Main *bmain, const Depsgraph *UNUSED(depsgraph), + Main *bmain, const Depsgraph *UNUSED(depsgraph), GpencilModifierData *md, Object *ob) { bGPdata *gpd = ob->data; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index af00b24715f..3cd298e9b87 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilcolor.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilcolor.c * \ingroup modifiers */ @@ -98,7 +98,7 @@ static void deformStroke( } static void bakeModifier( - Main *bmain, Depsgraph *depsgraph, + Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index e036b6b78be..40e5e718bdc 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilhook.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilhook.c * \ingroup modifiers */ @@ -265,7 +265,7 @@ static void deformStroke( * (i.e. one where we don't have to worry about restoring state) */ static void bakeModifier( - Main *bmain, Depsgraph *depsgraph, + Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { HookGpencilModifierData *mmd = (HookGpencilModifierData *)md; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c index 64f3fbc4a95..a35174d882f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilinstance.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilinstance.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilinstance.c * \ingroup modifiers */ @@ -320,7 +320,7 @@ static void generateStrokes( /* Generic "bakeModifier" callback */ static void bakeModifier( - Main *bmain, Depsgraph *depsgraph, + Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { InstanceGpencilModifierData *mmd = (InstanceGpencilModifierData *)md; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 944e787020e..c4ff44af927 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencillattice.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencillattice.c * \ingroup modifiers */ @@ -111,7 +111,7 @@ static void deformStroke( * (i.e. one where we don't have to worry about restoring state) */ static void bakeModifier( - Main *bmain, Depsgraph *depsgraph, + Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 9b5186755d6..afecdd34a5c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilmirror.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilmirror.c * \ingroup modifiers */ @@ -142,9 +142,9 @@ static void generateStrokes( tot_strokes = BLI_listbase_count(&gpf->strokes); for (i = 0, gps = gpf->strokes.first; i < tot_strokes; i++, gps = gps->next) { - if (is_stroke_affected_by_modifier(ob, - mmd->layername, mmd->pass_index, 1, gpl, gps, - mmd->flag & GP_MIRROR_INVERT_LAYER, mmd->flag & GP_MIRROR_INVERT_PASS)) + if (is_stroke_affected_by_modifier( + ob, mmd->layername, mmd->pass_index, 1, gpl, gps, + mmd->flag & GP_MIRROR_INVERT_LAYER, mmd->flag & GP_MIRROR_INVERT_PASS)) { /* check each axis for mirroring */ for (int xi = 0; xi < 3; ++xi) { @@ -162,7 +162,7 @@ static void generateStrokes( } static void bakeModifier( - Main *bmain, Depsgraph *depsgraph, + Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 37c8bf0b0f0..1edcaf84b81 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilnoise.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilnoise.c * \ingroup modifiers */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 8a96c705f08..50ff3f8766a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpenciloffset.c +/** \file blender/gpencil_modifiers/intern/MOD_gpenciloffset.c * \ingroup modifiers */ @@ -105,7 +105,7 @@ static void deformStroke( } static void bakeModifier( - struct Main *UNUSED(bmain), Depsgraph *depsgraph, + struct Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { bGPdata *gpd = ob->data; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index bdd651a69fc..361668f8725 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilopacity.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilopacity.c * \ingroup modifiers */ @@ -81,7 +81,7 @@ static void deformStroke( return; } - gp_style->fill_rgba[3]*= mmd->factor; + gp_style->fill_rgba[3] *= mmd->factor; /* if factor is > 1, then force opacity */ if (mmd->factor > 1.0f) { @@ -133,7 +133,7 @@ static void deformStroke( } static void bakeModifier( - struct Main *UNUSED(bmain), Depsgraph *depsgraph, + struct Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { bGPdata *gpd = ob->data; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index f0400e39b73..a8d10c973ce 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -23,7 +23,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilsimplify.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c * \ingroup modifiers */ @@ -85,7 +85,7 @@ static void deformStroke( } static void bakeModifier( - struct Main *UNUSED(bmain), Depsgraph *depsgraph, + struct Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { bGPdata *gpd = ob->data; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index b83c8ed98b1..182bd974959 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilsmooth.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c * \ingroup modifiers */ @@ -114,7 +114,7 @@ static void deformStroke( } static void bakeModifier( - struct Main *UNUSED(bmain), Depsgraph *depsgraph, + struct Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { bGPdata *gpd = ob->data; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index 6fe9c34c06b..dba3e028904 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilsubdiv.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c * \ingroup modifiers */ @@ -155,7 +155,7 @@ static void deformStroke( } static void bakeModifier( - struct Main *UNUSED(bmain), Depsgraph *depsgraph, + struct Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { bGPdata *gpd = ob->data; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index 118cc33255f..fb63aa31364 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpencilthick.c +/** \file blender/gpencil_modifiers/intern/MOD_gpencilthick.c * \ingroup modifiers */ @@ -133,7 +133,7 @@ static void deformStroke( } static void bakeModifier( - struct Main *UNUSED(bmain), Depsgraph *depsgraph, + struct Main *UNUSED(bmain), Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { bGPdata *gpd = ob->data; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 9d1e9eccb8c..859e12adfb5 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -24,7 +24,7 @@ * */ -/** \file blender/modifiers/intern/MOD_gpenciltint.c +/** \file blender/gpencil_modifiers/intern/MOD_gpenciltint.c * \ingroup modifiers */ @@ -106,7 +106,7 @@ static void deformStroke( } static void bakeModifier( - Main *bmain, Depsgraph *depsgraph, + Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 150b4a2d9f1..1e3a4bf09f0 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -18,12 +18,12 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file DNA_greasepencil_modifier_types.h +/** \file DNA_gpencil_modifier_types.h * \ingroup DNA */ -#ifndef __DNA_GREASEPENCIL_TYPES_H__ -#define __DNA_GREASEPENCIL_TYPES_H__ +#ifndef __DNA_GPENCIL_MODIFIER_TYPES_H__ +#define __DNA_GPENCIL_MODIFIER_TYPES_H__ #include "DNA_defs.h" #include "DNA_listBase.h" @@ -401,4 +401,4 @@ typedef enum eSmoothGpencil_Flag { #define MOD_MESHSEQ_READ_ALL \ (MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR) -#endif /* __DNA_GREASEPENCIL_TYPES_H__ */ +#endif /* __DNA_GPENCIL_MODIFIER_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h index 15147cf2b6c..f3c9f06c8dc 100644 --- a/source/blender/makesdna/DNA_shader_fx_types.h +++ b/source/blender/makesdna/DNA_shader_fx_types.h @@ -22,8 +22,8 @@ * \ingroup DNA */ -#ifndef __DNA_SHADERFX_TYPES_H__ -#define __DNA_SHADERFX_TYPES_H__ +#ifndef __DNA_SHADER_FX_TYPES_H__ +#define __DNA_SHADER_FX_TYPES_H__ #include "DNA_defs.h" #include "DNA_listBase.h" @@ -130,7 +130,7 @@ typedef struct LightShaderFxData { int flag; /* flags */ float energy; float ambient; - float loc[4]; /* internal, not visible in rna */ + float loc[4]; /* internal, not visible in rna */ char pad[4]; ShaderFxData_runtime runtime; } LightShaderFxData; @@ -193,4 +193,4 @@ typedef struct WaveShaderFxData { char pad[4]; ShaderFxData_runtime runtime; } WaveShaderFxData; -#endif /* __DNA_SHADERFX_TYPES_H__ */ +#endif /* __DNA_SHADER_FX_TYPES_H__ */ diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index f84f31b02f1..4b69a395ab6 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -32,6 +32,7 @@ #include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_brush_types.h" +#include "DNA_object_types.h" #include "MEM_guardedalloc.h" @@ -47,9 +48,6 @@ #include "rna_internal.h" #include "WM_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "ED_gpencil.h" /* parent type */ static const EnumPropertyItem parent_type_items[] = { @@ -77,7 +75,6 @@ static EnumPropertyItem rna_enum_gpencil_onion_modes_items[] = { #ifdef RNA_RUNTIME -#include "BLI_math.h" #include "BLI_ghash.h" #include "WM_api.h" diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index df64121b2b4..8c4edf8030c 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -50,7 +50,6 @@ #include "BKE_mesh_remap.h" #include "BKE_multires.h" #include "BKE_smoke.h" /* For smokeModifier_free & smokeModifier_createType */ -#include "BKE_gpencil_modifier.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index 950aef9a8dd..a005699dc32 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -38,7 +38,6 @@ #include "BLT_translation.h" #include "BKE_animsys.h" -#include "BKE_shader_fx.h" #include "RNA_access.h" #include "RNA_define.h" -- cgit v1.2.3 From 20d525eb8bcc0652e9776c333b77df6ae9f842cd Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 12:37:58 +0200 Subject: Fix assert when load file with shading enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Credits for this fix goes to Clément Foucault. --- source/blender/draw/engines/gpencil/gpencil_engine.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'source') diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index d81cf8b7752..0c76971ac4b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -92,9 +92,6 @@ void DRW_gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h GPU_ATTACHMENT_TEXTURE(txl->multisample_depth), GPU_ATTACHMENT_TEXTURE(txl->multisample_color) }); - if (!GPU_framebuffer_check_valid(fbl->multisample_fb, NULL)) { - GPU_framebuffer_free(fbl->multisample_fb); - } } } } -- cgit v1.2.3 From 0b85bb847c06b2115f135f82bce7bd762354acd4 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 12:38:44 +0200 Subject: Cleanup: Remove overflow array element --- source/blender/shader_fx/intern/FX_shader_rim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/shader_fx/intern/FX_shader_rim.c b/source/blender/shader_fx/intern/FX_shader_rim.c index 611e6f91bf7..bea6f645033 100644 --- a/source/blender/shader_fx/intern/FX_shader_rim.c +++ b/source/blender/shader_fx/intern/FX_shader_rim.c @@ -40,8 +40,8 @@ static void initData(ShaderFxData *fx) { RimShaderFxData *gpfx = (RimShaderFxData *)fx; ARRAY_SET_ITEMS(gpfx->offset, 50, -100); - ARRAY_SET_ITEMS(gpfx->rim_rgb, 1.0f, 1.0f, 0.5f, 0.9f); - ARRAY_SET_ITEMS(gpfx->mask_rgb, 0.0f, 0.0f, 0.0f, 1.0f); + ARRAY_SET_ITEMS(gpfx->rim_rgb, 1.0f, 1.0f, 0.5f); + ARRAY_SET_ITEMS(gpfx->mask_rgb, 0.0f, 0.0f, 0.0f); gpfx->mode = eShaderFxRimMode_Multiply; ARRAY_SET_ITEMS(gpfx->blur, 0, 0); } -- cgit v1.2.3 From f945303877e65999fbae7a37ba5a223367259396 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 12:44:01 +0200 Subject: Cleanup: Fix weird comparisons --- source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c | 2 +- source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c | 2 +- source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c | 2 +- source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c | 2 +- source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c | 4 ++-- source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c | 2 +- source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) (limited to 'source') diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index 40e5e718bdc..46d452545e2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -253,7 +253,7 @@ static void deformStroke( MDeformVert *dvert = &gps->dvert[i]; /* verify vertex group */ - weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_HOOK_INVERT_VGROUP) == 0), vindex); + weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_HOOK_INVERT_VGROUP) != 0), vindex); if (weight < 0) { continue; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index c4ff44af927..33bdb9c861d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -98,7 +98,7 @@ static void deformStroke( MDeformVert *dvert = &gps->dvert[i]; /* verify vertex group */ - weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_LATTICE_INVERT_VGROUP) == 0), vindex); + weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_LATTICE_INVERT_VGROUP) != 0), vindex); if (weight < 0) { continue; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 1edcaf84b81..be361498578 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -154,7 +154,7 @@ static void deformStroke( } /* verify vertex group */ - weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_NOISE_INVERT_VGROUP) == 0), vindex); + weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_NOISE_INVERT_VGROUP) != 0), vindex); if (weight < 0) { continue; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 50ff3f8766a..a31f889c48a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -89,7 +89,7 @@ static void deformStroke( MDeformVert *dvert = &gps->dvert[i]; /* verify vertex group */ - float weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_OFFSET_INVERT_VGROUP) == 0), vindex); + float weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_OFFSET_INVERT_VGROUP) != 0), vindex); if (weight < 0) { continue; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index 361668f8725..74b24acdfb6 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -101,7 +101,7 @@ static void deformStroke( MDeformVert *dvert = &gps->dvert[i]; /* verify vertex group */ - float weight = get_modifier_point_weight(dvert, (!(mmd->flag & GP_OPACITY_INVERT_VGROUP) == 0), vindex); + float weight = get_modifier_point_weight(dvert, ((mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0), vindex); if (weight < 0) { pt->strength += mmd->factor - 1.0f; } @@ -121,7 +121,7 @@ static void deformStroke( pt->strength *= mmd->factor; } else { - float weight = get_modifier_point_weight(dvert, (!(mmd->flag & GP_OPACITY_INVERT_VGROUP) == 0), vindex); + float weight = get_modifier_point_weight(dvert, ((mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0), vindex); if (weight >= 0) { pt->strength *= mmd->factor * weight; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index 182bd974959..b5f2f0349af 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -86,7 +86,7 @@ static void deformStroke( MDeformVert *dvert = &gps->dvert[i]; /* verify vertex group */ - weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_SMOOTH_INVERT_VGROUP) == 0), vindex); + weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_SMOOTH_INVERT_VGROUP) != 0), vindex); if (weight < 0) { continue; } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index fb63aa31364..2c01fec1357 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -111,7 +111,7 @@ static void deformStroke( MDeformVert *dvert = &gps->dvert[i]; float curvef = 1.0f; /* verify vertex group */ - float weight = get_modifier_point_weight(dvert, (int)(!(mmd->flag & GP_THICK_INVERT_VGROUP) == 0), vindex); + float weight = get_modifier_point_weight(dvert, (int)((mmd->flag & GP_THICK_INVERT_VGROUP) != 0), vindex); if (weight < 0) { continue; } -- cgit v1.2.3 From 31fcd40efd3a98113cec837282c6dd2e1d34caa1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 20:44:49 +1000 Subject: Cleanup: use static variables --- source/blender/blenkernel/BKE_studiolight.h | 2 +- source/blender/blenkernel/intern/DerivedMesh.c | 1 + .../blender/blenkernel/intern/blender_user_menu.c | 1 + source/blender/draw/intern/draw_anim_viz.c | 4 ++- source/blender/draw/intern/draw_armature.c | 2 +- source/blender/draw/intern/draw_cache.c | 32 ++++++++++++---------- source/blender/draw/intern/draw_manager.c | 2 +- source/blender/editors/gpencil/drawgpencil.c | 2 +- .../blender/editors/interface/interface_intern.h | 2 +- .../blender/editors/interface/interface_widgets.c | 2 +- source/blender/editors/mesh/editmesh_extrude.c | 10 +++---- source/blender/editors/space_node/drawnode.c | 2 +- .../editors/space_view3d/view3d_gizmo_navigate.c | 2 +- .../blender/editors/transform/transform_gizmo_3d.c | 2 +- source/blender/makesrna/intern/rna_context.c | 1 + source/blender/makesrna/intern/rna_rigidbody.c | 2 +- source/blender/makesrna/intern/rna_sculpt_paint.c | 4 +-- source/blender/makesrna/intern/rna_shader_fx.c | 4 +-- source/blender/makesrna/intern/rna_space.c | 2 +- .../windowmanager/gizmo/intern/wm_gizmo_group.c | 2 -- 20 files changed, 43 insertions(+), 38 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_studiolight.h b/source/blender/blenkernel/BKE_studiolight.h index fee01fa8abb..4a7f29d7190 100644 --- a/source/blender/blenkernel/BKE_studiolight.h +++ b/source/blender/blenkernel/BKE_studiolight.h @@ -99,7 +99,7 @@ enum StudioLightFlag { STUDIOLIGHT_EQUIRECTANGULAR_IRRADIANCE_GPUTEXTURE = (1 << 10), STUDIOLIGHT_RADIANCE_BUFFERS_CALCULATED = (1 << 11), STUDIOLIGHT_UI_EXPANDED = (1 << 13), -} StudioLightFlag; +}; #define STUDIOLIGHT_FLAG_ALL (STUDIOLIGHT_INTERNAL | STUDIOLIGHT_EXTERNAL_FILE) #define STUDIOLIGHT_FLAG_ORIENTATIONS (STUDIOLIGHT_ORIENTATION_CAMERA | STUDIOLIGHT_ORIENTATION_WORLD | STUDIOLIGHT_ORIENTATION_VIEWNORMAL) diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 9c4aae7cda5..05253f7962a 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -2098,6 +2098,7 @@ static void mesh_calc_modifiers( /* XXX: Is build_shapekey_layers ever even true? This should have crashed long ago... */ BLI_assert(!build_shapekey_layers); + UNUSED_VARS_NDEBUG(build_shapekey_layers); //if (build_shapekey_layers) // add_shapekey_layers(*r_deform_mesh, me, ob); diff --git a/source/blender/blenkernel/intern/blender_user_menu.c b/source/blender/blenkernel/intern/blender_user_menu.c index 3ec46e23cd1..2c18de70e6d 100644 --- a/source/blender/blenkernel/intern/blender_user_menu.c +++ b/source/blender/blenkernel/intern/blender_user_menu.c @@ -89,6 +89,7 @@ bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type) size = sizeof(bUserMenuItem_Prop); } else { + size = sizeof(bUserMenuItem); BLI_assert(0); } diff --git a/source/blender/draw/intern/draw_anim_viz.c b/source/blender/draw/intern/draw_anim_viz.c index f976c7b4d05..7ddcb306cea 100644 --- a/source/blender/draw/intern/draw_anim_viz.c +++ b/source/blender/draw/intern/draw_anim_viz.c @@ -90,10 +90,12 @@ typedef struct MPATH_Data { MPATH_StorageList *stl; } MPATH_Data; -struct { +#if 0 +static struct { GPUShader *mpath_line_sh; GPUShader *mpath_points_sh; } e_data = {0}; +#endif /* *************************** Path Cache *********************************** */ diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 8cd7431cfc0..a84b3fdeb41 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -460,7 +460,7 @@ static void drw_shgroup_bone_ik_spline_lines(const float start[3], const float e * \{ */ /* global here is reset before drawing each bone */ -struct { +static struct { const ThemeWireColor *bcolor; } g_color; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index ac84a847a1b..8ef5d600413 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -242,13 +242,15 @@ static GPUVertBuf *sphere_wire_vbo(const float rad) cv[0] = p[(i + j) % NSEGMENTS][0]; cv[1] = p[(i + j) % NSEGMENTS][1]; - if (axis == 0) - v[0] = cv[0], v[1] = cv[1], v[2] = 0.0f; - else if (axis == 1) - v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; - else - v[0] = 0.0f, v[1] = cv[0], v[2] = cv[1]; - + if (axis == 0) { + ARRAY_SET_ITEMS(v, cv[0], cv[1], 0.0f); + } + else if (axis == 1) { + ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]); + } + else { + ARRAY_SET_ITEMS(v, 0.0f, cv[0], cv[1]); + } GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 2 + j + (NSEGMENTS * 2 * axis), v); } } @@ -825,17 +827,17 @@ GPUBatch *DRW_cache_empty_cone_get(void) cv[1] = p[(i) % NSEGMENTS][1]; /* cone sides */ - v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v); - v[0] = 0.0f, v[1] = 2.0f, v[2] = 0.0f; + ARRAY_SET_ITEMS(v, 0.0f, 2.0f, 0.0f); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v); /* end ring */ - v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v); cv[0] = p[(i + 1) % NSEGMENTS][0]; cv[1] = p[(i + 1) % NSEGMENTS][1]; - v[0] = cv[0], v[1] = 0.0f, v[2] = cv[1]; + ARRAY_SET_ITEMS(v, cv[0], 0.0f, cv[1]); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v); } @@ -1578,9 +1580,9 @@ GPUBatch *DRW_cache_lamp_spot_get(void) cv[1] = p[i % NSEGMENTS][1]; /* cone sides */ - v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f; + ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4, v); - v[0] = 0.0f, v[1] = 0.0f, v[2] = 0.0f; + ARRAY_SET_ITEMS(v, 0.0f, 0.0f, 0.0f); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 1, v); GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4, n[(i) % NSEGMENTS]); @@ -1589,11 +1591,11 @@ GPUBatch *DRW_cache_lamp_spot_get(void) GPU_vertbuf_attr_set(vbo, attr_id.n2, i * 4 + 1, n[(i + 1) % NSEGMENTS]); /* end ring */ - v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f; + ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 2, v); cv[0] = p[(i + 1) % NSEGMENTS][0]; cv[1] = p[(i + 1) % NSEGMENTS][1]; - v[0] = cv[0], v[1] = cv[1], v[2] = -1.0f; + ARRAY_SET_ITEMS(v, cv[0], cv[1], -1.0f); GPU_vertbuf_attr_set(vbo, attr_id.pos, i * 4 + 3, v); GPU_vertbuf_attr_set(vbo, attr_id.n1, i * 4 + 2, n[(i) % NSEGMENTS]); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index e6e20934283..159f69d3226 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -95,7 +95,7 @@ /** Render State: No persistent data between draw calls. */ DRWManager DST = {NULL}; -ListBase DRW_engines = {NULL, NULL}; +static ListBase DRW_engines = {NULL, NULL}; extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */ diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 2c0b3e9900a..180fb65e743 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -574,7 +574,7 @@ static void gp_add_filldata_tobuffer( mul_v3_m4v3(fpt, diff_mat, &pt->x); /* if 2d, need conversion */ - if (!flag & GP_STROKE_3DSPACE) { + if (!(flag & GP_STROKE_3DSPACE)) { gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co); copy_v2_v2(fpt, co); fpt[2] = 0.0f; /* 2d always is z=0.0f */ diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index d4fccc48bfc..f7507223f31 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -780,7 +780,7 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na #define UI_POPUP_MENU_TOP (int)(8 * UI_DPI_FAC) #define UI_PIXEL_AA_JITTER 8 -const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2]; +extern const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2]; /* interface_style.c */ void uiStyleInit(void); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 52e6e237a58..d0cdba49536 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1083,7 +1083,7 @@ static void widgetbase_set_uniform_colors_ubv( #define MAX_WIDGET_BASE_BATCH 6 #define MAX_WIDGET_PARAMETERS 11 -struct { +static struct { GPUBatch *batch; /* Batch type */ uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]; int count; diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 061cc3ebc32..c5ef2a06059 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -365,11 +365,11 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) #ifdef USE_GIZMO -const float extrude_button_scale = 0.15f; -const float extrude_button_offset_scale = 1.5f; -const float extrude_arrow_scale = 1.0f; -const float extrude_arrow_xyz_axis_scale = 1.0f; -const float extrude_arrow_normal_axis_scale = 1.75f; +static const float extrude_button_scale = 0.15f; +static const float extrude_button_offset_scale = 1.5f; +static const float extrude_arrow_scale = 1.0f; +static const float extrude_arrow_xyz_axis_scale = 1.0f; +static const float extrude_arrow_normal_axis_scale = 1.75f; static const uchar shape_plus[] = { 0x5f, 0xfb, 0x40, 0xee, 0x25, 0xda, 0x11, 0xbf, 0x4, 0xa0, 0x0, 0x80, 0x4, 0x5f, 0x11, diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index f284fa015b8..a48a6faf69f 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3422,7 +3422,7 @@ bool node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, flo static float arrow_verts[3][2] = {{-1.0f, 1.0f}, {0.0f, 0.0f}, {-1.0f, -1.0f}}; static float arrow_expand_axis[3][2] = {{0.7071f, 0.7071f}, {M_SQRT2, 0.0f}, {0.7071f, -0.7071f}}; -struct { +static struct { GPUBatch *batch; /* for batching line together */ GPUBatch *batch_single; /* for single line */ GPUVertBuf *inst_vbo; diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c index 388d9a29eff..5778f85a99c 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c @@ -131,7 +131,7 @@ struct NavigateGizmoInfo { #define SHAPE_VARS(shape_id) shape = shape_id, .shape_size = ARRAY_SIZE(shape_id) -struct NavigateGizmoInfo g_navigate_params[MPR_TOTAL] = { +static struct NavigateGizmoInfo g_navigate_params[MPR_TOTAL] = { { .opname = "VIEW3D_OT_move", .gizmo = "GIZMO_GT_button_2d", diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 3b5d7d5871a..83dfa06f37d 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -107,7 +107,7 @@ #define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z) /* threshold for testing view aligned gizmo axis */ -struct { +static struct { float min, max; } g_tw_axis_range[2] = { /* Regular range */ diff --git a/source/blender/makesrna/intern/rna_context.c b/source/blender/makesrna/intern/rna_context.c index 781be07f1dc..618cefe13e5 100644 --- a/source/blender/makesrna/intern/rna_context.c +++ b/source/blender/makesrna/intern/rna_context.c @@ -34,6 +34,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" /* own include */ diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 47075d0d4f7..899439e1a02 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -77,7 +77,7 @@ const EnumPropertyItem rna_enum_rigidbody_constraint_type_items[] = { {0, NULL, 0, NULL, NULL}}; /* bullet spring type */ -const EnumPropertyItem rna_enum_rigidbody_constraint_spring_type_items[] = { +static const EnumPropertyItem rna_enum_rigidbody_constraint_spring_type_items[] = { {RBC_SPRING_TYPE1, "SPRING1", ICON_NONE, "Blender 2.7", "Spring implementation used in blender 2.7. Damping is capped at 1.0"}, {RBC_SPRING_TYPE2, "SPRING2", ICON_NONE, "Blender 2.8", "New implementation available since 2.8"}, {0, NULL, 0, NULL, NULL}}; diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 6a6c97b41ad..1f8f95cf380 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -76,12 +76,12 @@ const EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = { { 0, NULL, 0, NULL, NULL } }; -EnumPropertyItem rna_enum_gpencil_weight_brush_items[] = { +#ifndef RNA_RUNTIME +static EnumPropertyItem rna_enum_gpencil_weight_brush_items[] = { { GP_EDITBRUSH_TYPE_WEIGHT, "WEIGHT", ICON_GPBRUSH_WEIGHT, "Weight", "Weight Paint for Vertex Groups" }, { 0, NULL, 0, NULL, NULL } }; -#ifndef RNA_RUNTIME static const EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = { { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", ICON_UNLOCKED, "None", "" }, { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", ICON_NDOF_DOM, "X", "Project strokes to plane locked to X" }, diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index a005699dc32..da4470ccff7 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -60,7 +60,7 @@ const EnumPropertyItem rna_enum_object_shaderfx_type_items[] = { {0, NULL, 0, NULL, NULL} }; -const EnumPropertyItem rna_enum_shaderfx_rim_modes_items[] = { +static const EnumPropertyItem rna_enum_shaderfx_rim_modes_items[] = { {eShaderFxRimMode_Normal, "NORMAL", 0, "Normal", "" }, {eShaderFxRimMode_Overlay, "OVERLAY", 0, "Overlay", "" }, {eShaderFxRimMode_Add, "ADD", 0, "Add", "" }, @@ -70,7 +70,7 @@ const EnumPropertyItem rna_enum_shaderfx_rim_modes_items[] = { {0, NULL, 0, NULL, NULL } }; -const EnumPropertyItem rna_enum_shaderfx_colorize_modes_items[] = { +static const EnumPropertyItem rna_enum_shaderfx_colorize_modes_items[] = { {eShaderFxColorizeMode_GrayScale, "GRAYSCALE", 0, "Gray Scale", "" }, {eShaderFxColorizeMode_Sepia, "SEPIA", 0, "Sepia", "" }, {eShaderFxColorizeMode_BiTone, "BITONE", 0, "Bi-Tone", "" }, diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 56491fd70e4..ab662e71380 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -244,7 +244,7 @@ const EnumPropertyItem rna_enum_shading_type_items[] = { {0, NULL, 0, NULL, NULL} }; -const EnumPropertyItem rna_enum_viewport_lighting_items[] = { +static const EnumPropertyItem rna_enum_viewport_lighting_items[] = { {V3D_LIGHTING_FLAT, "FLAT", 0, "Flat", "Display using flat lighting"}, {V3D_LIGHTING_STUDIO, "STUDIO", 0, "Studio", "Display using studio lighting"}, {V3D_LIGHTING_MATCAP, "MATCAP", 0, "MatCap", "Display using matcap material and lighting"}, diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c index 9cc096e1cdd..204662b5713 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c @@ -296,8 +296,6 @@ static int gizmo_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE BLI_assert(0); return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); } - - return OPERATOR_PASS_THROUGH; } void GIZMOGROUP_OT_gizmo_select(wmOperatorType *ot) -- cgit v1.2.3 From 7a91ae110397c29a5bb63ed0489d67acdc11ecb4 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 13:21:04 +0200 Subject: Fix memory leak in DRW_cache_gpencil_axes_get The Batch was created using old function without GPU_BATCH_OWNS_VBO and the batch was not removed from memory --- source/blender/draw/intern/draw_cache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 8ef5d600413..c3fa9f5c1aa 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -605,7 +605,7 @@ GPUBatch *DRW_cache_gpencil_axes_get(void) GPU_vertbuf_attr_set(vbo, pos_id, i + 6, verts[indices[i]]); } - SHC.drw_gpencil_axes = GPU_batch_create(GPU_PRIM_LINES, vbo, NULL); + SHC.drw_gpencil_axes = GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO); } return SHC.drw_gpencil_axes; } -- cgit v1.2.3 From bb7b1cc884819d2a681f1c93b6bb9c015248aff0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 31 Jul 2018 13:23:01 +0200 Subject: Fix T56170: Fake dependency cycle in new depsgraph + interleaved armature update + proxy Make proxy copy result more atomic operation. --- source/blender/blenkernel/BKE_action.h | 1 + source/blender/blenkernel/BKE_armature.h | 11 +++- source/blender/blenkernel/intern/action.c | 61 ++++++++++---------- source/blender/blenkernel/intern/armature_update.c | 65 +++++++++++++++++----- .../intern/builder/deg_builder_nodes_rig.cc | 17 ++++-- .../intern/builder/deg_builder_relations.cc | 4 -- .../intern/builder/deg_builder_relations_rig.cc | 9 +++ 7 files changed, 117 insertions(+), 51 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index 106866aff0a..263a54eab4e 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -201,6 +201,7 @@ void BKE_pose_remove_group_index(struct bPose *pose, const int index); void what_does_obaction(struct Object *ob, struct Object *workob, struct bPose *pose, struct bAction *act, char groupname[], float cframe); /* for proxy */ +void BKE_pose_copyesult_pchan_result(struct bPoseChannel *pchanto, const struct bPoseChannel *pchanfrom); bool BKE_pose_copy_result(struct bPose *to, struct bPose *from); /* clear all transforms */ void BKE_pose_rest(struct bPose *pose); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 9e100eb9111..17329beb325 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -231,9 +231,16 @@ void BKE_pose_eval_flush( struct Scene *scene, struct Object *ob); -void BKE_pose_eval_proxy_copy( +void BKE_pose_eval_proxy_pose_init(struct Depsgraph *depsgraph, + struct Object *object); + +void BKE_pose_eval_proxy_pose_done(struct Depsgraph *depsgraph, + struct Object *object); + +void BKE_pose_eval_proxy_copy_bone( struct Depsgraph *depsgraph, - struct Object *ob); + struct Object *object, + int pchan_index); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index cbdabe2c440..6f97187f1e3 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1328,6 +1328,37 @@ void BKE_pose_rest(bPose *pose) } } +void BKE_pose_copyesult_pchan_result(bPoseChannel *pchanto, const bPoseChannel *pchanfrom) +{ + copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat); + copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat); + + /* used for local constraints */ + copy_v3_v3(pchanto->loc, pchanfrom->loc); + copy_qt_qt(pchanto->quat, pchanfrom->quat); + copy_v3_v3(pchanto->eul, pchanfrom->eul); + copy_v3_v3(pchanto->size, pchanfrom->size); + + copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head); + copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail); + + pchanto->roll1 = pchanfrom->roll1; + pchanto->roll2 = pchanfrom->roll2; + pchanto->curveInX = pchanfrom->curveInX; + pchanto->curveInY = pchanfrom->curveInY; + pchanto->curveOutX = pchanfrom->curveOutX; + pchanto->curveOutY = pchanfrom->curveOutY; + pchanto->ease1 = pchanfrom->ease1; + pchanto->ease2 = pchanfrom->ease2; + pchanto->scaleIn = pchanfrom->scaleIn; + pchanto->scaleOut = pchanfrom->scaleOut; + + pchanto->rotmode = pchanfrom->rotmode; + pchanto->flag = pchanfrom->flag; + pchanto->protectflag = pchanfrom->protectflag; + pchanto->bboneflag = pchanfrom->bboneflag; +} + /* both poses should be in sync */ bool BKE_pose_copy_result(bPose *to, bPose *from) { @@ -1346,34 +1377,8 @@ bool BKE_pose_copy_result(bPose *to, bPose *from) for (pchanfrom = from->chanbase.first; pchanfrom; pchanfrom = pchanfrom->next) { pchanto = BKE_pose_channel_find_name(to, pchanfrom->name); - if (pchanto) { - copy_m4_m4(pchanto->pose_mat, pchanfrom->pose_mat); - copy_m4_m4(pchanto->chan_mat, pchanfrom->chan_mat); - - /* used for local constraints */ - copy_v3_v3(pchanto->loc, pchanfrom->loc); - copy_qt_qt(pchanto->quat, pchanfrom->quat); - copy_v3_v3(pchanto->eul, pchanfrom->eul); - copy_v3_v3(pchanto->size, pchanfrom->size); - - copy_v3_v3(pchanto->pose_head, pchanfrom->pose_head); - copy_v3_v3(pchanto->pose_tail, pchanfrom->pose_tail); - - pchanto->roll1 = pchanfrom->roll1; - pchanto->roll2 = pchanfrom->roll2; - pchanto->curveInX = pchanfrom->curveInX; - pchanto->curveInY = pchanfrom->curveInY; - pchanto->curveOutX = pchanfrom->curveOutX; - pchanto->curveOutY = pchanfrom->curveOutY; - pchanto->ease1 = pchanfrom->ease1; - pchanto->ease2 = pchanfrom->ease2; - pchanto->scaleIn = pchanfrom->scaleIn; - pchanto->scaleOut = pchanfrom->scaleOut; - - pchanto->rotmode = pchanfrom->rotmode; - pchanto->flag = pchanfrom->flag; - pchanto->protectflag = pchanfrom->protectflag; - pchanto->bboneflag = pchanfrom->bboneflag; + if (pchanto != NULL) { + BKE_pose_copyesult_pchan_result(pchanto, pchanfrom); } } return true; diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 03d370f6e7c..d53c61255fe 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -558,6 +558,17 @@ void BKE_splineik_execute_tree( /* *************** Depsgraph evaluation callbacks ************ */ +static void pose_pchan_index_create(bPose *pose) +{ + const int num_channels = BLI_listbase_count(&pose->chanbase); + pose->chan_array = MEM_malloc_arrayN( + num_channels, sizeof(bPoseChannel *), "pose->chan_array"); + int pchan_index = 0; + for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + pose->chan_array[pchan_index++] = pchan; + } +} + BLI_INLINE bPoseChannel *pose_pchan_get_indexed(Object *ob, int pchan_index) { bPose *pose = ob->pose; @@ -585,16 +596,12 @@ void BKE_pose_eval_init(struct Depsgraph *depsgraph, /* imat is needed for solvers. */ invert_m4_m4(ob->imat, ob->obmat); - const int num_channels = BLI_listbase_count(&pose->chanbase); - pose->chan_array = MEM_malloc_arrayN( - num_channels, sizeof(bPoseChannel *), "pose->chan_array"); - /* clear flags */ - int pchan_index = 0; for (bPoseChannel *pchan = pose->chanbase.first; pchan != NULL; pchan = pchan->next) { pchan->flag &= ~(POSE_DONE | POSE_CHAIN | POSE_IKTREE | POSE_IKSPLINE); - pose->chan_array[pchan_index++] = pchan; } + + pose_pchan_index_create(pose); } void BKE_pose_eval_init_ik(struct Depsgraph *depsgraph, @@ -752,12 +759,44 @@ void BKE_pose_eval_flush(struct Depsgraph *depsgraph, pose->chan_array = NULL; } -void BKE_pose_eval_proxy_copy(struct Depsgraph *depsgraph, Object *ob) +void BKE_pose_eval_proxy_pose_init(struct Depsgraph *depsgraph, Object *object) { - BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL); - DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); - if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { - printf("Proxy copy error, lib Object: %s proxy Object: %s\n", - ob->id.name + 2, ob->proxy_from->id.name + 2); - } + BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + + pose_pchan_index_create(object->pose); +} + +void BKE_pose_eval_proxy_pose_done(struct Depsgraph *depsgraph, Object *object) +{ + BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + + bPose *pose = object->pose; + BLI_assert(pose->chan_array != NULL); + MEM_freeN(pose->chan_array); + pose->chan_array = NULL; +} + +void BKE_pose_eval_proxy_copy_bone( + struct Depsgraph *depsgraph, + Object *object, + int pchan_index) +{ + BLI_assert(ID_IS_LINKED(object) && object->proxy_from != NULL); + DEG_debug_print_eval(depsgraph, __func__, object->id.name, object); + bPoseChannel *pchan = pose_pchan_get_indexed(object, pchan_index); + /* TODO(sergey): Use indexec lookup, once it's guaranteed to be kept + * around for the time while proxies are evaluating. + */ +#if 0 + bPoseChannel *pchan_from = pose_pchan_get_indexed( + object->proxy_from, pchan_index); +#else + bPoseChannel *pchan_from = BKE_pose_channel_find_name( + object->proxy_from->pose, pchan->name); +#endif + BLI_assert(pchan != NULL); + BLI_assert(pchan_from != NULL); + BKE_pose_copyesult_pchan_result(pchan, pchan_from); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 88996dc1f56..b1486e82af5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -314,12 +314,13 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) } op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - function_bind(BKE_pose_eval_proxy_copy, + function_bind(BKE_pose_eval_proxy_pose_init, _1, object_cow), DEG_OPCODE_POSE_INIT); op_node->set_as_entry(); + int pchan_index = 0; LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, @@ -334,10 +335,14 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) NULL, DEG_OPCODE_BONE_READY); /* Bone is fully evaluated. */ - op_node = add_operation_node(&object->id, + op_node = add_operation_node( + &object->id, DEG_NODE_TYPE_BONE, pchan->name, - NULL, + function_bind(BKE_pose_eval_proxy_copy_bone, + _1, + object_cow, + pchan_index), DEG_OPCODE_BONE_DONE); op_node->set_as_exit(); @@ -349,10 +354,14 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object) DEG_OPCODE_PARAMETERS_EVAL, pchan->name); } + + pchan_index++; } op_node = add_operation_node(&object->id, DEG_NODE_TYPE_EVAL_POSE, - NULL, + function_bind(BKE_pose_eval_proxy_pose_done, + _1, + object_cow), DEG_OPCODE_POSE_DONE); op_node->set_as_exit(); } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 1d01b3e987b..4f94066f3bb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -587,10 +587,6 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object) /* Proxy object to copy from. */ if (object->proxy_from != NULL) { build_object(NULL, object->proxy_from); - ComponentKey ob_pose_key(&object->proxy_from->id, DEG_NODE_TYPE_EVAL_POSE); - ComponentKey proxy_pose_key(&object->id, DEG_NODE_TYPE_EVAL_POSE); - add_relation(ob_pose_key, proxy_pose_key, "Proxy Pose"); - ComponentKey ob_transform_key(&object->proxy_from->id, DEG_NODE_TYPE_TRANSFORM); ComponentKey proxy_transform_key(&object->id, DEG_NODE_TYPE_TRANSFORM); add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index eaa17d27ffc..811986ea0e8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -469,11 +469,20 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *object) DEG_NODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + OperationKey from_bone_done_key(&proxy_from->id, + DEG_NODE_TYPE_BONE, + pchan->name, + DEG_OPCODE_BONE_DONE); add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local"); add_relation(bone_local_key, bone_ready_key, "Local -> Ready"); add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done"); + /* Make sure bone in the proxy is not done before it's FROM is done. */ + add_relation(from_bone_done_key, + bone_done_key, + "From Bone Done -> Pose Done"); + if (pchan->prop != NULL) { OperationKey bone_parameters(&object->id, DEG_NODE_TYPE_PARAMETERS, -- cgit v1.2.3 From ddd44315b805aab491c085e478226f916ce03176 Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Tue, 31 Jul 2018 15:13:08 +0200 Subject: UI: Grease Pencil Onion Skin minor tweaks Avoid double label for same properties in single-column. Onion Skinning: Group custom colors together, and frame before/after together. Small changes to tooltips. --- source/blender/makesrna/intern/rna_gpencil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 4b69a395ab6..c4aa90fb61b 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1073,7 +1073,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) /* Onion-Skinning */ prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "onion_flag", GP_LAYER_ONIONSKIN); - RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame"); + RNA_def_property_ui_text(prop, "Onion Skinning", "Display onion skins before and after the current frame"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Flags */ @@ -1303,7 +1303,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) prop = RNA_def_property(srna, "show_constant_thickness", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_KEEPTHICKNESS); - RNA_def_property_ui_text(prop, "Keep thickness", "Show stroke with same thickness when viewport zoom change"); + RNA_def_property_ui_text(prop, "Keep Thickness", "Maintain the thickness of the stroke when the viewport zoom changes"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "pixfactor", PROP_FLOAT, PROP_NONE); -- cgit v1.2.3 From 475e9003c06869df8182e7135fe9459d7309696c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 31 Jul 2018 15:29:51 +0200 Subject: Fix T55718: Blender 2.8 crashes when converting to Curve from Mesh. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only want to care about runtime.mesh_orig if… data is indeed a Mesh! ;) --- .../depsgraph/intern/eval/deg_eval_copy_on_write.cc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'source') diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 22c1167de2a..9ed50fafc3d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -757,7 +757,7 @@ static void deg_restore_object_runtime( Mesh *mesh_orig = object->runtime.mesh_orig; object->runtime = object_runtime_backup->runtime; object->runtime.mesh_orig = mesh_orig; - if (object->runtime.mesh_eval != NULL) { + if (object->type == OB_MESH && object->runtime.mesh_eval != NULL) { if (object->id.recalc & ID_RECALC_GEOMETRY) { /* If geometry is tagged for update it means, that part of * evaluated mesh are not valid anymore. In this case we can not @@ -773,14 +773,12 @@ static void deg_restore_object_runtime( /* Do same thing as object update: override actual object data * pointer with evaluated datablock. */ - if (object->type == OB_MESH) { - object->data = mesh_eval; - /* Evaluated mesh simply copied edit_btmesh pointer from - * original mesh during update, need to make sure no dead - * pointers are left behind. - */ - mesh_eval->edit_btmesh = mesh_orig->edit_btmesh; - } + object->data = mesh_eval; + /* Evaluated mesh simply copied edit_btmesh pointer from + * original mesh during update, need to make sure no dead + * pointers are left behind. + */ + mesh_eval->edit_btmesh = mesh_orig->edit_btmesh; } } object->base_flag = object_runtime_backup->base_flag; -- cgit v1.2.3 From ebca6f5f2087b545a196422f3c1e4e988a7cd93f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 31 Jul 2018 23:36:01 +1000 Subject: Fix grease pencil line toggle Replace with generic context toggle operator. --- source/blender/editors/gpencil/gpencil_edit.c | 38 ------------------------- source/blender/editors/gpencil/gpencil_intern.h | 1 - source/blender/editors/gpencil/gpencil_ops.c | 30 ++++++++----------- 3 files changed, 12 insertions(+), 57 deletions(-) (limited to 'source') diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index fdeadcc648a..56d1d53ea40 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -486,44 +486,6 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot) ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; } -/* toggle multi edit strokes support */ -static int gpencil_multiedit_toggle_exec(bContext *C, wmOperator *op) -{ - View3D *v3d = CTX_wm_view3d(C); - const bool lines = RNA_boolean_get(op->ptr, "lines"); - - /* Just toggle value */ - if (lines == 0) { - v3d->flag3 ^= V3D_GP_SHOW_EDIT_LINES; - } - else { - v3d->flag3 ^= V3D_GP_SHOW_MULTIEDIT_LINES; - } - - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); - - return OPERATOR_FINISHED; -} - -void GPENCIL_OT_multiedit_toggle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Edit Lines Toggle"; - ot->idname = "GPENCIL_OT_multiedit_toggle"; - ot->description = "Enable/disable edit lines support"; - - /* callbacks */ - ot->exec = gpencil_multiedit_toggle_exec; - ot->poll = gp_stroke_edit_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; - - /* properties */ - RNA_def_boolean(ot->srna, "toggle_visibility", 0, "Toggle Visibility Only", "Toggle visibility of edit lines only"); -} - /* ************** Duplicate Selected Strokes **************** */ /* Make copies of selected point segments in a selected stroke */ diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index a51f9e7a065..52e7d1e1f30 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -291,7 +291,6 @@ void GPENCIL_OT_paintmode_toggle(struct wmOperatorType *ot); void GPENCIL_OT_sculptmode_toggle(struct wmOperatorType *ot); void GPENCIL_OT_weightmode_toggle(struct wmOperatorType *ot); void GPENCIL_OT_selection_opacity_toggle(struct wmOperatorType *ot); -void GPENCIL_OT_multiedit_toggle(struct wmOperatorType *ot); void GPENCIL_OT_select(struct wmOperatorType *ot); void GPENCIL_OT_select_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index e5ebfcecdf8..43ccc77e921 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -404,11 +404,10 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0); /* toogle multiedit support */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "toggle_visibility", 0); - - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "toggle_visibility", 1); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_edit_lines"); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_multiedit_line_only"); /* Isolate Layer */ WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0); @@ -605,12 +604,10 @@ static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf) ed_keymap_gpencil_sculpt(keymap); /* toogle multiedit support */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "toggle_visibility", 0); - - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "toggle_visibility", 1); - + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_edit_lines"); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_multiedit_line_only"); } /* Stroke Weight Paint Keymap - Only when weight is enabled */ @@ -637,12 +634,10 @@ static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf) RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.weight_brush.size"); /* toogle multiedit support */ - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, 0, 0); - RNA_boolean_set(kmi->ptr, "toggle_visibility", 0); - - kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_multiedit_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); - RNA_boolean_set(kmi->ptr, "toggle_visibility", 1); - + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_edit_lines"); + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_multiedit_line_only"); } /* ==================== */ @@ -678,7 +673,6 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_sculptmode_toggle); WM_operatortype_append(GPENCIL_OT_weightmode_toggle); WM_operatortype_append(GPENCIL_OT_selection_opacity_toggle); - WM_operatortype_append(GPENCIL_OT_multiedit_toggle); WM_operatortype_append(GPENCIL_OT_select); WM_operatortype_append(GPENCIL_OT_select_all); -- cgit v1.2.3 From a3893ed03eeb9dbdfad1f4414bf168601985b0cf Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 15:38:45 +0200 Subject: Enable ghost onion skin by default This option was changed by error when implement annotations. --- source/blender/blenkernel/intern/gpencil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index c86f39f1d55..18817f20d1c 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -419,13 +419,13 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti /* set default thickness of new strokes for this layer */ gpl->thickness = 3; - /* onion-skinning settings */ - gpl->onion_flag |= GP_LAYER_ONIONSKIN; } else { /* thickness parameter represents "thickness change", not absolute thickness */ gpl->thickness = 0; gpl->opacity = 1.0f; + /* onion-skinning settings */ + gpl->onion_flag |= GP_LAYER_ONIONSKIN; } /* auto-name */ -- cgit v1.2.3 From ff1ca80f01012eacb347a3e33c3afa87ba752097 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 15:57:11 +0200 Subject: Set overlay default values --- source/blender/blenloader/intern/versioning_defaults.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'source') diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index a86986e2e09..da3787816d2 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -442,4 +442,21 @@ void BLO_update_defaults_startup_blend(Main *bmain) la->energy = 10.0; } } + /* default grease pencil settings */ + { + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->flag3 |= V3D_GP_SHOW_EDIT_LINES; + v3d->flag3 |= V3D_GP_SHOW_MULTIEDIT_LINES; + v3d->flag3 |= V3D_GP_SHOW_ONION_SKIN; + v3d->vertex_opacity = 0.9f; + break; + } + } + } + } + } } -- cgit v1.2.3 From d41f448b3bb34e56f2c4a082ccd1457e80ef1849 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 16:04:57 +0200 Subject: Change Brush smooth factor to 0.1 by default The old values were too high. --- source/blender/blenkernel/intern/brush.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 598eb9b5b54..c769978f9bb 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -289,7 +289,7 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->draw_angle_factor = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; @@ -321,7 +321,7 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->draw_angle_factor = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->draw_subdivide = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; @@ -350,7 +350,7 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->draw_angle_factor = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; @@ -387,7 +387,7 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->draw_angle_factor = 0.0f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 1.0f; + brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 2; brush->gpencil_settings->thick_smoothfac = 0.5f; brush->gpencil_settings->thick_smoothlvl = 2; @@ -454,7 +454,7 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->draw_angle_factor = 1.0f; brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS; - brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; @@ -477,7 +477,7 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_FILL; - brush->gpencil_settings->draw_smoothfac = 0.5f; + brush->gpencil_settings->draw_smoothfac = 0.1f; brush->gpencil_settings->draw_smoothlvl = 1; brush->gpencil_settings->thick_smoothfac = 1.0f; brush->gpencil_settings->thick_smoothlvl = 3; -- cgit v1.2.3 From d803b4e43b11bffc819d130c811f0e6f03195d57 Mon Sep 17 00:00:00 2001 From: Pablo Vazquez Date: Tue, 31 Jul 2018 16:14:05 +0200 Subject: UI: Grease Pencil Simplify tweaks Single-column layout and tweaks to tooltips. --- source/blender/makesrna/intern/rna_scene.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 9fde87be486..c8f1d810b00 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -5188,27 +5188,27 @@ static void rna_def_scene_render_data(BlenderRNA *brna) /* Grease Pencil - Simplify Options */ prop = RNA_def_property(srna, "simplify_gpencil", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ENABLE); - RNA_def_property_ui_text(prop, "Simplify", "Simplify Grease Pencil Drawing"); + RNA_def_property_ui_text(prop, "Simplify", "Simplify Grease Pencil drawing"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "simplify_gpencil_onplay", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_ON_PLAY); - RNA_def_property_ui_text(prop, "On Play", "Simplify Grease Pencil only when play animation"); + RNA_def_property_ui_text(prop, "Simplify Playback", "Simplify Grease Pencil only during animation playback"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "simplify_gpencil_view_fill", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FILL); - RNA_def_property_ui_text(prop, "Fill", "Do not fill strokes on viewport"); + RNA_def_property_ui_text(prop, "Disable Fill", "Disable fill strokes in the viewport"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "simplify_gpencil_remove_lines", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE); - RNA_def_property_ui_text(prop, "Remove Lines", "Remove External Lines of Filling Strokes"); + RNA_def_property_ui_text(prop, "Disable Lines", "Disable external lines of fill strokes"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "simplify_gpencil_view_modifier", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER); - RNA_def_property_ui_text(prop, "Fill", "Do not apply modifiers on viewport"); + RNA_def_property_ui_text(prop, "Disable Modifiers", "Do not apply modifiers in the viewport"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* persistent data */ -- cgit v1.2.3 From 4684375bd45f7c6bebcfd5006a8bc86e777f971e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 1 Aug 2018 01:27:47 +1200 Subject: Fix: Motion Paths were still visible after clearing them After clearing motion paths from objects, those objects needed to be tagged for copy on write so that the copied data (i.e. viewport) recieve the changes (i.e. removed paths) Reported by Hjalti --- source/blender/editors/armature/pose_edit.c | 3 +++ source/blender/editors/object/object_edit.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'source') diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 3ae578279ca..1dfb9ec984a 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -365,6 +365,9 @@ static void ED_pose_clear_paths(Object *ob, bool only_selected) /* if nothing was skipped, there should be no paths left! */ if (skipped == false) ob->pose->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS; + + /* tag armature object for copy on write - so removed paths don't still show */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } /* operator callback - wrapper for the backend function */ diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 48048319cb7..a6dad906579 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1378,6 +1378,9 @@ static void object_clear_mpath(Object *ob) animviz_free_motionpath(ob->mpath); ob->mpath = NULL; ob->avs.path_bakeflag &= ~MOTIONPATH_BAKE_HAS_PATHS; + + /* tag object for copy on write - so removed paths don't still show */ + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } } -- cgit v1.2.3 From 9b817bc168903f9c44c2464b9b2f671ddf465f06 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Tue, 31 Jul 2018 17:02:50 +0200 Subject: Fix set_pixel overflow in fill brush The value of the index was above the size of image --- source/blender/editors/gpencil/gpencil_fill.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'source') diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 20db5c1504f..253f0db865e 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -372,6 +372,7 @@ static void get_pixel(ImBuf *ibuf, int idx, float r_col[4]) /* set pixel data (rgba) at index */ static void set_pixel(ImBuf *ibuf, int idx, const float col[4]) { + //BLI_assert(idx <= ibuf->x * ibuf->y); if (ibuf->rect) { uint *rrect = &ibuf->rect[idx]; uchar ccol[4]; @@ -587,20 +588,23 @@ static void gpencil_clean_borders(tGPDfill *tgpf) const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); int idx; + int pixel = 0; /* horizontal lines */ - for (idx = 0; idx < ibuf->x; idx++) { + for (idx = 0; idx < ibuf->x - 1; idx++) { /* bottom line */ set_pixel(ibuf, idx, fill_col); /* top line */ - set_pixel(ibuf, idx + (ibuf->x * (ibuf->y - 1)), fill_col); + pixel = idx + (ibuf->x * (ibuf->y - 1)); + set_pixel(ibuf, pixel, fill_col); } /* vertical lines */ for (idx = 0; idx < ibuf->y; idx++) { /* left line */ set_pixel(ibuf, ibuf->x * idx, fill_col); /* right line */ - set_pixel(ibuf, ibuf->x * idx + (ibuf->x - 1), fill_col); + pixel = ibuf->x * idx + (ibuf->x - 1); + set_pixel(ibuf, pixel, fill_col); } /* release ibuf */ -- cgit v1.2.3 From 3ecba657bb79e010cffae4110ee74a063429f7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 31 Jul 2018 16:54:58 +0200 Subject: GPU: Replace malloc/calloc/realloc/free with MEM_* counterpart --- source/blender/gpu/intern/gpu_batch.c | 20 +++++++++--------- source/blender/gpu/intern/gpu_element.c | 10 +++++---- source/blender/gpu/intern/gpu_shader_interface.c | 27 ++++++++++++------------ source/blender/gpu/intern/gpu_vertex_buffer.c | 16 ++++++++------ 4 files changed, 39 insertions(+), 34 deletions(-) (limited to 'source') diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index 9b433a37a72..87ea112148c 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -30,6 +30,8 @@ * Contains VAOs + VBOs + Shader representing a drawable entity. */ +#include "MEM_guardedalloc.h" + #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_matrix.h" @@ -59,8 +61,8 @@ void GPU_batch_vao_cache_clear(GPUBatch *batch) GPU_shaderinterface_remove_batch_ref((GPUShaderInterface *)batch->dynamic_vaos.interfaces[i], batch); } } - free(batch->dynamic_vaos.interfaces); - free(batch->dynamic_vaos.vao_ids); + MEM_freeN(batch->dynamic_vaos.interfaces); + MEM_freeN(batch->dynamic_vaos.vao_ids); } else { for (int i = 0; i < GPU_BATCH_VAO_STATIC_LEN; ++i) { @@ -85,7 +87,7 @@ GPUBatch *GPU_batch_create_ex( GPUPrimType prim_type, GPUVertBuf *verts, GPUIndexBuf *elem, uint owns_flag) { - GPUBatch *batch = calloc(1, sizeof(GPUBatch)); + GPUBatch *batch = MEM_callocN(sizeof(GPUBatch), "GPUBatch"); GPU_batch_init_ex(batch, prim_type, verts, elem, owns_flag); return batch; } @@ -146,7 +148,7 @@ void GPU_batch_discard(GPUBatch *batch) if (batch->free_callback) { batch->free_callback(batch, batch->callback_data); } - free(batch); + MEM_freeN(batch); } void GPU_batch_callback_free_set(GPUBatch *batch, void (*callback)(GPUBatch *, void *), void *user_data) @@ -255,8 +257,8 @@ static GLuint batch_vao_get(GPUBatch *batch) } /* Init dynamic arrays and let the branch below set the values. */ batch->dynamic_vaos.count = GPU_BATCH_VAO_DYN_ALLOC_COUNT; - batch->dynamic_vaos.interfaces = calloc(batch->dynamic_vaos.count, sizeof(GPUShaderInterface *)); - batch->dynamic_vaos.vao_ids = calloc(batch->dynamic_vaos.count, sizeof(GLuint)); + batch->dynamic_vaos.interfaces = MEM_callocN(batch->dynamic_vaos.count * sizeof(GPUShaderInterface *), "dyn vaos interfaces"); + batch->dynamic_vaos.vao_ids = MEM_callocN(batch->dynamic_vaos.count * sizeof(GLuint), "dyn vaos ids"); } } @@ -270,10 +272,8 @@ static GLuint batch_vao_get(GPUBatch *batch) /* Not enough place, realloc the array. */ i = batch->dynamic_vaos.count; batch->dynamic_vaos.count += GPU_BATCH_VAO_DYN_ALLOC_COUNT; - batch->dynamic_vaos.interfaces = realloc(batch->dynamic_vaos.interfaces, sizeof(GPUShaderInterface *) * batch->dynamic_vaos.count); - batch->dynamic_vaos.vao_ids = realloc(batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count); - memset(batch->dynamic_vaos.interfaces + i, 0, sizeof(GPUShaderInterface *) * GPU_BATCH_VAO_DYN_ALLOC_COUNT); - memset(batch->dynamic_vaos.vao_ids + i, 0, sizeof(GLuint) * GPU_BATCH_VAO_DYN_ALLOC_COUNT); + batch->dynamic_vaos.interfaces = MEM_recallocN(batch->dynamic_vaos.interfaces, sizeof(GPUShaderInterface *) * batch->dynamic_vaos.count); + batch->dynamic_vaos.vao_ids = MEM_recallocN(batch->dynamic_vaos.vao_ids, sizeof(GLuint) * batch->dynamic_vaos.count); } batch->dynamic_vaos.interfaces[i] = batch->interface; batch->dynamic_vaos.vao_ids[i] = new_vao = GPU_vao_alloc(); diff --git a/source/blender/gpu/intern/gpu_element.c b/source/blender/gpu/intern/gpu_element.c index 901e09443d1..56a0c90d5b5 100644 --- a/source/blender/gpu/intern/gpu_element.c +++ b/source/blender/gpu/intern/gpu_element.c @@ -29,6 +29,8 @@ * GPU element list (AKA index buffer) */ +#include "MEM_guardedalloc.h" + #include "GPU_element.h" #include "gpu_context_private.h" @@ -70,7 +72,7 @@ void GPU_indexbuf_init_ex( builder->max_index_len = index_len; builder->index_len = 0; // start empty builder->prim_type = prim_type; - builder->data = calloc(builder->max_index_len, sizeof(uint)); + builder->data = MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data"); } void GPU_indexbuf_init(GPUIndexBufBuilder *builder, GPUPrimType prim_type, uint prim_len, uint vertex_len) @@ -243,7 +245,7 @@ static void squeeze_indices_short(GPUIndexBufBuilder *builder, GPUIndexBuf *elem GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *builder) { - GPUIndexBuf *elem = calloc(1, sizeof(GPUIndexBuf)); + GPUIndexBuf *elem = MEM_callocN(sizeof(GPUIndexBuf), "GPUIndexBuf"); GPU_indexbuf_build_in_place(builder, elem); return elem; } @@ -290,7 +292,7 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem) glBufferData(GL_ARRAY_BUFFER, GPU_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW); /* discard builder (one-time use) */ - free(builder->data); + MEM_freeN(builder->data); builder->data = NULL; /* other fields are safe to leave */ } @@ -305,5 +307,5 @@ void GPU_indexbuf_discard(GPUIndexBuf *elem) if (elem->vbo_id) { GPU_buf_free(elem->vbo_id); } - free(elem); + MEM_freeN(elem); } diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index 54c5f41bbd3..f6bbc228ae9 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -29,6 +29,8 @@ * GPU shader interface (C --> GLSL) */ +#include "MEM_guardedalloc.h" + #include "GPU_shader_interface.h" #include "gpu_batch_private.h" @@ -154,7 +156,7 @@ GPU_INLINE void buckets_free(GPUShaderInput *buckets[GPU_NUM_SHADERINTERFACE_BUC GPUShaderInput *input = buckets[bucket_index]; while (input != NULL) { GPUShaderInput *input_next = input->next; - free(input); + MEM_freeN(input); input = input_next; } } @@ -178,12 +180,12 @@ static bool setup_builtin_uniform(GPUShaderInput *input, const char *name) static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const char *name) { - GPUShaderInput *input = malloc(sizeof(GPUShaderInput)); + GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Unif"); input->location = glGetUniformLocation(shaderface->program, name); uint name_len = strlen(name); - shaderface->name_buffer = realloc(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); /* include NULL terminator */ + shaderface->name_buffer = MEM_reallocN(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); /* include NULL terminator */ char *name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset; strcpy(name_buffer, name); @@ -208,7 +210,7 @@ static const GPUShaderInput *add_uniform(GPUShaderInterface *shaderface, const c GPUShaderInterface *GPU_shaderinterface_create(int32_t program) { - GPUShaderInterface *shaderface = calloc(1, sizeof(GPUShaderInterface)); + GPUShaderInterface *shaderface = MEM_callocN(sizeof(GPUShaderInterface), "GPUShaderInterface"); shaderface->program = program; #if DEBUG_SHADER_INTERFACE @@ -225,11 +227,11 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len); const uint32_t name_buffer_len = attr_len * max_attrib_name_len + ubo_len * max_ubo_name_len; - shaderface->name_buffer = malloc(name_buffer_len); + shaderface->name_buffer = MEM_mallocN(name_buffer_len, "name_buffer"); /* Attributes */ for (uint32_t i = 0; i < attr_len; ++i) { - GPUShaderInput *input = malloc(sizeof(GPUShaderInput)); + GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput Attr"); GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; char *name = shaderface->name_buffer + shaderface->name_buffer_offset; GLsizei name_len = 0; @@ -256,7 +258,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) } /* Uniform Blocks */ for (uint32_t i = 0; i < ubo_len; ++i) { - GPUShaderInput *input = malloc(sizeof(GPUShaderInput)); + GPUShaderInput *input = MEM_mallocN(sizeof(GPUShaderInput), "GPUShaderInput UBO"); GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset; char *name = shaderface->name_buffer + shaderface->name_buffer_offset; GLsizei name_len = 0; @@ -282,7 +284,7 @@ GPUShaderInterface *GPU_shaderinterface_create(int32_t program) } /* Batches ref buffer */ shaderface->batches_len = GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = calloc(shaderface->batches_len, sizeof(GPUBatch *)); + shaderface->batches = MEM_callocN(shaderface->batches_len * sizeof(GPUBatch *), "GPUShaderInterface batches"); return shaderface; } @@ -294,16 +296,16 @@ void GPU_shaderinterface_discard(GPUShaderInterface *shaderface) buckets_free(shaderface->attrib_buckets); buckets_free(shaderface->ubo_buckets); /* Free memory used by name_buffer. */ - free(shaderface->name_buffer); + MEM_freeN(shaderface->name_buffer); /* Remove this interface from all linked Batches vao cache. */ for (int i = 0; i < shaderface->batches_len; ++i) { if (shaderface->batches[i] != NULL) { gpu_batch_remove_interface_ref(shaderface->batches[i], shaderface); } } - free(shaderface->batches); + MEM_freeN(shaderface->batches); /* Free memory used by shader interface by its self. */ - free(shaderface); + MEM_freeN(shaderface); } const GPUShaderInput *GPU_shaderinterface_uniform(const GPUShaderInterface *shaderface, const char *name) @@ -350,8 +352,7 @@ void GPU_shaderinterface_add_batch_ref(GPUShaderInterface *shaderface, GPUBatch /* Not enough place, realloc the array. */ i = shaderface->batches_len; shaderface->batches_len += GPU_SHADERINTERFACE_REF_ALLOC_COUNT; - shaderface->batches = realloc(shaderface->batches, sizeof(GPUBatch *) * shaderface->batches_len); - memset(shaderface->batches + i, 0, sizeof(GPUBatch *) * GPU_SHADERINTERFACE_REF_ALLOC_COUNT); + shaderface->batches = MEM_recallocN(shaderface->batches, sizeof(GPUBatch *) * shaderface->batches_len); } shaderface->batches[i] = batch; } diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.c b/source/blender/gpu/intern/gpu_vertex_buffer.c index d605378bf0e..05100b8a23f 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.c +++ b/source/blender/gpu/intern/gpu_vertex_buffer.c @@ -29,6 +29,8 @@ * GPU vertex buffer */ +#include "MEM_guardedalloc.h" + #include "GPU_vertex_buffer.h" #include "gpu_context_private.h" @@ -53,7 +55,7 @@ static GLenum convert_usage_type_to_gl(GPUUsageType type) GPUVertBuf *GPU_vertbuf_create(GPUUsageType usage) { - GPUVertBuf *verts = malloc(sizeof(GPUVertBuf)); + GPUVertBuf *verts = MEM_mallocN(sizeof(GPUVertBuf), "GPUVertBuf"); GPU_vertbuf_init(verts, usage); return verts; } @@ -96,9 +98,9 @@ void GPU_vertbuf_discard(GPUVertBuf *verts) #endif } if (verts->data) { - free(verts->data); + MEM_freeN(verts->data); } - free(verts); + MEM_freeN(verts); } uint GPU_vertbuf_size_get(const GPUVertBuf *verts) @@ -123,7 +125,7 @@ void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len) } /* discard previous data if any */ if (verts->data) { - free(verts->data); + MEM_freeN(verts->data); } #if VRAM_USAGE uint new_size = vertex_buffer_size(&verts->format, v_len); @@ -131,7 +133,7 @@ void GPU_vertbuf_data_alloc(GPUVertBuf *verts, uint v_len) #endif verts->dirty = true; verts->vertex_len = verts->vertex_alloc = v_len; - verts->data = malloc(sizeof(GLubyte) * GPU_vertbuf_size_get(verts)); + verts->data = MEM_mallocN(sizeof(GLubyte) * GPU_vertbuf_size_get(verts), "GPUVertBuf data"); } /* resize buffer keeping existing data */ @@ -148,7 +150,7 @@ void GPU_vertbuf_data_resize(GPUVertBuf *verts, uint v_len) #endif verts->dirty = true; verts->vertex_len = verts->vertex_alloc = v_len; - verts->data = realloc(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts)); + verts->data = MEM_reallocN(verts->data, sizeof(GLubyte) * GPU_vertbuf_size_get(verts)); } /* Set vertex count but does not change allocation. @@ -250,7 +252,7 @@ static void VertBuffer_upload_data(GPUVertBuf *verts) glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); if (verts->usage == GPU_USAGE_STATIC) { - free(verts->data); + MEM_freeN(verts->data); verts->data = NULL; } verts->dirty = false; -- cgit v1.2.3 From 7e0eb0d071776ea938a70737fb3a0a9592264e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 31 Jul 2018 18:16:08 +0200 Subject: GPUFrameBuffer: Put active framebuffer in GPUContext instead of being ThreadLocal and leading to incorrect usage. We still enforce no framebuffer when changing context. We can lift this restriction later. --- source/blender/draw/intern/draw_manager.c | 2 +- source/blender/gpu/GPU_framebuffer.h | 3 +- source/blender/gpu/intern/gpu_context.cpp | 12 ++++++ source/blender/gpu/intern/gpu_context_private.h | 3 ++ source/blender/gpu/intern/gpu_framebuffer.c | 54 ++++++++++++------------- source/blender/windowmanager/intern/wm_window.c | 12 +++--- 6 files changed, 50 insertions(+), 36 deletions(-) (limited to 'source') diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 159f69d3226..0c731811f32 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1419,7 +1419,7 @@ void DRW_draw_render_loop_ex( DRW_hair_init(); /* No framebuffer allowed before drawing. */ - BLI_assert(GPU_framebuffer_current_get() == 0); + BLI_assert(GPU_framebuffer_active_get() == NULL); /* Init engines */ drw_engines_init(); diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 04357d6a927..ef49f9721dd 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -69,8 +69,7 @@ void GPU_framebuffer_restore(void); bool GPU_framebuffer_bound(GPUFrameBuffer *fb); bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); -/* internal use only */ -unsigned int GPU_framebuffer_current_get(void); +GPUFrameBuffer *GPU_framebuffer_active_get(void); #define GPU_FRAMEBUFFER_FREE_SAFE(fb) do { \ if (fb != NULL) { \ diff --git a/source/blender/gpu/intern/gpu_context.cpp b/source/blender/gpu/intern/gpu_context.cpp index 8d8f4d12b04..ce3eb64fa37 100644 --- a/source/blender/gpu/intern/gpu_context.cpp +++ b/source/blender/gpu/intern/gpu_context.cpp @@ -69,6 +69,7 @@ static std::mutex orphans_mutex; struct GPUContext { GLuint default_vao; + GPUFrameBuffer *current_fbo; std::unordered_set batches; /* Batches that have VAOs from this context */ #ifdef DEBUG std::unordered_set framebuffers; /* Framebuffers that have FBO from this context */ @@ -82,6 +83,7 @@ struct GPUContext { GPUContext() { thread_is_used = false; + current_fbo = 0; } #endif }; @@ -315,3 +317,13 @@ void gpu_context_remove_framebuffer(GPUContext *ctx, GPUFrameBuffer *fb) UNUSED_VARS(ctx, fb); #endif } + +void gpu_context_active_framebuffer_set(GPUContext *ctx, GPUFrameBuffer *fb) +{ + ctx->current_fbo = fb; +} + +GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx) +{ + return ctx->current_fbo; +} diff --git a/source/blender/gpu/intern/gpu_context_private.h b/source/blender/gpu/intern/gpu_context_private.h index 4881a892e38..762d9ff10c0 100644 --- a/source/blender/gpu/intern/gpu_context_private.h +++ b/source/blender/gpu/intern/gpu_context_private.h @@ -61,6 +61,9 @@ void gpu_context_remove_batch(GPUContext *ctx, GPUBatch *batch); void gpu_context_add_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb); void gpu_context_remove_framebuffer(GPUContext *ctx, struct GPUFrameBuffer *fb); +void gpu_context_active_framebuffer_set(GPUContext *ctx, struct GPUFrameBuffer *fb); +struct GPUFrameBuffer *gpu_context_active_framebuffer_get(GPUContext *ctx); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index ba8dcb04269..56abe040f32 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -45,8 +45,6 @@ #include "gpu_private.h" #include "gpu_context_private.h" -static ThreadLocal(void *) g_currentfb; - typedef enum { GPU_FB_DEPTH_ATTACHMENT = 0, GPU_FB_DEPTH_STENCIL_ATTACHMENT, @@ -169,22 +167,29 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) void gpu_framebuffer_module_init(void) { - BLI_thread_local_create(g_currentfb); } void gpu_framebuffer_module_exit(void) { - BLI_thread_local_delete(g_currentfb); } -static uint gpu_framebuffer_current_get(void) +GPUFrameBuffer *GPU_framebuffer_active_get(void) { - return GET_UINT_FROM_POINTER(BLI_thread_local_get(g_currentfb)); + GPUContext *ctx = GPU_context_active_get(); + if (ctx) { + return gpu_context_active_framebuffer_get(ctx); + } + else { + return 0; + } } -static void gpu_framebuffer_current_set(uint object) +static void gpu_framebuffer_current_set(GPUFrameBuffer *fb) { - BLI_thread_local_set(g_currentfb, SET_UINT_IN_POINTER(object)); + GPUContext *ctx = GPU_context_active_get(); + if (ctx) { + gpu_context_active_framebuffer_set(ctx, fb); + } } /* GPUFrameBuffer */ @@ -217,8 +222,8 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) gpu_context_remove_framebuffer(fb->ctx, fb); } - if (gpu_framebuffer_current_get() == fb->object) { - gpu_framebuffer_current_set(0); + if (GPU_framebuffer_active_get() == fb) { + gpu_framebuffer_current_set(NULL); } MEM_freeN(fb); @@ -371,7 +376,7 @@ static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb) GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; int numslots = 0; - BLI_assert(gpu_framebuffer_current_get() == fb->object); + BLI_assert(GPU_framebuffer_active_get() == fb); /* Update attachments */ for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { @@ -415,10 +420,10 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb) if (fb->object == 0) gpu_framebuffer_init(fb); - if (gpu_framebuffer_current_get() != fb->object) + if (GPU_framebuffer_active_get() != fb) glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - gpu_framebuffer_current_set(fb->object); + gpu_framebuffer_current_set(fb); if (fb->dirty_flag != 0) gpu_framebuffer_update_attachments(fb); @@ -439,20 +444,15 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb) void GPU_framebuffer_restore(void) { - if (gpu_framebuffer_current_get() != 0) { + if (GPU_framebuffer_active_get() != NULL) { glBindFramebuffer(GL_FRAMEBUFFER, 0); - gpu_framebuffer_current_set(0); + gpu_framebuffer_current_set(NULL); } } bool GPU_framebuffer_bound(GPUFrameBuffer *fb) { - return (fb->object == gpu_framebuffer_current_get()) && (fb->object != 0); -} - -unsigned int GPU_framebuffer_current_get(void) -{ - return gpu_framebuffer_current_get(); + return (fb == GPU_framebuffer_active_get()) && (fb->object != 0); } bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) @@ -543,7 +543,7 @@ void GPU_framebuffer_blit( { BLI_assert(blit_buffers != 0); - GLuint prev_fb = gpu_framebuffer_current_get(); + GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); /* Framebuffers must be up to date. This simplify this function. */ if (fb_read->dirty_flag != 0 || fb_read->object == 0) { @@ -601,11 +601,11 @@ void GPU_framebuffer_blit( mask, GL_NEAREST); /* Restore previous framebuffer */ - if (fb_write->object == prev_fb) { + if (fb_write == prev_fb) { GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ } else { - glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); + glBindFramebuffer(GL_FRAMEBUFFER, prev_fb->object); gpu_framebuffer_current_set(prev_fb); } } @@ -619,13 +619,13 @@ void GPU_framebuffer_recursive_downsample( void (*callback)(void *userData, int level), void *userData) { /* Framebuffer must be up to date and bound. This simplify this function. */ - if (gpu_framebuffer_current_get() != fb->object || fb->dirty_flag != 0 || fb->object == 0) { + if (GPU_framebuffer_active_get() != fb || fb->dirty_flag != 0 || fb->object == 0) { GPU_framebuffer_bind(fb); } /* HACK: We make the framebuffer appear not bound in order to * not trigger any error in GPU_texture_bind(). */ - GLuint prev_fb = gpu_framebuffer_current_get(); - gpu_framebuffer_current_set(0); + GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get(); + gpu_framebuffer_current_set(NULL); int i; int current_dim[2] = {fb->width, fb->height}; diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 3083607b8a9..f391c92b4ca 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1113,7 +1113,7 @@ void wm_window_clear_drawable(wmWindowManager *wm) void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) { - BLI_assert(GPU_framebuffer_current_get() == 0); + BLI_assert(GPU_framebuffer_active_get() == NULL); if (win != wm->windrawable && win->ghostwin) { // win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */ @@ -1134,7 +1134,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) void wm_window_reset_drawable(void) { BLI_assert(BLI_thread_is_main()); - BLI_assert(GPU_framebuffer_current_get() == 0); + BLI_assert(GPU_framebuffer_active_get() == NULL); wmWindowManager *wm = G_MAIN->wm.first; if (wm == NULL) @@ -2280,24 +2280,24 @@ void *WM_opengl_context_create(void) * So we should call this function only on the main thread. */ BLI_assert(BLI_thread_is_main()); - BLI_assert(GPU_framebuffer_current_get() == 0); + BLI_assert(GPU_framebuffer_active_get() == NULL); return GHOST_CreateOpenGLContext(g_system); } void WM_opengl_context_dispose(void *context) { - BLI_assert(GPU_framebuffer_current_get() == 0); + BLI_assert(GPU_framebuffer_active_get() == NULL); GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context); } void WM_opengl_context_activate(void *context) { - BLI_assert(GPU_framebuffer_current_get() == 0); + BLI_assert(GPU_framebuffer_active_get() == NULL); GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context); } void WM_opengl_context_release(void *context) { - BLI_assert(GPU_framebuffer_current_get() == 0); + BLI_assert(GPU_framebuffer_active_get() == NULL); GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context); } -- cgit v1.2.3 From 6ba70d5996a4fdb82516d199dacfee066f2b3bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 31 Jul 2018 18:20:57 +0200 Subject: Fix crash when rendering viewport within another area This also Fix T55574 Crash on sequencer preview --- source/blender/editors/space_view3d/view3d_draw.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source') diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 0157bc567ca..46b53a369e3 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1412,6 +1412,12 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( ofs = NULL; } + GPUFrameBuffer *old_fb = GPU_framebuffer_active_get(); + + if (old_fb) { + GPU_framebuffer_restore(); + } + const bool own_ofs = (ofs == NULL); DRW_opengl_context_enable(); @@ -1556,6 +1562,10 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( DRW_opengl_context_disable(); + if (old_fb) { + GPU_framebuffer_bind(old_fb); + } + if (ibuf->rect_float && ibuf->rect) IMB_rect_from_float(ibuf); -- cgit v1.2.3 From 3667a5402e3d548073b4a9c031868dd0e55ed72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 31 Jul 2018 20:10:14 +0200 Subject: KnifeTool: Use GPUBatch API instead of IMM to fix buffer overflow issue This also include a small optimisation (remove of a double loop and half of the memory allocation for hit points) This should fix T55946 Crash using knife tool on mesh with large number of vertices. Tried with a 500K vert suzanne and it seems fine. --- source/blender/editors/mesh/editmesh_knife.c | 57 ++++++++++++++++------------ 1 file changed, 33 insertions(+), 24 deletions(-) (limited to 'source') diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 61f55451b17..c98aef74ae7 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1040,7 +1040,6 @@ static void knife_init_colors(KnifeColors *colors) static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) { const KnifeTool_OpData *kcd = arg; - GPU_depth_test(false); glPolygonOffset(1.0f, 1.0f); @@ -1052,7 +1051,8 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void knifetool_draw_angle_snapping(kcd); } - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); @@ -1113,40 +1113,43 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void if (kcd->totlinehit > 0) { KnifeLineHit *lh; - int i; + int i, v, vs; + float fcol[4]; GPU_blend(true); GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - /* draw any snapped verts first */ - immUniformColor4ubv(kcd->colors.point_a); - GPU_point_size(11); - - immBeginAtMost(GPU_PRIM_POINTS, kcd->totlinehit); + GPUVertBuf *vert = GPU_vertbuf_create_with_format(format); + GPU_vertbuf_data_alloc(vert, kcd->totlinehit); lh = kcd->linehits; - for (i = 0; i < kcd->totlinehit; i++, lh++) { + for (i = 0, v = 0, vs = kcd->totlinehit - 1; i < kcd->totlinehit; i++, lh++) { if (lh->v) { - immVertex3fv(pos, lh->cagehit); + GPU_vertbuf_attr_set(vert, pos, v++, lh->cagehit); + } + else { + GPU_vertbuf_attr_set(vert, pos, vs--, lh->cagehit); } } - immEnd(); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO); + GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR); + + /* draw any snapped verts first */ + rgba_uchar_to_float(fcol, kcd->colors.point_a); + GPU_batch_uniform_4fv(batch, "color", fcol); + GPU_matrix_bind(batch->interface); + GPU_point_size(11); + GPU_batch_draw_range_ex(batch, 0, v - 1, false); /* now draw the rest */ - immUniformColor4ubv(kcd->colors.curpoint_a); + rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); + GPU_batch_uniform_4fv(batch, "color", fcol); GPU_point_size(7); + GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false); - immBeginAtMost(GPU_PRIM_POINTS, kcd->totlinehit); - - lh = kcd->linehits; - for (i = 0; i < kcd->totlinehit; i++, lh++) { - if (!lh->v) { - immVertex3fv(pos, lh->cagehit); - } - } - - immEnd(); + GPU_batch_program_use_end(batch); + GPU_batch_discard(batch); GPU_blend(false); } @@ -1158,7 +1161,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.line); GPU_line_width(1.0); - immBeginAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_LINES, BLI_mempool_len(kcd->kedges) * 2); BLI_mempool_iternew(kcd->kedges, &iter); for (kfe = BLI_mempool_iterstep(&iter); kfe; kfe = BLI_mempool_iterstep(&iter)) { @@ -1170,6 +1173,9 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void } immEnd(); + + GPU_batch_draw(batch); + GPU_batch_discard(batch); } if (kcd->totkvert > 0) { @@ -1179,7 +1185,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void immUniformColor3ubv(kcd->colors.point); GPU_point_size(5.0); - immBeginAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); + GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); BLI_mempool_iternew(kcd->kverts, &iter); for (kfv = BLI_mempool_iterstep(&iter); kfv; kfv = BLI_mempool_iterstep(&iter)) { @@ -1190,6 +1196,9 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void } immEnd(); + + GPU_batch_draw(batch); + GPU_batch_discard(batch); } immUnbindProgram(); -- cgit v1.2.3 From e8d58080df07d4b7d9372bfca0dd54ea2817394a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 1 Aug 2018 08:08:59 +1000 Subject: DNA: remove View3D.flag3 Having 'flag, flag2, flag3' is getting out of hand especially when we support increasing the size of types. Make flag2 into an int. Note, this looses the 'show world' option, but it's not such an important setting. --- source/blender/editors/space_view3d/space_view3d.c | 2 +- source/blender/editors/space_view3d/view3d_draw.c | 4 ++-- source/blender/makesdna/DNA_view3d_types.h | 15 +++++++-------- source/blender/makesrna/intern/rna_space.c | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) (limited to 'source') diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 63ae3bbb657..7f3a36c7ba6 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1238,7 +1238,7 @@ static void space_view3d_listener(bScreen *UNUSED(sc), ScrArea *sa, struct wmNot switch (wmn->data) { case ND_WORLD_DRAW: case ND_WORLD: - if (v3d->flag3 & V3D_SHOW_WORLD) + if (v3d->flag2 & V3D_SHOW_WORLD) ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW); break; } diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index fbf2bd33638..1cf2e71f2bf 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -3091,7 +3091,7 @@ void ED_view3d_draw_offscreen_init(Main *bmain, Scene *scene, View3D *v3d) */ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) { - if (scene->world && (v3d->flag3 & V3D_SHOW_WORLD)) { + if (scene->world && (v3d->flag2 & V3D_SHOW_WORLD)) { RegionView3D *rv3d = ar->regiondata; GPUMaterial *gpumat = GPU_material_world(scene, scene->world); @@ -3497,7 +3497,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple( v3d.flag2 |= V3D_SOLID_TEX; } if (draw_flags & V3D_OFSDRAW_USE_BACKGROUND) { - v3d.flag3 |= V3D_SHOW_WORLD; + v3d.flag2 |= V3D_SHOW_WORLD; } if (draw_flags & V3D_OFSDRAW_USE_CAMERA_DOF) { if (camera->type == OB_CAMERA) { diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 845e7ab3658..1b3eef0f3ec 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -182,10 +182,11 @@ typedef struct View3D { /** * The drawing mode for the 3d display. Set to OB_BOUNDBOX, OB_WIRE, OB_SOLID, * OB_TEXTURE, OB_MATERIAL or OB_RENDER */ - short drawtype; - short ob_centre_cursor; /* optional bool for 3d cursor to define center */ + char drawtype; + char ob_centre_cursor; /* optional bool for 3d cursor to define center */ short scenelock, around; - short flag, flag2; + short flag; + int flag2; float lens, grid; float near, far; @@ -201,7 +202,7 @@ typedef struct View3D { /* transform widget info */ char twtype, twmode, twflag; - short flag3; + short _pad1; /* afterdraw, for xray & transparent */ struct ListBase afterdraw_transp; @@ -297,7 +298,7 @@ typedef struct View3D { #define RV3D_VIEW_IS_AXIS(view) \ (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM)) -/* View3d->flag2 (short) */ +/* View3d->flag2 (int) */ #define V3D_RENDER_OVERRIDE (1 << 2) #define V3D_SOLID_TEX (1 << 3) #define V3D_SHOW_GPENCIL (1 << 4) @@ -312,11 +313,9 @@ typedef struct View3D { #define V3D_SHOW_SOLID_MATCAP (1 << 13) /* runtime flag */ #define V3D_OCCLUDE_WIRE (1 << 14) #define V3D_SHADELESS_TEX (1 << 15) +#define V3D_SHOW_WORLD (1 << 16) -/* View3d->flag3 (short) */ -#define V3D_SHOW_WORLD (1 << 0) - /* View3D->around */ enum { /* center of the bounding box */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 813e847aae6..ae1761faec1 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2621,7 +2621,7 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "show_world", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag3", V3D_SHOW_WORLD); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_WORLD); RNA_def_property_ui_text(prop, "World Background", "Display world colors in the background"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); -- cgit v1.2.3 From 6a39d7255848511f231085bfb70c7daea8f0ca59 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 1 Aug 2018 08:57:31 +1000 Subject: Cleanup: declare vars or make static --- source/blender/makesrna/intern/rna_rigidbody.c | 2 +- source/blender/python/generic/imbuf_py_api.h | 2 ++ source/blender/python/intern/bpy_driver.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 853b1d9978c..5b86ec6b10d 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -77,7 +77,7 @@ const EnumPropertyItem rna_enum_rigidbody_constraint_type_items[] = { {0, NULL, 0, NULL, NULL}}; /* bullet spring type */ -const EnumPropertyItem rna_enum_rigidbody_constraint_spring_type_items[] = { +static const EnumPropertyItem rna_enum_rigidbody_constraint_spring_type_items[] = { {RBC_SPRING_TYPE1, "SPRING1", ICON_NONE, "Blender 2.7", "Spring implementation used in blender 2.7. Damping is capped at 1.0"}, {RBC_SPRING_TYPE2, "SPRING2", ICON_NONE, "Blender 2.8", "New implementation available since 2.8"}, {0, NULL, 0, NULL, NULL}}; diff --git a/source/blender/python/generic/imbuf_py_api.h b/source/blender/python/generic/imbuf_py_api.h index 92c1732a9c9..35adc541bfc 100644 --- a/source/blender/python/generic/imbuf_py_api.h +++ b/source/blender/python/generic/imbuf_py_api.h @@ -27,4 +27,6 @@ PyObject *BPyInit_imbuf(void); +extern PyTypeObject Py_ImBuf_Type; + #endif /* __IMBUF_PY_API_H__ */ diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index f6ff1b3f36b..e7608e93f58 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -252,7 +252,7 @@ static void pydriver_error(ChannelDriver *driver) #define OK_OP(op) [op] = 1 -const char secure_opcodes[255] = { +static const char secure_opcodes[255] = { OK_OP(POP_TOP), OK_OP(ROT_TWO), OK_OP(ROT_THREE), -- cgit v1.2.3 From f4a06b390ba779bd4dbd57ffb9121df53e343dc3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 1 Aug 2018 12:19:46 +1000 Subject: Keymap: use Q key for quick menu in gpencil mode Note, the keys for changing line display are now more obscure (Shift-Q, Shift-Alt-Q), and might be changed. --- source/blender/editors/gpencil/gpencil_ops.c | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'source') diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 43ccc77e921..3a86b0c13ef 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -248,7 +248,17 @@ static void ed_keymap_gpencil_selection(wmKeyMap *keymap) /* select more/less */ WM_keymap_add_item(keymap, "GPENCIL_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); +} +static void ed_keymap_gpencil_display(wmKeyMap *keymap) +{ + wmKeyMapItem *kmi; + + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_edit_lines"); + + kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT | KM_ALT, 0); + RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_multiedit_line_only"); } static void ed_keymap_gpencil_sculpt(wmKeyMap *keymap) @@ -403,11 +413,8 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_selection_opacity_toggle", HKEY, KM_PRESS, KM_CTRL, 0); - /* toogle multiedit support */ - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_edit_lines"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_multiedit_line_only"); + /* Display. */ + ed_keymap_gpencil_display(keymap); /* Isolate Layer */ WM_keymap_add_item(keymap, "GPENCIL_OT_layer_isolate", PADASTERKEY, KM_PRESS, 0, 0); @@ -592,7 +599,6 @@ static void ed_keymap_gpencil_painting(wmKeyConfig *keyconf) static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf) { wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Sculpt Mode", 0, 0); - wmKeyMapItem *kmi; /* set poll callback - so that this keymap only gets enabled when stroke sculptmode is enabled */ keymap->poll = gp_stroke_sculptmode_poll; @@ -603,11 +609,8 @@ static void ed_keymap_gpencil_sculpting(wmKeyConfig *keyconf) /* sculpt */ ed_keymap_gpencil_sculpt(keymap); - /* toogle multiedit support */ - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_edit_lines"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_multiedit_line_only"); + /* Display. */ + ed_keymap_gpencil_display(keymap); } /* Stroke Weight Paint Keymap - Only when weight is enabled */ @@ -633,11 +636,8 @@ static void ed_keymap_gpencil_weightpainting(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, 0, 0); RNA_string_set(kmi->ptr, "data_path_primary", "tool_settings.gpencil_sculpt.weight_brush.size"); - /* toogle multiedit support */ - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, 0, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_edit_lines"); - kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", QKEY, KM_PRESS, KM_SHIFT, 0); - RNA_string_set(kmi->ptr, "data_path", "space_data.overlay.use_gpencil_multiedit_line_only"); + /* Display. */ + ed_keymap_gpencil_display(keymap); } /* ==================== */ -- cgit v1.2.3 From 5f55bbf3d07db4f1b89921cbe742873fd5645e11 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 1 Aug 2018 16:02:20 +1000 Subject: RNA: add space_type to tool --- source/blender/makesrna/intern/rna_workspace.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source') diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c index 166d71689d1..88b79e8ee32 100644 --- a/source/blender/makesrna/intern/rna_workspace.c +++ b/source/blender/makesrna/intern/rna_workspace.c @@ -224,6 +224,12 @@ static void rna_def_workspace_tool(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Index", ""); RNA_def_property_int_funcs(prop, "rna_WorkspaceTool_index_get", NULL, NULL); + prop = RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "space_type"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_enum_items(prop, rna_enum_space_type_items); + RNA_def_property_ui_text(prop, "Space Type", ""); + RNA_api_workspace_tool(srna); } -- cgit v1.2.3 From 583b2f9a3d9d49a23e525b998c4b1893befa8dd0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 1 Aug 2018 16:32:22 +1000 Subject: Cleanup: remove unused array member --- source/blender/blenlib/intern/math_geom.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'source') diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 61b8f6819cc..356740b138f 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2486,19 +2486,19 @@ bool isect_ray_aabb_v3_simple( const float bb_min[3], const float bb_max[3], float *tmin, float *tmax) { - double t[7]; + double t[6]; float hit_dist[2]; const double invdirx = (dir[0] > 1e-35f || dir[0] < -1e-35f) ? 1.0 / (double)dir[0] : DBL_MAX; const double invdiry = (dir[1] > 1e-35f || dir[1] < -1e-35f) ? 1.0 / (double)dir[1] : DBL_MAX; const double invdirz = (dir[2] > 1e-35f || dir[2] < -1e-35f) ? 1.0 / (double)dir[2] : DBL_MAX; - t[1] = (double)(bb_min[0] - orig[0]) * invdirx; - t[2] = (double)(bb_max[0] - orig[0]) * invdirx; - t[3] = (double)(bb_min[1] - orig[1]) * invdiry; - t[4] = (double)(bb_max[1] - orig[1]) * invdiry; - t[5] = (double)(bb_min[2] - orig[2]) * invdirz; - t[6] = (double)(bb_max[2] - orig[2]) * invdirz; - hit_dist[0] = (float)fmax(fmax(fmin(t[1], t[2]), fmin(t[3], t[4])), fmin(t[5], t[6])); - hit_dist[1] = (float)fmin(fmin(fmax(t[1], t[2]), fmax(t[3], t[4])), fmax(t[5], t[6])); + t[0] = (double)(bb_min[0] - orig[0]) * invdirx; + t[1] = (double)(bb_max[0] - orig[0]) * invdirx; + t[2] = (double)(bb_min[1] - orig[1]) * invdiry; + t[3] = (double)(bb_max[1] - orig[1]) * invdiry; + t[4] = (double)(bb_min[2] - orig[2]) * invdirz; + t[5] = (double)(bb_max[2] - orig[2]) * invdirz; + hit_dist[0] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5])); + hit_dist[1] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5])); if ((hit_dist[1] < 0.0f || hit_dist[0] > hit_dist[1])) { return false; } -- cgit v1.2.3 From c06bed25c70cb80657447e510890b29ceb6bbc1b Mon Sep 17 00:00:00 2001 From: Antonioya Date: Wed, 1 Aug 2018 10:17:05 +0200 Subject: Fix T56187: Crash using cursor tool in Edit/Sculpt and Weight Paint mode The transform tried to calculate the multiframe falloff, but there was not any stroke to do that. --- source/blender/editors/transform/transform.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b0de996ee0e..85229ddd041 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -4636,7 +4636,12 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) if (t->options & CTX_GPENCIL_STROKES) { /* grease pencil multiframe falloff */ bGPDstroke *gps = (bGPDstroke *)td->extra; - mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); + if (gps != NULL) { + mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff); + } + else { + mul_v3_fl(tvec, td->factor); + } } else { /* proportional editing falloff */ -- cgit v1.2.3 From af79ac944d7b14f8ce24548345cac5a34ff4de55 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Wed, 1 Aug 2018 10:39:16 +0200 Subject: Cleanup: Replace "Move Color" to "Assign Material" --- source/blender/editors/gpencil/gpencil_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c58c45b3117..01cf8aeb7f1 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1192,7 +1192,7 @@ void GPENCIL_OT_stroke_change_color(wmOperatorType *ot) /* identifiers */ ot->name = "Change Stroke Color"; ot->idname = "GPENCIL_OT_stroke_change_color"; - ot->description = "Move selected strokes to active color"; + ot->description = "Move selected strokes to active material"; /* callbacks */ ot->exec = gp_stroke_change_color_exec; -- cgit v1.2.3 From 20e5fc4d328bf566841f22b16de809da8de15bf7 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Wed, 1 Aug 2018 10:58:10 +0200 Subject: Fix context problem when render in background mode Bug reported by Sergey. --- source/blender/draw/intern/draw_manager.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'source') diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 0c731811f32..ab50e6673f2 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1659,7 +1659,24 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph Render *render = engine->re; /* Changing Context */ /* GPXX Review this context */ - DRW_opengl_context_enable(); + if (G.background && DST.gl_context == NULL) { + WM_init_opengl(G_MAIN); + } + + void *re_gl_context = RE_gl_context_get(render); + void *re_gpu_context = NULL; + + /* Changing Context */ + if (re_gl_context != NULL) { + DRW_opengl_render_context_enable(re_gl_context); + /* We need to query gpu context after a gl context has been bound. */ + re_gpu_context = RE_gpu_context_get(render); + DRW_gawain_render_context_enable(re_gpu_context); + } + else { + DRW_opengl_context_enable(); + } + /* Reset before using it. */ drw_state_prepare_clean_for_draw(&DST); DST.options.is_image_render = true; -- cgit v1.2.3 From ddd62f1b1063d69df5171c7b3457ffcffcc6b0e4 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Wed, 1 Aug 2018 11:21:37 +0200 Subject: Cleanup: Remove ToDo comment --- source/blender/draw/intern/draw_manager.c | 1 - 1 file changed, 1 deletion(-) (limited to 'source') diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index ab50e6673f2..ba53c3aa664 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1658,7 +1658,6 @@ void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph RenderData *r = &scene->r; Render *render = engine->re; /* Changing Context */ - /* GPXX Review this context */ if (G.background && DST.gl_context == NULL) { WM_init_opengl(G_MAIN); } -- cgit v1.2.3