diff options
205 files changed, 12785 insertions, 15548 deletions
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index 09ce29200b3..334e8f2ba69 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -188,7 +188,6 @@ const UserDef U_default = { .pie_menu_radius = 100, .pie_menu_threshold = 12, .opensubdiv_compute_type = 0, - .gpencil_multisamples = 4, .factor_display_type = USER_FACTOR_AS_FACTOR, .render_display_type = USER_RENDER_DISPLAY_WINDOW, .filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW, diff --git a/release/scripts/presets/gpencil_material/fill_only.py b/release/scripts/presets/gpencil_material/fill_only.py index c60811d25bc..be045ce5fa4 100644 --- a/release/scripts/presets/gpencil_material/fill_only.py +++ b/release/scripts/presets/gpencil_material/fill_only.py @@ -7,8 +7,6 @@ gpcolor.stroke_style = 'SOLID' gpcolor.color = (0.0, 0.0, 0.0, 0.0) gpcolor.stroke_image = None gpcolor.pixel_size = 100.0 -gpcolor.use_stroke_pattern = False -gpcolor.use_stroke_texture_mix = False gpcolor.mix_stroke_factor = 0.0 gpcolor.alignment_mode = 'PATH' gpcolor.fill_style = 'SOLID' @@ -22,14 +20,11 @@ gpcolor.pattern_shift = (0.0, 0.0) gpcolor.pattern_scale = (1.0, 1.0) gpcolor.pattern_radius = 0.5 gpcolor.pattern_angle = 0.0 -gpcolor.pattern_gridsize = 0.1 -gpcolor.use_fill_pattern = False gpcolor.texture_offset = (0.0, 0.0) gpcolor.texture_scale = (1.0, 1.0) gpcolor.texture_angle = 0.0 gpcolor.texture_opacity = 1.0 gpcolor.texture_clamp = False -gpcolor.use_fill_texture_mix = False gpcolor.mix_factor = 0.0 gpcolor.show_stroke = False gpcolor.show_fill = True diff --git a/release/scripts/presets/gpencil_material/stroke_and_fill.py b/release/scripts/presets/gpencil_material/stroke_and_fill.py index ee18eeb0114..3860c790d16 100644 --- a/release/scripts/presets/gpencil_material/stroke_and_fill.py +++ b/release/scripts/presets/gpencil_material/stroke_and_fill.py @@ -7,8 +7,6 @@ gpcolor.stroke_style = 'SOLID' gpcolor.color = (0.0, 0.0, 0.0, 1.0) gpcolor.stroke_image = None gpcolor.pixel_size = 100.0 -gpcolor.use_stroke_pattern = False -gpcolor.use_stroke_texture_mix = False gpcolor.mix_stroke_factor = 0.0 gpcolor.alignment_mode = 'PATH' gpcolor.fill_style = 'SOLID' @@ -22,14 +20,11 @@ gpcolor.pattern_shift = (0.0, 0.0) gpcolor.pattern_scale = (1.0, 1.0) gpcolor.pattern_radius = 0.5 gpcolor.pattern_angle = 0.0 -gpcolor.pattern_gridsize = 0.1 -gpcolor.use_fill_pattern = False gpcolor.texture_offset = (0.0, 0.0) gpcolor.texture_scale = (1.0, 1.0) gpcolor.texture_angle = 0.0 gpcolor.texture_opacity = 1.0 gpcolor.texture_clamp = False -gpcolor.use_fill_texture_mix = False gpcolor.mix_factor = 0.0 gpcolor.show_stroke = True gpcolor.show_fill = True diff --git a/release/scripts/presets/gpencil_material/stroke_only.py b/release/scripts/presets/gpencil_material/stroke_only.py index 3ca05c6a073..4bd88af7496 100644 --- a/release/scripts/presets/gpencil_material/stroke_only.py +++ b/release/scripts/presets/gpencil_material/stroke_only.py @@ -7,8 +7,6 @@ gpcolor.stroke_style = 'SOLID' gpcolor.color = (0.0, 0.0, 0.0, 1.0) gpcolor.stroke_image = None gpcolor.pixel_size = 100.0 -gpcolor.use_stroke_pattern = False -gpcolor.use_stroke_texture_mix = False gpcolor.mix_stroke_factor = 0.0 gpcolor.alignment_mode = 'PATH' gpcolor.fill_style = 'SOLID' @@ -22,14 +20,11 @@ gpcolor.pattern_shift = (0.0, 0.0) gpcolor.pattern_scale = (1.0, 1.0) gpcolor.pattern_radius = 0.5 gpcolor.pattern_angle = 0.0 -gpcolor.pattern_gridsize = 0.1 -gpcolor.use_fill_pattern = False gpcolor.texture_offset = (0.0, 0.0) gpcolor.texture_scale = (1.0, 1.0) gpcolor.texture_angle = 0.0 gpcolor.texture_opacity = 1.0 gpcolor.texture_clamp = False -gpcolor.use_fill_texture_mix = False gpcolor.mix_factor = 0.0 gpcolor.show_stroke = True gpcolor.show_fill = False diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 8b07d239616..da91f7e841d 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -672,8 +672,6 @@ class AddPresetGpencilMaterial(AddPresetBase, Operator): "gpcolor.color", "gpcolor.stroke_image", "gpcolor.pixel_size", - "gpcolor.use_stroke_pattern", - "gpcolor.use_stroke_texture_mix", "gpcolor.mix_stroke_factor", "gpcolor.alignment_mode", "gpcolor.fill_style", @@ -687,14 +685,11 @@ class AddPresetGpencilMaterial(AddPresetBase, Operator): "gpcolor.pattern_scale", "gpcolor.pattern_radius", "gpcolor.pattern_angle", - "gpcolor.pattern_gridsize", - "gpcolor.use_fill_pattern", "gpcolor.texture_offset", "gpcolor.texture_scale", "gpcolor.texture_angle", "gpcolor.texture_opacity", "gpcolor.texture_clamp", - "gpcolor.use_fill_texture_mix", "gpcolor.mix_factor", "gpcolor.show_stroke", "gpcolor.show_fill", diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py index 9c2f88173bf..02745874283 100644 --- a/release/scripts/startup/bl_ui/properties_data_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -171,12 +171,18 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel): layout.use_property_decorate = True col = layout.column(align=True) - col = layout.row(align=True) - col.prop(gpl, "blend_mode", text="Blend") + if not gpl.mask_layer: + col = layout.row(align=True) + col.prop(gpl, "blend_mode", text="Blend") + col = layout.row(align=True) + col.prop_search(gpl, "mask_layer_name", gpd, "layers", icon='GREASEPENCIL') col = layout.row(align=True) col.prop(gpl, "opacity", text="Opacity", slider=True) + col = layout.row(align=True) + col.prop(gpl, "use_lights") + class DATA_PT_gpencil_layer_adjustments(LayerDataButtonsPanel, GreasePencilLayerAdjustmentsPanel, Panel): bl_label = "Adjustments" @@ -363,9 +369,6 @@ class DATA_PT_gpencil_strokes(DataButtonsPanel, Panel): sub.active = gpd.stroke_thickness_space == 'WORLDSPACE' sub.prop(gpd, "pixel_factor", text="Thickness Scale") - layout.prop(gpd, "use_force_fill_recalc", text="Force Fill Update") - layout.prop(gpd, "use_adaptive_uv", text="Adaptive UVs") - class DATA_PT_gpencil_display(DataButtonsPanel, Panel): bl_label = "Viewport Display" @@ -380,8 +383,6 @@ class DATA_PT_gpencil_display(DataButtonsPanel, Panel): gpl = gpd.layers.active layout.prop(gpd, "edit_line_color", text="Edit Line Color") - if gpl: - layout.prop(gpd, "show_stroke_direction", text="Show Stroke Directions") class DATA_PT_gpencil_canvas(DataButtonsPanel, Panel): diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 644dfbeae69..f3fbb35160d 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -1945,7 +1945,6 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "factor") row = layout.row() - row.prop(md, "create_materials") row.prop(md, "modify_color") col = layout.column() @@ -2024,7 +2023,6 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "value", text="V", slider=True) row = layout.row() - row.prop(md, "create_materials") row.prop(md, "modify_color") col = layout.column() @@ -2056,21 +2054,14 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.label(text="Opacity:") col.prop(md, "factor") + col.prop(md, "modify_color", text="Change") - row = layout.row() - row.prop(md, "opacity_mode", text="Mode") - - if md.opacity_mode == 'MATERIAL': - row = layout.row() - row.prop(md, "create_materials") - row.prop(md, "modify_color", text="Change") - else: - col = layout.column() - col.separator() - col.label(text="Vertex Group:") - row = col.row(align=True) - row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") - row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT') + col = layout.column() + col.separator() + col.label(text="Vertex Group:") + row = col.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT') col = layout.column() col.separator() diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py index fce86446dfc..8a803bf2c55 100644 --- a/release/scripts/startup/bl_ui/properties_data_shaderfx.py +++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py @@ -75,8 +75,7 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel): if fx.mode == 'BITONE': layout.prop(fx, "high_color", text="High Color") - if fx.mode in {'BITONE', 'CUSTOM', 'TRANSPARENT'}: - layout.prop(fx, "factor") + layout.prop(fx, "factor") def FX_WAVE(self, layout, fx): row = layout.row(align=True) @@ -144,18 +143,10 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel): layout.prop(fx, "radius") layout.prop(fx, "angle") - layout.prop(fx, "use_transparent") - def FX_FLIP(self, layout, fx): layout.prop(fx, "flip_horizontal") layout.prop(fx, "flip_vertical") - def FX_LIGHT(self, layout, fx): - layout.prop(fx, "object", text="Object") - - layout.prop(fx, "energy") - layout.prop(fx, "ambient") - classes = ( DATA_PT_shader_fx, diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index e6457f36c5a..f0858ed49d8 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -625,11 +625,7 @@ class GreasePencilMaterialsPanel: if ma is not None and ma.grease_pencil is not None: gpcolor = ma.grease_pencil - if ( - gpcolor.stroke_style == 'SOLID' or - gpcolor.use_stroke_pattern or - gpcolor.use_stroke_texture_mix - ): + if gpcolor.stroke_style == 'SOLID': row = layout.row() row.prop(gpcolor, "color", text="Stroke Color") @@ -694,9 +690,12 @@ class GPENCIL_UL_layer(UIList): row.prop(gpl, "info", text="", emboss=False) row = layout.row(align=True) - row.prop(gpl, "mask_layer", text="", - icon='MOD_MASK' if gpl.mask_layer else 'LAYER_ACTIVE', - emboss=False) + + icon_mask = 'LAYER_ACTIVE' + if gpl.mask_layer: + icon_mask = 'HOLDOUT_ON' if gpl.invert_mask else 'MOD_MASK' + + row.prop(gpl, "mask_layer", text="", icon=icon_mask, emboss=False) subrow = row.row(align=True) subrow.prop( @@ -732,16 +731,12 @@ class GreasePencilSimplifyPanel: layout.active = rd.simplify_gpencil col = layout.column() - col.prop(rd, "simplify_gpencil_onplay", text="Playback Only") - col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers") - col.prop(rd, "simplify_gpencil_shader_fx", text="ShaderFX") - col.prop(rd, "simplify_gpencil_blend", text="Layers Blending") - col.prop(rd, "simplify_gpencil_tint", text="Layers Tinting") - + col.prop(rd, "simplify_gpencil_onplay") col.prop(rd, "simplify_gpencil_view_fill") - sub = col.column() - sub.active = rd.simplify_gpencil_view_fill - sub.prop(rd, "simplify_gpencil_remove_lines", text="Lines") + col.prop(rd, "simplify_gpencil_modifier") + col.prop(rd, "simplify_gpencil_shader_fx") + col.prop(rd, "simplify_gpencil_tint") + col.prop(rd, "simplify_gpencil_antialiasing") class GreasePencilLayerAdjustmentsPanel: diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py index 1f4ec108c58..664c1cf3cbb 100644 --- a/release/scripts/startup/bl_ui/properties_material_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py @@ -151,22 +151,20 @@ class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel): row.enabled = not gpcolor.lock col = row.column(align=True) col.template_ID(gpcolor, "stroke_image", open="image.open") - if gpcolor.mode == 'LINE': - col.prop(gpcolor, "pixel_size", text="UV Factor") - col.prop(gpcolor, "use_stroke_pattern", text="Use As Stencil Mask") - if gpcolor.use_stroke_pattern is False: - col.prop(gpcolor, "use_stroke_texture_mix", text="Mix Color") - if gpcolor.use_stroke_texture_mix is True: - col.prop(gpcolor, "mix_stroke_factor", text="Factor") + row = col.row() + row.prop(gpcolor, "color", text="Base Color") - if (gpcolor.stroke_style == 'SOLID' or gpcolor.use_stroke_pattern or gpcolor.use_stroke_texture_mix): - col.prop(gpcolor, "color", text="Base Color") + if gpcolor.stroke_style == 'TEXTURE': + row = col.row() + row.prop(gpcolor, "mix_stroke_factor", text="Factor", slider=True) + if gpcolor.mode == 'LINE': + col.prop(gpcolor, "pixel_size", text="UV Factor") if gpcolor.mode in {'DOTS', 'BOX'}: col.prop(gpcolor, "alignment_mode") - if gpcolor.mode == 'LINE' and gpcolor.stroke_style != 'TEXTURE': + if gpcolor.mode == 'LINE': col.prop(gpcolor, "use_overlap_strokes") @@ -192,55 +190,35 @@ class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel): col.enabled = not gpcolor.lock col.prop(gpcolor, "fill_style", text="Style") - if gpcolor.fill_style == 'GRADIENT': - col.prop(gpcolor, "gradient_type") - if gpcolor.fill_style != 'TEXTURE': + if gpcolor.fill_style == 'SOLID': col.prop(gpcolor, "fill_color", text="Base Color") - if gpcolor.fill_style in {'GRADIENT', 'CHECKER'}: - col.prop(gpcolor, "mix_color", text="Secondary Color") - - if gpcolor.fill_style == 'GRADIENT': - col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True) - - if gpcolor.fill_style in {'GRADIENT', 'CHECKER'}: - col.prop(gpcolor, "flip", text="Flip Colors") - - col.prop(gpcolor, "pattern_shift", text="Location") - col.prop(gpcolor, "pattern_scale", text="Scale") + elif gpcolor.fill_style == 'GRADIENT': + col.prop(gpcolor, "gradient_type") - if gpcolor.gradient_type == 'RADIAL' and gpcolor.fill_style not in {'SOLID', 'CHECKER'}: - col.prop(gpcolor, "pattern_radius", text="Radius") - else: - if gpcolor.fill_style != 'SOLID': - col.prop(gpcolor, "pattern_angle", text="Angle") + col.prop(gpcolor, "fill_color", text="Base Color") + col.prop(gpcolor, "mix_color", text="Secondary Color") + col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True) + col.prop(gpcolor, "flip", text="Flip Colors") - if gpcolor.fill_style == 'CHECKER': - col.prop(gpcolor, "pattern_gridsize", text="Box Size") + col.prop(gpcolor, "texture_offset", text="Location") + col.prop(gpcolor, "texture_scale", text="Scale") + if gpcolor.gradient_type == 'LINEAR': + col.prop(gpcolor, "texture_angle", text="Rotation") - # Texture - if gpcolor.fill_style == 'TEXTURE' or (gpcolor.use_fill_texture_mix is True and gpcolor.fill_style == 'SOLID'): + elif gpcolor.fill_style == 'TEXTURE': col.template_ID(gpcolor, "fill_image", open="image.open") - if gpcolor.fill_style == 'TEXTURE': - col.prop(gpcolor, "use_fill_pattern", text="Use as Stencil Mask") - if gpcolor.use_fill_pattern is True: - col.prop(gpcolor, "fill_color", text="Base Color") + col.prop(gpcolor, "fill_color", text="Base Color") + col.prop(gpcolor, "texture_opacity", slider=True) + col.prop(gpcolor, "mix_factor", text="Factor", slider=True) - col.prop(gpcolor, "texture_offset", text="Offset") + col.prop(gpcolor, "texture_offset", text="Location") + col.prop(gpcolor, "texture_angle", text="Rotation") col.prop(gpcolor, "texture_scale", text="Scale") - col.prop(gpcolor, "texture_angle") - col.prop(gpcolor, "texture_opacity") col.prop(gpcolor, "texture_clamp", text="Clip Image") - if gpcolor.use_fill_pattern is False: - col.prop(gpcolor, "use_fill_texture_mix", text="Mix with Color") - - if gpcolor.use_fill_texture_mix is True: - col.prop(gpcolor, "fill_color", text="Mix Color") - col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True) - class MATERIAL_PT_gpencil_preview(GPMaterialButtonsPanel, Panel): bl_label = "Preview" diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index bb020084b03..33ba981e235 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -397,6 +397,27 @@ class OBJECT_PT_visibility(ObjectButtonsPanel, Panel): col.prop(ob, "hide_select", text="Selectable", toggle=False, invert_checkbox=True) +class OBJECT_PT_greasepencil_light(ObjectButtonsPanel, Panel): + bl_label = "Grease Pencil" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + @classmethod + def poll(cls, context): + return (context.object) and (context.engine in cls.COMPAT_ENGINES) and (context.object.type == 'GPENCIL') + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) + layout = self.layout + ob = context.object + + col = flow.column() + col.prop(ob, "use_grease_pencil_lights", toggle=False) + + class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} _context_path = "object" @@ -417,6 +438,7 @@ classes = ( OBJECT_PT_display, OBJECT_PT_display_bounds, OBJECT_PT_visibility, + OBJECT_PT_greasepencil_light, OBJECT_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index a09e263fd87..6d0e1fdb289 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -699,6 +699,9 @@ class DOPESHEET_PT_gpencil_mode(LayersDopeSheetPanel, Panel): row = layout.row(align=True) row.prop(gpl, "opacity", text="Opacity", slider=True) + row = layout.row(align=True) + row.prop(gpl, "use_lights") + class DOPESHEET_PT_gpencil_layer_adjustments(LayersDopeSheetPanel, GreasePencilLayerAdjustmentsPanel, Panel): bl_label = "Adjustments" diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 192b239ac03..82a1f5b6b0a 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -169,7 +169,7 @@ class TOPBAR_PT_gpencil_layers(Panel): icon='MOD_MASK' if gpl.mask_layer else 'LAYER_ACTIVE') srow = col.row(align=True) - srow.prop(gpl, "use_solo_mode", text="Show Only On Keyframed") + srow.prop(gpl, "use_lights") col = row.column() diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index ad5e7b5442c..1e64b55cb96 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -669,7 +669,6 @@ class USERPREF_PT_viewport_quality(ViewportPanel, CenterAlignMixIn, Panel): flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False) flow.prop(system, "viewport_aa") - flow.prop(system, "gpencil_multi_sample", text="Grease Pencil Multisampling") flow.prop(system, "use_overlay_smooth_wire") flow.prop(system, "use_edit_mode_smooth_wire") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index e9724704022..c49b22ed693 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -434,17 +434,16 @@ class _draw_tool_settings_context_mode: if brush.gpencil_tool in {'DRAW', 'FILL'} and ma: gp_style = ma.grease_pencil - if gp_style.stroke_style != 'TEXTURE': - row.separator(factor=0.4) - row.prop(settings, "use_vertex_color", text="", - icon='CHECKBOX_HLT' if settings.use_vertex_color else 'CHECKBOX_DEHLT') - sub_row = row.row(align=True) - sub_row.enabled = settings.use_vertex_color - sub_row.prop(brush, "color", text="") - sub_row.popover( - panel="TOPBAR_PT_gpencil_vertexcolor", - text="Vertex Color", - ) + row.separator(factor=0.4) + row.prop(settings, "use_vertex_color", text="", + icon='CHECKBOX_HLT' if settings.use_vertex_color else 'CHECKBOX_DEHLT') + sub_row = row.row(align=True) + sub_row.enabled = settings.use_vertex_color + sub_row.prop(brush, "color", text="") + sub_row.popover( + panel="TOPBAR_PT_gpencil_vertexcolor", + text="Vertex Color", + ) row = layout.row(align=True) tool_settings = context.scene.tool_settings @@ -6480,20 +6479,29 @@ class VIEW3D_PT_overlay_gpencil_options(Panel): sub.prop(overlay, "gpencil_fade_layer", text="Fade Layers", slider=True) row = col.row() - row.prop(overlay, "use_gpencil_paper", text="") + row.prop(overlay, "use_gpencil_fade_objects", text="") sub = row.row(align=True) - sub.active = overlay.use_gpencil_paper - sub.prop(overlay, "gpencil_paper_opacity", text="Fade Objects", slider=True) - sub.prop(overlay, "use_gpencil_fade_objects", text="", icon='OUTLINER_OB_GREASEPENCIL') + sub.active = overlay.use_gpencil_fade_objects + sub.prop(overlay, "gpencil_fade_objects", text="Fade Objects", slider=True) + sub.prop(overlay, "use_gpencil_fade_gp_objects", text="", icon='OUTLINER_OB_GREASEPENCIL') if context.object.mode in {'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}: - layout.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines") - layout.prop(overlay, "use_gpencil_multiedit_line_only", text="Show Edit Lines only in multiframe") + split = layout.split() + col = split.column() + col.prop(overlay, "use_gpencil_edit_lines", text="Edit Lines") + col = split.column() + col.prop(overlay, "use_gpencil_multiedit_line_only", text="Only in Multiframe") + + if context.object.mode == 'EDIT_GPENCIL': + split = layout.split() + col = split.column() + col.prop(overlay, "use_gpencil_show_directions") + col = split.column() + col.prop(overlay, "use_gpencil_show_material_name", text="Material Name") - if context.object.mode in {'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}: layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True) - if context.object.mode in {'PAINT_GPENCIL', 'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'VERTEX_GPENCIL'}: + if context.object.mode in {'PAINT_GPENCIL', 'VERTEX_GPENCIL'}: layout.label(text="Vertex Paint") layout.prop(overlay, "gpencil_vertex_paint_opacity", text="Opacity", slider=True) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 1d403fc488f..36101e3a3bf 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1453,6 +1453,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel): bl_label = "Advanced" bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_settings' bl_category = "Tool" + bl_ui_units_x = 12 bl_options = {'DEFAULT_CLOSED'} @classmethod diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 8dc19ed32e5..495fe4eb7f6 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -42,7 +42,7 @@ struct bGPDlayer; struct bGPDspoint; struct bGPDstroke; struct bGPdata; - +struct MaterialGPencilStyle; struct MDeformVert; #define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)) @@ -52,18 +52,15 @@ struct MDeformVert; #define GPENCIL_SIMPLIFY_FILL(scene, playing) \ ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL))) -#define GPENCIL_SIMPLIFY_MODIF(scene, playing) \ - ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ - (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER))) +#define GPENCIL_SIMPLIFY_MODIF(scene) \ + ((GPENCIL_SIMPLIFY(scene) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER))) #define GPENCIL_SIMPLIFY_FX(scene, playing) \ ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX))) -#define GPENCIL_SIMPLIFY_BLEND(scene, playing) \ - ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ - (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND))) -#define GPENCIL_SIMPLIFY_TINT(scene, playing) \ - ((GPENCIL_SIMPLIFY_ONPLAY(playing) && (GPENCIL_SIMPLIFY(scene)) && \ - (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_TINT))) +#define GPENCIL_SIMPLIFY_TINT(scene) \ + ((GPENCIL_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_TINT)) +#define GPENCIL_SIMPLIFY_AA(scene) \ + ((GPENCIL_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_AA)) /* Vertex Color macros. */ #define GPENCIL_USE_VERTEX_COLOR(toolsettings) \ @@ -91,8 +88,8 @@ 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); -bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *gpf_eval); void BKE_gpencil_free(struct bGPdata *gpd, bool free_all); +void BKE_gpencil_eval_delete(struct bGPdata *gpd_eval); void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd); void BKE_gpencil_batch_cache_free(struct bGPdata *gpd); @@ -107,10 +104,11 @@ 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); +struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points); void BKE_gpencil_copy_data(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); @@ -145,12 +143,11 @@ void BKE_gpencil_stroke_add_points(struct bGPDstroke *gps, const int totpoints, const float mat[4][4]); -struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, - int mat_idx, - int totpoints, - short thickness); +struct bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness); +struct bGPDstroke *BKE_gpencil_stroke_add( + struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head); -struct bGPDstroke *BKE_gpencil_add_stroke_existing_style(struct bGPDframe *gpf, +struct bGPDstroke *BKE_gpencil_stroke_add_existing_style(struct bGPDframe *gpf, struct bGPDstroke *existing, int mat_idx, int totpoints, @@ -161,7 +158,7 @@ struct bGPDstroke *BKE_gpencil_add_stroke_existing_style(struct bGPDframe *gpf, #define GPENCIL_STRENGTH_MIN 0.003f #define GP_VERTEX_MASK_ATTENUATE 0.3f -bool gpencil_layer_is_editable(const struct bGPDlayer *gpl); +bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl); /* How gpencil_layer_getframe() should behave when there * is no existing GP-Frame on the frame requested. @@ -176,14 +173,14 @@ typedef enum eGP_GetFrame_Mode { GP_GETFRAME_ADD_COPY = 2, } eGP_GetFrame_Mode; -struct bGPDframe *BKE_gpencil_layer_getframe(struct bGPDlayer *gpl, - int cframe, - eGP_GetFrame_Mode addnew); -struct bGPDframe *BKE_gpencil_layer_find_frame(struct bGPDlayer *gpl, int cframe); -bool BKE_gpencil_layer_delframe(struct bGPDlayer *gpl, struct bGPDframe *gpf); +struct bGPDframe *BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, + int cframe, + eGP_GetFrame_Mode addnew); +struct bGPDframe *BKE_gpencil_layer_frame_find(struct bGPDlayer *gpl, int cframe); +bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf); -struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd); -void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active); +struct bGPDlayer *BKE_gpencil_layer_active_get(struct bGPdata *gpd); +void BKE_gpencil_layer_active_set(struct bGPdata *gpd, struct bGPDlayer *active); void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl); void BKE_gpencil_layer_autolock_set(struct bGPdata *gpd, const bool unlock); @@ -205,9 +202,9 @@ struct Material *BKE_gpencil_object_material_new(struct Main *bmain, const char *name, int *r_index); -int BKE_gpencil_object_material_get_index(struct Object *ob, struct Material *ma); +int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma); -struct Material *BKE_gpencil_object_material_get_from_brush(struct Object *ob, +struct Material *BKE_gpencil_object_material_from_brush_get(struct Object *ob, struct Brush *brush); int BKE_gpencil_object_material_get_index_from_brush(struct Object *ob, struct Brush *brush); @@ -228,6 +225,7 @@ bool BKE_gpencil_stroke_select_check(const struct bGPDstroke *gps); struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob); void BKE_gpencil_centroid_3d(struct bGPdata *gpd, float r_centroid[3]); +void BKE_gpencil_stroke_collision_get(struct bGPDstroke *gps); /* vertex groups */ void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps); @@ -239,11 +237,11 @@ 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_subdivide(struct bGPDstroke *gps, int level, int flag); -bool BKE_gpencil_trim_stroke(struct bGPDstroke *gps); -void BKE_gpencil_merge_distance_stroke(struct bGPDframe *gpf, +void BKE_gpencil_stroke_simplify(struct bGPDstroke *gps, float factor); +void BKE_gpencil_stroke_simplify_fixed(struct bGPDstroke *gps); +void BKE_gpencil_stroke_subdivide(struct bGPDstroke *gps, int level, int flag); +bool BKE_gpencil_stroke_trim(struct bGPDstroke *gps); +void BKE_gpencil_stroke_merge_distance(struct bGPDframe *gpf, struct bGPDstroke *gps, const float threshold, const bool use_unselected); @@ -259,27 +257,29 @@ void BKE_gpencil_stroke_2d_flat_ref(const struct bGPDspoint *ref_points, float (*points2d)[2], const float scale, int *r_direction); -void BKE_gpencil_triangulate_stroke_fill(struct bGPdata *gpd, struct bGPDstroke *gps); +void BKE_gpencil_stroke_fill_triangulate(struct bGPDstroke *gps); +void BKE_gpencil_stroke_geometry_update(struct bGPDstroke *gps); +void BKE_gpencil_stroke_uv_update(struct bGPDstroke *gps); void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]); -bool BKE_gpencil_sample_stroke(struct bGPDstroke *gps, const float dist, const bool select); -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); -bool BKE_gpencil_close_stroke(struct bGPDstroke *gps); +bool BKE_gpencil_stroke_sample(struct bGPDstroke *gps, const float dist, const bool select); +bool BKE_gpencil_stroke_smooth(struct bGPDstroke *gps, int i, float inf); +bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_stroke_close(struct bGPDstroke *gps); void BKE_gpencil_dissolve_points(struct bGPDframe *gpf, struct bGPDstroke *gps, const short tag); -bool BKE_gpencil_stretch_stroke(struct bGPDstroke *gps, const float dist, const float tip_length); -bool BKE_gpencil_trim_stroke_points(struct bGPDstroke *gps, +bool BKE_gpencil_stroke_stretch(struct bGPDstroke *gps, const float dist, const float tip_length); +bool BKE_gpencil_stroke_trim_points(struct bGPDstroke *gps, const int index_from, const int index_to); -bool BKE_gpencil_split_stroke(struct bGPDframe *gpf, +bool BKE_gpencil_stroke_split(struct bGPDframe *gpf, struct bGPDstroke *gps, const int before_index, struct bGPDstroke **remaining_gps); -bool BKE_gpencil_shrink_stroke(struct bGPDstroke *gps, const float dist); +bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist); float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d); @@ -302,7 +302,39 @@ bool BKE_gpencil_from_image(struct SpaceImage *sima, const float size, const bool mask); +/* Iterator */ +/* frame & stroke are NULL if it is a layer callback. */ +typedef void (*gpIterCb)(struct bGPDlayer *layer, + struct bGPDframe *frame, + struct bGPDstroke *stroke, + void *thunk); + +void BKE_gpencil_visible_stroke_iter(struct Object *ob, + gpIterCb layer_cb, + gpIterCb stroke_cb, + void *thunk, + bool do_onion, + int cfra); + extern void (*BKE_gpencil_batch_cache_dirty_tag_cb)(struct bGPdata *gpd); extern void (*BKE_gpencil_batch_cache_free_cb)(struct bGPdata *gpd); +#ifdef __cplusplus +extern "C" { +#endif +void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig, + const struct bGPDframe *gpf_eval); +void BKE_gpencil_update_orig_pointers(const struct Object *ob_orig, const struct Object *ob_eval); + +void BKE_gpencil_parent_matrix_get(const struct Depsgraph *depsgraph, + struct Object *obact, + struct bGPDlayer *gpl, + float diff_mat[4][4]); + +void BKE_gpencil_update_layer_parent(const struct Depsgraph *depsgraph, struct Object *ob); + +#ifdef __cplusplus +} +#endif + #endif /* __BKE_GPENCIL_H__ */ diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index 9cbc7d05ac2..07cc041cc51 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -293,24 +293,6 @@ bool BKE_gpencil_has_geometry_modifiers(struct Object *ob); bool BKE_gpencil_has_time_modifiers(struct Object *ob); bool BKE_gpencil_has_transform_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); -int BKE_gpencil_time_modifier(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct bGPDlayer *gpl, - int cfra, - bool is_render); - void BKE_gpencil_lattice_init(struct Object *ob); void BKE_gpencil_lattice_clear(struct Object *ob); @@ -318,4 +300,7 @@ void BKE_gpencil_modifiers_calc(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); +void BKE_gpencil_prepare_eval_data(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); #endif /* __BKE_GPENCIL_MODIFIER_H__ */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2879905795b..c38c4a44d54 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -326,6 +326,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) /* Pin the matterial to the brush. */ brush->gpencil_settings->flag |= GP_BRUSH_MATERIAL_PINNED; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_INK_PEN: { @@ -362,6 +367,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_INK_PEN_ROUGH: { @@ -399,6 +409,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_MARKER_BOLD: { @@ -436,6 +451,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_MARKER_CHISEL: { @@ -466,6 +486,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_CHISEL; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_PEN: { @@ -497,6 +522,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_PENCIL_SOFT: { @@ -528,6 +558,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_PENCIL: { @@ -558,6 +593,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL; brush->gpencil_tool = GPAINT_TOOL_DRAW; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_FILL_AREA: { @@ -580,6 +620,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_tool = GPAINT_TOOL_FILL; brush->gpencil_settings->vertex_mode = GPPAINT_MODE_FILL; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_ERASER_SOFT: { @@ -635,12 +680,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->draw_strength = 0.8f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->rgb[0] = 0.757f; - brush->rgb[1] = 0.659f; - brush->rgb[2] = 0.824f; - zero_v3(brush->secondary_rgb); + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_VERTEX_DRAW: { @@ -652,9 +697,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->draw_strength = 0.8f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; - brush->rgb[0] = 0.757f; - brush->rgb[1] = 0.659f; - brush->rgb[2] = 0.824f; + + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; zero_v3(brush->secondary_rgb); break; @@ -668,6 +714,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->draw_strength = 0.8f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_VERTEX_AVERAGE: { @@ -679,6 +731,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->draw_strength = 0.8f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_VERTEX_SMEAR: { @@ -690,6 +748,12 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->draw_strength = 0.8f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_VERTEX_REPLACE: { @@ -702,6 +766,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->draw_strength = 0.8f; brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE; + brush->rgb[0] = 1.0f; + brush->rgb[1] = 1.0f; + brush->rgb[2] = 1.0f; + + zero_v3(brush->secondary_rgb); break; } case GP_BRUSH_PRESET_SMOOTH_STROKE: { @@ -843,7 +912,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) static Brush *gpencil_brush_ensure(Main *bmain, ToolSettings *ts, - char *brush_name, + const char *brush_name, eObjectMode mode) { Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 8612973fd11..610c8b4280c 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -69,6 +69,7 @@ #include "BLI_math_color.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" static CLG_LogRef LOG = {"bke.gpencil"}; @@ -158,24 +159,6 @@ 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 *gpf_eval) -{ - bGPDstroke *gps_next; - if (!gpf_eval) { - return false; - } - - /* free strokes */ - for (bGPDstroke *gps = gpf_eval->strokes.first; gps; gps = gps_next) { - gps_next = gps->next; - BKE_gpencil_free_stroke(gps); - } - BLI_listbase_clear(&gpf_eval->strokes); - - return true; -} - /* Free all of a gp-layer's frames */ void BKE_gpencil_free_frames(bGPDlayer *gpl) { @@ -236,6 +219,13 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all) } } +void BKE_gpencil_eval_delete(bGPdata *gpd_eval) +{ + BKE_gpencil_free(gpd_eval, true); + BKE_libblock_free_data(&gpd_eval->id, false); + MEM_freeN(gpd_eval); +} + /* ************************************************** */ /* Container Creation */ @@ -313,7 +303,7 @@ bGPDframe *BKE_gpencil_frame_addcopy(bGPDlayer *gpl, int cframe) new_frame = BKE_gpencil_frame_duplicate(gpl->actframe); /* Find frame to insert it before */ - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (gpf->framenum > cframe) { /* Add it here */ BLI_insertlinkbefore(&gpl->frames, gpf, new_frame); @@ -362,7 +352,7 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti /* allocate memory for frame and add to end of list */ gpl = MEM_callocN(sizeof(bGPDlayer), "bGPDlayer"); - gpl_active = BKE_gpencil_layer_getactive(gpd); + gpl_active = BKE_gpencil_layer_active_get(gpd); /* add to datablock */ if (gpl_active == NULL) { @@ -405,9 +395,12 @@ bGPDlayer *BKE_gpencil_layer_addnew(bGPdata *gpd, const char *name, bool setacti offsetof(bGPDlayer, info), sizeof(gpl->info)); + /* Enable always affected by scene lights. */ + gpl->flag |= GP_LAYER_USE_LIGHTS; + gpl->mask_layer[0] = '\0'; /* make this one the active one */ if (setactive) { - BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_active_set(gpd, gpl); } /* return layer */ @@ -427,7 +420,6 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) /* general flags */ gpd->flag |= GP_DATA_VIEWALIGN; - gpd->flag |= GP_DATA_STROKE_FORCE_RECALC; /* always enable object onion skin switch */ gpd->flag |= GP_DATA_SHOW_ONIONSKINS; /* GP object specific settings */ @@ -482,13 +474,14 @@ void BKE_gpencil_stroke_add_points(bGPDstroke *gps, } } -/* Create a new stroke, with pre-allocated data buffers */ -bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, short thickness) +/* Create a new stroke, with pre-allocated data buffers. */ +bGPDstroke *BKE_gpencil_stroke_new(int mat_idx, int totpoints, short thickness) { /* allocate memory for a new stroke */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); gps->thickness = thickness; + gps->fill_opacity_fac = 1.0f; gps->gradient_f = 1.0f; gps->gradient_s[0] = 1.0f; gps->gradient_s[1] = 1.0f; @@ -497,30 +490,44 @@ bGPDstroke *BKE_gpencil_add_stroke(bGPDframe *gpf, int mat_idx, int totpoints, s gps->inittime = 0; - /* enable recalculation flag by default */ - gps->flag = GP_STROKE_RECALC_GEOMETRY | GP_STROKE_3DSPACE; + gps->flag = GP_STROKE_3DSPACE; gps->totpoints = totpoints; gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); /* initialize triangle memory to dummy data */ gps->triangles = NULL; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; gps->tot_triangles = 0; gps->mat_nr = mat_idx; - /* add to frame */ - BLI_addtail(&gpf->strokes, gps); + return gps; +} + +/* Create a new stroke and add to frame. */ +bGPDstroke *BKE_gpencil_stroke_add( + bGPDframe *gpf, int mat_idx, int totpoints, short thickness, const bool insert_at_head) +{ + bGPDstroke *gps = BKE_gpencil_stroke_new(mat_idx, totpoints, thickness); + + /* Add to frame. */ + if ((gps != NULL) && (gpf != NULL)) { + if (!insert_at_head) { + BLI_addtail(&gpf->strokes, gps); + } + else { + BLI_addhead(&gpf->strokes, gps); + } + } return gps; } /* Add a stroke and copy the temporary drawing color value from one of the existing stroke */ -bGPDstroke *BKE_gpencil_add_stroke_existing_style( +bGPDstroke *BKE_gpencil_stroke_add_existing_style( bGPDframe *gpf, bGPDstroke *existing, int mat_idx, int totpoints, short thickness) { - bGPDstroke *gps = BKE_gpencil_add_stroke(gpf, mat_idx, totpoints, thickness); + bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, mat_idx, totpoints, thickness, false); /* Copy run-time color data so that strokes added in the modifier has the style. * There are depsgraph reference pointers inside, * change the copy function if interfere with future drawing implementation. */ @@ -543,30 +550,26 @@ void BKE_gpencil_stroke_weights_duplicate(bGPDstroke *gps_src, bGPDstroke *gps_d } /* make a copy of a given gpencil stroke */ -bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src) +bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src, const bool dup_points) { bGPDstroke *gps_dst = NULL; gps_dst = MEM_dupallocN(gps_src); gps_dst->prev = gps_dst->next = NULL; + gps_dst->triangles = MEM_dupallocN(gps_dst->triangles); - gps_dst->points = MEM_dupallocN(gps_src->points); + if (dup_points) { + gps_dst->points = MEM_dupallocN(gps_src->points); - if (gps_src->dvert != NULL) { - gps_dst->dvert = MEM_dupallocN(gps_src->dvert); - BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); - } - else { - gps_dst->dvert = NULL; + if (gps_src->dvert != NULL) { + gps_dst->dvert = MEM_dupallocN(gps_src->dvert); + BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); + } + else { + gps_dst->dvert = NULL; + } } - /* 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. - */ - gps_dst->triangles = MEM_dupallocN(gps_dst->triangles); - /* gps_dst->flag |= GP_STROKE_RECALC_GEOMETRY; */ - /* return new stroke */ return gps_dst; } @@ -590,7 +593,7 @@ bGPDframe *BKE_gpencil_frame_duplicate(const bGPDframe *gpf_src) 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); + gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true); BLI_addtail(&gpf_dst->strokes, gps_dst); } @@ -611,7 +614,7 @@ void BKE_gpencil_frame_copy_strokes(bGPDframe *gpf_src, struct bGPDframe *gpf_ds 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); + gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true); BLI_addtail(&gpf_dst->strokes, gps_dst); } } @@ -668,7 +671,7 @@ void BKE_gpencil_copy_data(bGPdata *gpd_dst, const bGPdata *gpd_src, const int U /* copy layers */ BLI_listbase_clear(&gpd_dst->layers); - for (const bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) { /* make a copy of source layer and its data */ /* TODO here too could add unused flags... */ @@ -776,8 +779,8 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) /* if frame has no strokes after this, delete it */ if (BLI_listbase_is_empty(&gpf->strokes)) { - BKE_gpencil_layer_delframe(gpl, gpf); - BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV); + BKE_gpencil_layer_frame_delete(gpl, gpf); + BKE_gpencil_layer_frame_get(gpl, cfra, GP_GETFRAME_USE_PREV); } } @@ -785,7 +788,7 @@ void BKE_gpencil_frame_delete_laststroke(bGPDlayer *gpl, bGPDframe *gpf) /* GP Layer API */ /* Check if the given layer is able to be edited or not */ -bool gpencil_layer_is_editable(const bGPDlayer *gpl) +bool BKE_gpencil_layer_is_editable(const bGPDlayer *gpl) { /* Sanity check */ if (gpl == NULL) { @@ -807,7 +810,7 @@ bool gpencil_layer_is_editable(const bGPDlayer *gpl) } /* Look up the gp-frame on the requested frame number, but don't add a new one */ -bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe) +bGPDframe *BKE_gpencil_layer_frame_find(bGPDlayer *gpl, int cframe) { bGPDframe *gpf; @@ -827,7 +830,7 @@ bGPDframe *BKE_gpencil_layer_find_frame(bGPDlayer *gpl, int cframe) * - this sets the layer's actframe var (if allowed to) * - extension beyond range (if first gp-frame is after all frame in interest and cannot add) */ -bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew) +bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew) { bGPDframe *gpf = NULL; bool found = false; @@ -976,7 +979,7 @@ bGPDframe *BKE_gpencil_layer_getframe(bGPDlayer *gpl, int cframe, eGP_GetFrame_M } /* delete the given frame from a layer */ -bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) +bool BKE_gpencil_layer_frame_delete(bGPDlayer *gpl, bGPDframe *gpf) { bool changed = false; @@ -1000,17 +1003,15 @@ bool BKE_gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf) } /* get the active gp-layer for editing */ -bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd) +bGPDlayer *BKE_gpencil_layer_active_get(bGPdata *gpd) { - bGPDlayer *gpl; - /* error checking */ if (ELEM(NULL, gpd, gpd->layers.first)) { return NULL; } /* loop over layers until found (assume only one active) */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->flag & GP_LAYER_ACTIVE) { return gpl; } @@ -1021,17 +1022,15 @@ bGPDlayer *BKE_gpencil_layer_getactive(bGPdata *gpd) } /* set the active gp-layer */ -void BKE_gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active) +void BKE_gpencil_layer_active_set(bGPdata *gpd, bGPDlayer *active) { - bGPDlayer *gpl; - /* error checking */ if (ELEM(NULL, gpd, gpd->layers.first, active)) { return; } /* loop over layers deactivating all */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpl->flag &= ~GP_LAYER_ACTIVE; if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) { gpl->flag |= GP_LAYER_LOCKED; @@ -1050,13 +1049,11 @@ void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock) { BLI_assert(gpd != NULL); - bGPDlayer *gpl; - if (gpd->flag & GP_DATA_AUTOLOCK_LAYERS) { - bGPDlayer *layer_active = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *layer_active = BKE_gpencil_layer_active_get(gpd); /* Lock all other layers */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* unlock active layer */ if (gpl == layer_active) { gpl->flag &= ~GP_LAYER_LOCKED; @@ -1071,7 +1068,7 @@ void BKE_gpencil_layer_autolock_set(bGPdata *gpd, const bool unlock) * a problem in the UI because the user expects all layers will be unlocked */ if (unlock) { - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpl->flag &= ~GP_LAYER_LOCKED; } } @@ -1129,7 +1126,7 @@ Material *BKE_gpencil_object_material_ensure_from_brush(Main *bmain, Object *ob, Material *ma = BKE_gpencil_brush_material_get(brush); /* check if the material is already on object material slots and add it if missing */ - if (ma && BKE_gpencil_object_material_get_index(ob, ma) < 0) { + if (ma && BKE_gpencil_object_material_index_get(ob, ma) < 0) { BKE_object_material_slot_add(bmain, ob); BKE_object_material_assign(bmain, ob, ma, ob->totcol, BKE_MAT_ASSIGN_USERPREF); } @@ -1148,7 +1145,7 @@ int BKE_gpencil_object_material_ensure(Main *bmain, Object *ob, Material *materi if (!material) { return -1; } - int index = BKE_gpencil_object_material_get_index(ob, material); + int index = BKE_gpencil_object_material_index_get(ob, material); if (index < 0) { BKE_object_material_slot_add(bmain, ob); BKE_object_material_assign(bmain, ob, material, ob->totcol, BKE_MAT_ASSIGN_USERPREF); @@ -1177,7 +1174,7 @@ Material *BKE_gpencil_object_material_new(Main *bmain, Object *ob, const char *n } /* Returns the material for a brush with respect to its pinned state. */ -Material *BKE_gpencil_object_material_get_from_brush(Object *ob, Brush *brush) +Material *BKE_gpencil_object_material_from_brush_get(Object *ob, Brush *brush) { if ((brush) && (brush->gpencil_settings) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) { @@ -1193,7 +1190,7 @@ Material *BKE_gpencil_object_material_get_from_brush(Object *ob, Brush *brush) int BKE_gpencil_object_material_get_index_from_brush(Object *ob, Brush *brush) { if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) { - return BKE_gpencil_object_material_get_index(ob, brush->gpencil_settings->material); + return BKE_gpencil_object_material_index_get(ob, brush->gpencil_settings->material); } else { return ob->actcol - 1; @@ -1304,11 +1301,11 @@ bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3]) return changed; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { bGPDframe *gpf = gpl->actframe; if (gpf != NULL) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); } } @@ -1340,6 +1337,13 @@ void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3]) mul_v3_v3fl(r_centroid, tot, 0.5f); } +/* Compute stroke collision detection center and radius. */ +void BKE_gpencil_stroke_collision_get(bGPDstroke *gps) +{ + INIT_MINMAX(gps->collision_min, gps->collision_max); + BKE_gpencil_stroke_minmax(gps, false, gps->collision_min, gps->collision_max); +} + /* create bounding box values */ static void boundbox_gpencil(Object *ob) { @@ -1391,7 +1395,7 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) } const float scalef = mat4_to_scale(mat); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* FIXME: For now, we just skip parented layers. * Otherwise, we have to update each frame to find * the current parent position/effects. @@ -1400,8 +1404,8 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) continue; } - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { bGPDspoint *pt; int i; @@ -1410,9 +1414,8 @@ void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4]) pt->pressure *= scalef; } - /* TODO: Do we need to do this? distortion may mean we need to re-triangulate */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + /* Distortion may mean we need to re-triangulate. */ + BKE_gpencil_stroke_geometry_update(gps); } } } @@ -1431,9 +1434,9 @@ void BKE_gpencil_vgroup_remove(Object *ob, bDeformGroup *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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->dvert != NULL) { for (int i = 0; i < gps->totpoints; i++) { dvert = &gps->dvert[i]; @@ -1547,7 +1550,7 @@ static int stroke_march_next_point(const bGPDstroke *gps, float *result, float *pressure, float *strength, - float *mix_color, + float *vert_color, float *ratio_result, int *index_from, int *index_to) @@ -1587,7 +1590,7 @@ static int stroke_march_next_point(const bGPDstroke *gps, copy_v3_v3(result, &pt->x); *pressure = gps->points[next_point_index].pressure; *strength = gps->points[next_point_index].strength; - memcpy(mix_color, gps->points[next_point_index].mix_color, sizeof(float) * 4); + memcpy(vert_color, gps->points[next_point_index].vert_color, sizeof(float) * 4); *index_from = next_point_index - 1; *index_to = next_point_index; @@ -1602,9 +1605,9 @@ static int stroke_march_next_point(const bGPDstroke *gps, gps->points[next_point_index].pressure, gps->points[next_point_index - 1].pressure, ratio); *strength = interpf( gps->points[next_point_index].strength, gps->points[next_point_index - 1].strength, ratio); - interp_v4_v4v4(mix_color, - gps->points[next_point_index - 1].mix_color, - gps->points[next_point_index].mix_color, + interp_v4_v4v4(vert_color, + gps->points[next_point_index - 1].vert_color, + gps->points[next_point_index].vert_color, ratio); *index_from = next_point_index - 1; @@ -1689,7 +1692,7 @@ static int stroke_march_count(const bGPDstroke *gps, const float dist) * \param gps: Stroke to sample * \param dist: Distance of one segment */ -bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool select) +bool BKE_gpencil_stroke_sample(bGPDstroke *gps, const float dist, const bool select) { bGPDspoint *pt = gps->points; bGPDspoint *pt1 = NULL; @@ -1717,7 +1720,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel int next_point_index = 1; i = 0; float pressure, strength, ratio_result; - float mix_color[4]; + float vert_color[4]; int index_from, index_to; float last_coord[3]; @@ -1728,7 +1731,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel copy_v3_v3(&pt2->x, last_coord); new_pt[i].pressure = pt[0].pressure; new_pt[i].strength = pt[0].strength; - memcpy(new_pt[i].mix_color, pt[0].mix_color, sizeof(float) * 4); + memcpy(new_pt[i].vert_color, pt[0].vert_color, sizeof(float) * 4); if (select) { new_pt[i].flag |= GP_SPOINT_SELECT; } @@ -1746,7 +1749,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel last_coord, &pressure, &strength, - mix_color, + vert_color, &ratio_result, &index_from, &index_to)) > -1) { @@ -1754,7 +1757,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel copy_v3_v3(&pt2->x, last_coord); new_pt[i].pressure = pressure; new_pt[i].strength = strength; - memcpy(new_pt[i].mix_color, mix_color, sizeof(float) * 4); + memcpy(new_pt[i].vert_color, vert_color, sizeof(float) * 4); if (select) { new_pt[i].flag |= GP_SPOINT_SELECT; } @@ -1786,8 +1789,8 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel gps->totpoints = i; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); return true; } @@ -1798,7 +1801,7 @@ bool BKE_gpencil_sample_stroke(bGPDstroke *gps, const float dist, const bool sel * \param dist: Distance of one segment * \param tip_length: Ignore tip jittering, set zero to use default value. */ -bool BKE_gpencil_stretch_stroke(bGPDstroke *gps, const float dist, const float tip_length) +bool BKE_gpencil_stroke_stretch(bGPDstroke *gps, const float dist, const float tip_length) { bGPDspoint *pt = gps->points, *last_pt, *second_last, *next_pt; int i; @@ -1849,7 +1852,7 @@ bool BKE_gpencil_stretch_stroke(bGPDstroke *gps, const float dist, const float t * \param index_from: the index of the first point to be used in the trimmed result * \param index_to: the index of the last point to be used in the trimmed result */ -bool BKE_gpencil_trim_stroke_points(bGPDstroke *gps, const int index_from, const int index_to) +bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to) { bGPDspoint *pt = gps->points, *new_pt; MDeformVert *dv, *new_dv; @@ -1899,7 +1902,7 @@ bool BKE_gpencil_trim_stroke_points(bGPDstroke *gps, const int index_from, const return true; } -bool BKE_gpencil_split_stroke(bGPDframe *gpf, +bool BKE_gpencil_stroke_split(bGPDframe *gpf, bGPDstroke *gps, const int before_index, bGPDstroke **remaining_gps) @@ -1917,7 +1920,7 @@ bool BKE_gpencil_split_stroke(bGPDframe *gpf, /* Handle remaining segments first. */ - new_gps = BKE_gpencil_add_stroke_existing_style( + new_gps = BKE_gpencil_stroke_add_existing_style( gpf, gps, gps->mat_nr, new_count, gps->thickness); new_pt = new_gps->points; /* Allocated from above. */ @@ -1947,8 +1950,8 @@ bool BKE_gpencil_split_stroke(bGPDframe *gpf, /* Trim the original stroke into a shorter one. * Keep the end point. */ - BKE_gpencil_trim_stroke_points(gps, 0, old_count); - + BKE_gpencil_stroke_trim_points(gps, 0, old_count); + BKE_gpencil_stroke_geometry_update(gps); return true; } @@ -1957,7 +1960,7 @@ bool BKE_gpencil_split_stroke(bGPDframe *gpf, * \param gps: Stroke to shrink * \param dist: delta length */ -bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist) +bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist) { bGPDspoint *pt = gps->points, *second_last; int i; @@ -2001,7 +2004,7 @@ bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist) index_start = index_end = 0; /* no length left to cut */ } - BKE_gpencil_trim_stroke_points(gps, index_start, index_end); + BKE_gpencil_stroke_trim_points(gps, index_start, index_end); if (gps->totpoints == 0) { return false; @@ -2029,7 +2032,7 @@ bool BKE_gpencil_shrink_stroke(bGPDstroke *gps, const float dist) * \param i: Point index * \param inf: Amount of smoothing to apply */ -bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf) +bool BKE_gpencil_stroke_smooth(bGPDstroke *gps, int i, float inf) { bGPDspoint *pt = &gps->points[i]; float sco[3] = {0.0f}; @@ -2088,7 +2091,7 @@ bool BKE_gpencil_smooth_stroke(bGPDstroke *gps, int i, float inf) /** * Apply smooth for strength to stroke point */ -bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence) { bGPDspoint *ptb = &gps->points[point_index]; @@ -2148,7 +2151,7 @@ bool BKE_gpencil_smooth_stroke_strength(bGPDstroke *gps, int point_index, float /** * Apply smooth for thickness to stroke point (use pressure) */ -bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence) { bGPDspoint *ptb = &gps->points[point_index]; @@ -2208,7 +2211,7 @@ bool BKE_gpencil_smooth_stroke_thickness(bGPDstroke *gps, int point_index, float /** * Apply smooth for UV rotation to stroke point (use pressure). */ -bool BKE_gpencil_smooth_stroke_uv(bGPDstroke *gps, int point_index, float influence) +bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence) { bGPDspoint *ptb = &gps->points[point_index]; @@ -2258,7 +2261,7 @@ void BKE_gpencil_get_range_selected(bGPDlayer *gpl, int *r_initframe, int *r_end *r_initframe = gpl->actframe->framenum; *r_endframe = gpl->actframe->framenum; - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (gpf->flag & GP_FRAME_SELECT) { if (gpf->framenum < *r_initframe) { *r_initframe = gpf->framenum; @@ -2311,9 +2314,9 @@ float BKE_gpencil_multiframe_falloff_calc( /* reassign strokes using a material */ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index) { - 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* reassign strokes */ if ((gps->mat_nr > index) || (gps->mat_nr > totcol - 1)) { gps->mat_nr--; @@ -2327,9 +2330,9 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index) /* remove strokes using a material */ bool BKE_gpencil_material_index_used(bGPdata *gpd, int index) { - 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->mat_nr == index) { return true; } @@ -2353,9 +2356,9 @@ void BKE_gpencil_material_remap(struct bGPdata *gpd, } \ ((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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* reassign strokes */ MAT_NR_REMAP(gps->mat_nr); } @@ -2402,7 +2405,7 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob, gp_style_secondary = ma_secondary->gp_style; if ((gp_style_primary == NULL) || (gp_style_secondary == NULL) || - (gp_style_secondary->flag & GP_STYLE_COLOR_LOCKED)) { + (gp_style_secondary->flag & GP_MATERIAL_LOCKED)) { continue; } @@ -2412,13 +2415,13 @@ bool BKE_gpencil_merge_materials_table_get(Object *ob, } /* Check materials have same stroke and fill attributes. */ - if ((gp_style_primary->flag & GP_STYLE_STROKE_SHOW) != - (gp_style_secondary->flag & GP_STYLE_STROKE_SHOW)) { + if ((gp_style_primary->flag & GP_MATERIAL_STROKE_SHOW) != + (gp_style_secondary->flag & GP_MATERIAL_STROKE_SHOW)) { continue; } - if ((gp_style_primary->flag & GP_STYLE_FILL_SHOW) != - (gp_style_secondary->flag & GP_STYLE_FILL_SHOW)) { + if ((gp_style_primary->flag & GP_MATERIAL_FILL_SHOW) != + (gp_style_secondary->flag & GP_MATERIAL_FILL_SHOW)) { continue; } @@ -2469,11 +2472,11 @@ void BKE_gpencil_stats_update(bGPdata *gpd) gpd->totstroke = 0; gpd->totpoint = 0; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpd->totlayer++; - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { gpd->totframe++; - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { gpd->totstroke++; gpd->totpoint += gps->totpoints; } @@ -2482,7 +2485,7 @@ void BKE_gpencil_stats_update(bGPdata *gpd) } /* get material index (0-based like mat_nr not actcol) */ -int BKE_gpencil_object_material_get_index(Object *ob, Material *ma) +int BKE_gpencil_object_material_index_get(Object *ob, Material *ma) { short *totcol = BKE_object_material_num(ob); Material *read_ma = NULL; @@ -2717,7 +2720,7 @@ static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2], /* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was * modified) */ -void BKE_gpencil_triangulate_stroke_fill(bGPdata *gpd, bGPDstroke *gps) +void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps) { BLI_assert(gps->totpoints >= 3); @@ -2739,36 +2742,25 @@ void BKE_gpencil_triangulate_stroke_fill(bGPdata *gpd, bGPDstroke *gps) float minv[2]; float maxv[2]; /* first needs bounding box data */ - if (gpd->flag & GP_DATA_UV_ADAPTIVE) { - gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv); - } - else { - ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); - ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); - } + ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); + ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); /* calc uv data */ gpencil_calc_stroke_fill_uv(points2d, gps, minv, maxv, uv); - /* Number of triangles */ - gps->tot_triangles = gps->totpoints - 2; - /* save triangulation data in stroke cache */ + /* Save triangulation data. */ 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); - } + MEM_SAFE_FREE(gps->triangles); + gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, + "GP Stroke triangulation"); 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]]); + } + + /* Copy UVs to bGPDspoint. */ + for (int i = 0; i < gps->totpoints; i++) { + copy_v2_v2(gps->points[i].uv_fill, uv[i]); } } else { @@ -2780,17 +2772,50 @@ void BKE_gpencil_triangulate_stroke_fill(bGPdata *gpd, bGPDstroke *gps) gps->triangles = NULL; } - /* disable recalculation flag */ - if (gps->flag & GP_STROKE_RECALC_GEOMETRY) { - gps->flag &= ~GP_STROKE_RECALC_GEOMETRY; - } - /* clear memory */ MEM_SAFE_FREE(tmp_triangles); MEM_SAFE_FREE(points2d); MEM_SAFE_FREE(uv); } +/* texture coordinate utilities */ +void BKE_gpencil_stroke_uv_update(bGPDstroke *gps) +{ + if (gps == NULL || gps->totpoints == 0) { + return; + } + + bGPDspoint *pt = gps->points; + float totlen = 0.0f; + pt[0].uv_fac = totlen; + for (int i = 1; i < gps->totpoints; i++) { + totlen += len_v3v3(&pt[i - 1].x, &pt[i].x); + pt[i].uv_fac = totlen; + } +} + +/* Recalc the internal geometry caches for fill and uvs. */ +void BKE_gpencil_stroke_geometry_update(bGPDstroke *gps) +{ + if (gps == NULL) { + return; + } + + if (gps->totpoints > 2) { + BKE_gpencil_stroke_fill_triangulate(gps); + } + else { + gps->tot_triangles = 0; + MEM_SAFE_FREE(gps->triangles); + } + + /* calc uv data along the stroke */ + BKE_gpencil_stroke_uv_update(gps); + + /* Calc collision center and radius. */ + BKE_gpencil_stroke_collision_get(gps); +} + float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d) { if (!gps->points || gps->totpoints < 2) { @@ -2817,7 +2842,7 @@ float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d) * Trim stroke to the first intersection or loop * \param gps: Stroke data */ -bool BKE_gpencil_trim_stroke(bGPDstroke *gps) +bool BKE_gpencil_stroke_trim(bGPDstroke *gps) { if (gps->totpoints < 4) { return false; @@ -2898,13 +2923,14 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps) } } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; gps->totpoints = newtot; MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); } + + BKE_gpencil_stroke_geometry_update(gps); + return intersect; } @@ -2912,7 +2938,7 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps) * Close stroke * \param gps: Stroke to close */ -bool BKE_gpencil_close_stroke(bGPDstroke *gps) +bool BKE_gpencil_stroke_close(bGPDstroke *gps) { bGPDspoint *pt1 = NULL; bGPDspoint *pt2 = NULL; @@ -2970,7 +2996,7 @@ bool BKE_gpencil_close_stroke(bGPDstroke *gps) pt->pressure = interpf(pt2->pressure, pt1->pressure, step); pt->strength = interpf(pt2->strength, pt1->strength, step); pt->flag = 0; - interp_v4_v4v4(pt->mix_color, pt1->mix_color, pt2->mix_color, step); + interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step); /* Set weights. */ if (gps->dvert != NULL) { @@ -3073,8 +3099,7 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta gps->totpoints = tot; /* triangles cache needs to be recalculated */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + BKE_gpencil_stroke_geometry_update(gps); } } @@ -3087,7 +3112,7 @@ void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short ta * \param threshold: Distance between points * \param use_unselected: Set to true to analyze all stroke and not only selected points */ -void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf, +void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf, bGPDstroke *gps, const float threshold, const bool use_unselected) @@ -3154,6 +3179,9 @@ void BKE_gpencil_merge_distance_stroke(bGPDframe *gpf, if (tagged) { BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG); } + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* Helper: Check materials with same color. */ @@ -3173,7 +3201,8 @@ static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Mate float hsv2[4]; rgb_to_hsv_v(gp_style->fill_rgba, hsv2); hsv2[3] = gp_style->fill_rgba[3]; - if ((gp_style->fill_style == GP_STYLE_FILL_STYLE_SOLID) && (compare_v4v4(hsv1, hsv2, 0.01f))) { + if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) && + (compare_v4v4(hsv1, hsv2, 0.01f))) { *r_mat = ma; return i - 1; } @@ -3198,24 +3227,24 @@ static Material *gpencil_add_from_curve_material(Main *bmain, /* Stroke color. */ if (gpencil_lines) { ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f); - gp_style->flag |= GP_STYLE_STROKE_SHOW; + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } else { linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color); - gp_style->flag &= ~GP_STYLE_STROKE_SHOW; + gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; } /* Fill color. */ linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color); /* Fill is false if the original curve hasn't material assigned, so enable it. */ if (fill) { - gp_style->flag |= GP_STYLE_FILL_SHOW; + gp_style->flag |= GP_MATERIAL_FILL_SHOW; } /* Check at least one is enabled. */ - if (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0) && - ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) { - gp_style->flag |= GP_STYLE_STROKE_SHOW; + if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) && + ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) { + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } return mat_gp; @@ -3280,6 +3309,7 @@ static void gpencil_convert_spline(Main *bmain, /* Create Stroke. */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); gps->thickness = 1.0f; + gps->fill_opacity_fac = 1.0f; gps->gradient_f = 1.0f; gps->uv_scale = 1.0f; @@ -3287,8 +3317,6 @@ static void gpencil_convert_spline(Main *bmain, ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND); gps->inittime = 0.0f; - /* Enable recalculation flag by default. */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; gps->flag &= ~GP_STROKE_SELECT; gps->flag |= GP_STROKE_3DSPACE; @@ -3307,10 +3335,6 @@ static void gpencil_convert_spline(Main *bmain, } totpoints = (resolu * segments) - (segments - 1); - /* Initialize triangle memory to dummy data. */ - gps->tot_triangles = 0; - gps->triangles = NULL; - /* Materials * Notice: The color of the material is the color of viewport and not the final shader color. */ @@ -3370,16 +3394,16 @@ static void gpencil_convert_spline(Main *bmain, if (ob_cu->totcol > 0) { mat_curve = BKE_object_material_get(ob_cu, 1); if (mat_curve) { - linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); + copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r); mat_gp->gp_style->stroke_rgba[3] = mat_curve->a; /* Set fill and stroke depending of curve type (3D or 2D). */ if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) { - mat_gp->gp_style->flag |= GP_STYLE_STROKE_SHOW; - mat_gp->gp_style->flag &= ~GP_STYLE_FILL_SHOW; + mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; } else { - mat_gp->gp_style->flag &= ~GP_STYLE_STROKE_SHOW; - mat_gp->gp_style->flag |= GP_STYLE_FILL_SHOW; + mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; + mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW; } } } @@ -3491,8 +3515,11 @@ static void gpencil_convert_spline(Main *bmain, } /* Cyclic curve, close stroke. */ if ((cyclic) && (!do_stroke)) { - BKE_gpencil_close_stroke(gps); + BKE_gpencil_stroke_close(gps); } + + /* Recalc fill geometry. */ + BKE_gpencil_stroke_geometry_update(gps); } /* Convert a curve object to grease pencil stroke. @@ -3538,14 +3565,14 @@ void BKE_gpencil_convert_curve(Main *bmain, } if (gpl == NULL) { - gpl = BKE_gpencil_layer_getactive(gpd); + gpl = BKE_gpencil_layer_active_get(gpd); if (gpl == NULL) { gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); } } /* Check if there is an active frame and add if needed. */ - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); /* Read all splines of the curve and create a stroke for each. */ for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) { @@ -3560,7 +3587,7 @@ void BKE_gpencil_convert_curve(Main *bmain, void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene) { const int totcol = 120; - static char *hexcol[] = { + const char *hexcol[] = { "FFFFFF", "F2F2F2", "E6E6E6", "D9D9D9", "CCCCCC", "BFBFBF", "B2B2B2", "A6A6A6", "999999", "8C8C8C", "808080", "737373", "666666", "595959", "4C4C4C", "404040", "333333", "262626", "1A1A1A", "000000", "F2FC24", "FFEA00", "FEA711", "FE8B68", "FB3B02", "FE3521", "D00000", @@ -3589,7 +3616,7 @@ void BKE_gpencil_palette_ensure(Main *bmain, Scene *scene) for (int i = 0; i < totcol; i++) { PaletteColor *palcol = BKE_palette_color_add(paint->palette); if (palcol) { - hex_to_rgb(hexcol[i], palcol->rgb, palcol->rgb + 1, palcol->rgb + 2); + hex_to_rgb((char *)hexcol[i], palcol->rgb, palcol->rgb + 1, palcol->rgb + 2); } } } @@ -3614,27 +3641,26 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size, int img_x = ibuf->x; int img_y = ibuf->y; - // space = 0.005 pixels = image.pixels float color[4]; bGPDspoint *pt; for (int row = 0; row < img_y; row++) { /* Create new stroke */ - bGPDstroke *gps = BKE_gpencil_add_stroke(gpf, 0, img_x, size * 1000); + bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, 0, img_x, size * 1000, false); done = true; for (int col = 0; col < img_x; col++) { - IMB_sampleImageAtLocation(ibuf, col, row, false, color); + IMB_sampleImageAtLocation(ibuf, col, row, true, color); pt = &gps->points[col]; pt->pressure = 1.0f; pt->x = col * size; pt->z = row * size; if (!mask) { - copy_v3_v3(pt->mix_color, color); - pt->mix_color[3] = 1.0f; + copy_v3_v3(pt->vert_color, color); + pt->vert_color[3] = 1.0f; pt->strength = color[3]; } else { - zero_v3(pt->mix_color); - pt->mix_color[3] = 1.0f; + zero_v3(pt->vert_color); + pt->vert_color[3] = 1.0f; pt->strength = 1.0f - color[3]; } @@ -3644,6 +3670,7 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size, pt->flag |= GP_SPOINT_SELECT; } } + BKE_gpencil_stroke_geometry_update(gps); } } @@ -3652,3 +3679,282 @@ bool BKE_gpencil_from_image(SpaceImage *sima, bGPDframe *gpf, const float size, return done; } + +/* -------------------------------------------------------------------- */ +/** \name Iterators + * + * Iterate over all visible stroke of all visible layers inside a gpObject. + * Also take into account onion skining. + * + * \{ */ + +void BKE_gpencil_visible_stroke_iter( + Object *ob, gpIterCb layer_cb, gpIterCb stroke_cb, void *thunk, bool do_onion, int cfra) +{ + bGPdata *gpd = (bGPdata *)ob->data; + const bool is_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool is_onion = do_onion && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0); + + /* Onion skinning. */ + const bool onion_mode_abs = (gpd->onion_mode == GP_ONION_MODE_ABSOLUTE); + const bool onion_mode_sel = (gpd->onion_mode == GP_ONION_MODE_SELECTED); + const bool onion_loop = (gpd->onion_flag & GP_ONION_LOOP) != 0; + const short onion_keytype = gpd->onion_keytype; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + + bGPDframe *act_gpf = gpl->actframe; + bGPDframe *sta_gpf = act_gpf; + bGPDframe *end_gpf = act_gpf ? act_gpf->next : NULL; + + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + + if (is_multiedit) { + sta_gpf = end_gpf = NULL; + /* Check the whole range and tag the editable frames. */ + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + if (gpf == act_gpf || (gpf->flag & GP_FRAME_SELECT)) { + gpf->runtime.onion_id = 0; + if (sta_gpf == NULL) { + sta_gpf = gpf; + } + end_gpf = gpf->next; + } + else { + gpf->runtime.onion_id = INT_MAX; + } + } + } + else if (is_onion && (gpl->onion_flag & GP_LAYER_ONIONSKIN)) { + if (act_gpf) { + bGPDframe *last_gpf = gpl->frames.last; + + int frame_len = 0; + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + gpf->runtime.frameid = frame_len++; + } + + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + bool is_wrong_keytype = (onion_keytype > -1) && (gpf->key_type != onion_keytype); + bool is_in_range; + int delta = (onion_mode_abs) ? (gpf->framenum - cfra) : + (gpf->runtime.frameid - act_gpf->runtime.frameid); + + if (onion_mode_sel) { + is_in_range = (gpf->flag & GP_FRAME_SELECT) != 0; + } + else { + is_in_range = (-delta <= gpd->gstep) && (delta <= gpd->gstep_next); + + if (onion_loop && !is_in_range) { + /* We wrap the value using the last frame and 0 as reference. */ + /* FIXME: This might not be good for animations not starting at 0. */ + int shift = (onion_mode_abs) ? last_gpf->framenum : last_gpf->runtime.frameid; + delta += (delta < 0) ? (shift + 1) : -(shift + 1); + /* Test again with wrapped value. */ + is_in_range = (-delta <= gpd->gstep) && (delta <= gpd->gstep_next); + } + } + /* Mask frames that have wrong keytype of are not in range. */ + gpf->runtime.onion_id = (is_wrong_keytype || !is_in_range) ? INT_MAX : delta; + } + /* Active frame is always shown. */ + act_gpf->runtime.onion_id = 0; + } + + sta_gpf = gpl->frames.first; + end_gpf = NULL; + } + else { + /* Bypass multiedit/onion skinning. */ + end_gpf = sta_gpf = NULL; + } + + if (sta_gpf == NULL && act_gpf == NULL) { + if (layer_cb) { + layer_cb(gpl, act_gpf, NULL, thunk); + } + continue; + } + + /* Draw multiedit/onion skinning first */ + for (bGPDframe *gpf = sta_gpf; gpf && gpf != end_gpf; gpf = gpf->next) { + if (gpf->runtime.onion_id == INT_MAX || gpf == act_gpf) { + continue; + } + + if (layer_cb) { + layer_cb(gpl, gpf, NULL, thunk); + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + stroke_cb(gpl, gpf, gps, thunk); + } + } + /* Draw Active frame on top. */ + /* Use evaluated frame (with modifiers for active stroke)/ */ + act_gpf = gpl->actframe; + act_gpf->runtime.onion_id = 0; + if (act_gpf) { + if (layer_cb) { + layer_cb(gpl, act_gpf, NULL, thunk); + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &act_gpf->strokes) { + stroke_cb(gpl, act_gpf, gps, thunk); + } + } + } +} + +void BKE_gpencil_frame_original_pointers_update(const struct bGPDframe *gpf_orig, + const struct bGPDframe *gpf_eval) +{ + bGPDstroke *gps_eval = gpf_eval->strokes.first; + LISTBASE_FOREACH (bGPDstroke *, gps_orig, &gpf_orig->strokes) { + + /* Assign original stroke pointer. */ + if (gps_eval != NULL) { + gps_eval->runtime.gps_orig = gps_orig; + + /* Assign original point pointer. */ + for (int i = 0; i < gps_orig->totpoints; i++) { + bGPDspoint *pt_eval = &gps_eval->points[i]; + pt_eval->runtime.pt_orig = &gps_orig->points[i]; + pt_eval->runtime.idx_orig = i; + } + /* Increase pointer. */ + gps_eval = gps_eval->next; + } + } +} + +void BKE_gpencil_update_orig_pointers(const Object *ob_orig, const Object *ob_eval) +{ + bGPdata *gpd_eval = (bGPdata *)ob_eval->data; + bGPdata *gpd_orig = (bGPdata *)ob_orig->data; + + /* Assign pointers to the original stroke and points to the evaluated data. This must + * be done before applying any modifier because at this moment the structure is equals, + * so we can assume the layer index is the same in both datablocks. + * This data will be used by operators. */ + + bGPDlayer *gpl_eval = gpd_eval->layers.first; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { + if (gpl_eval != NULL) { + /* Update layer reference pointers. */ + gpl_eval->runtime.gpl_orig = (bGPDlayer *)gpl; + + bGPDframe *gpf_eval = gpl_eval->frames.first; + LISTBASE_FOREACH (bGPDframe *, gpf_orig, &gpl->frames) { + if (gpf_eval != NULL) { + /* Update frame reference pointers. */ + gpf_eval->runtime.gpf_orig = (bGPDframe *)gpf_orig; + BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval); + gpf_eval = gpf_eval->next; + } + } + gpl_eval = gpl_eval->next; + } + } +} + +void BKE_gpencil_parent_matrix_get(const Depsgraph *depsgraph, + Object *obact, + bGPDlayer *gpl, + float diff_mat[4][4]) +{ + 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, obparent_eval->obmat, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + return; + } + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr); + if (pchan) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat); + mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + } + else { + /* if bone not found use object (armature) */ + mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); + add_v3_v3(diff_mat[3], ob_eval->obmat[3]); + } + return; + } + else { + unit_m4(diff_mat); /* not defined type */ + } + } +} + +void BKE_gpencil_update_layer_parent(const Depsgraph *depsgraph, Object *ob) +{ + if (ob->type != OB_GPENCIL) { + return; + } + + bGPdata *gpd = (bGPdata *)ob->data; + bGPDspoint *pt; + int i; + float diff_mat[4][4]; + float cur_mat[4][4]; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if ((gpl->parent != NULL) && (gpl->actframe != NULL)) { + Object *ob_eval = DEG_get_evaluated_object(depsgraph, gpl->parent); + + /* calculate new matrix */ + if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { + invert_m4_m4(cur_mat, ob_eval->obmat); + } + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(ob_eval->pose, gpl->parsubstr); + if (pchan) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, ob_eval->obmat, pchan->pose_mat); + invert_m4_m4(cur_mat, tmp_mat); + } + } + /* only redo if any change */ + if (!equals_m4m4(gpl->inverse, cur_mat)) { + + /* first apply current transformation to all strokes */ + BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat); + /* undo local object */ + sub_v3_v3(diff_mat[3], ob->obmat[3]); + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + mul_m4_v3(diff_mat, &pt->x); + } + } + /* set new parent matrix */ + copy_m4_m4(gpl->inverse, cur_mat); + } + } + } +} +/** \} */ diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 444ba8b4db3..6eb4c4ea36d 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -96,7 +96,7 @@ void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3]) * Ramer - Douglas - Peucker algorithm * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm */ -void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float epsilon) +void BKE_gpencil_stroke_simplify(bGPDstroke *gps, float epsilon) { bGPDspoint *old_points = MEM_dupallocN(gps->points); int totpoints = gps->totpoints; @@ -165,9 +165,6 @@ void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float epsilon) old_dvert = MEM_dupallocN(gps->dvert); } /* resize gps */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; - int j = 0; for (int i = 0; i < totpoints; i++) { bGPDspoint *pt_src = &old_points[i]; @@ -195,13 +192,16 @@ void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float epsilon) gps->totpoints = j; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); MEM_SAFE_FREE(marked); } /* Simplify alternate vertex of stroke except extremes */ -void BKE_gpencil_simplify_fixed(bGPDstroke *gps) +void BKE_gpencil_stroke_simplify_fixed(bGPDstroke *gps) { if (gps->totpoints < 5) { return; @@ -227,8 +227,6 @@ void BKE_gpencil_simplify_fixed(bGPDstroke *gps) if (gps->dvert != NULL) { gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; int j = 0; for (int i = 0; i < gps->totpoints; i++) { @@ -256,6 +254,8 @@ void BKE_gpencil_simplify_fixed(bGPDstroke *gps) } gps->totpoints = j; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); @@ -357,73 +357,8 @@ bool BKE_gpencil_has_transform_modifiers(Object *ob) return false; } -/* apply stroke modifiers */ -void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, - Object *ob, - bGPDlayer *gpl, - bGPDframe *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)) && (!is_render)) { - continue; - } - - if (mti && mti->deformStroke) { - mti->deformStroke(md, depsgraph, ob, gpl, gpf, gps); - /* subdivide always requires update */ - if (md->type == eGpencilModifierType_Subdiv) { - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - } - /* some modifiers could require a recalc of fill triangulation data */ - else if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) { - if (ELEM(md->type, - eGpencilModifierType_Armature, - eGpencilModifierType_Hook, - eGpencilModifierType_Lattice, - eGpencilModifierType_Offset)) { - - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - } - } - } - } - } -} - -/* 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)) && (!is_render)) { - continue; - } - - if (mti->generateStrokes) { - mti->generateStrokes(md, depsgraph, ob, gpl, gpf); - } - } - } -} - /* apply time modifiers */ -int BKE_gpencil_time_modifier( +static int gpencil_time_modifier( Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl, int cfra, bool is_render) { GpencilModifierData *md; @@ -460,8 +395,8 @@ void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, bGPdata *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); + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, ctime, GP_GETFRAME_USE_PREV); } if (DEG_is_active(depsgraph)) { @@ -471,8 +406,8 @@ void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, bGPdata *gpd) * 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); + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, ctime, GP_GETFRAME_USE_PREV); } } } @@ -687,7 +622,7 @@ GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *na return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name)); } -void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) +void BKE_gpencil_stroke_subdivide(bGPDstroke *gps, int level, int flag) { bGPDspoint *temp_points; MDeformVert *temp_dverts = NULL; @@ -710,8 +645,6 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) temp_dverts = MEM_dupallocN(gps->dvert); gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; /* move points from last to first to new place */ i2 = gps->totpoints - 1; @@ -726,7 +659,7 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) pt_final->flag = pt->flag; pt_final->runtime.pt_orig = pt->runtime.pt_orig; pt_final->runtime.idx_orig = pt->runtime.idx_orig; - copy_v4_v4(pt_final->mix_color, pt->mix_color); + copy_v4_v4(pt_final->vert_color, pt->vert_color); if (gps->dvert != NULL) { dvert = &temp_dverts[i]; @@ -750,7 +683,7 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt_final->time = interpf(pt->time, next->time, 0.5f); pt_final->runtime.pt_orig = NULL; - interp_v4_v4v4(pt_final->mix_color, pt->mix_color, next->mix_color, 0.5f); + interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f); if (gps->dvert != NULL) { dvert = &temp_dverts[i]; @@ -795,145 +728,174 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag) MEM_SAFE_FREE(temp_points); } } + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } -/* Copy frame but do not assign new memory */ -static void gpencil_frame_copy_noalloc(Object *ob, bGPDframe *gpf, bGPDframe *gpf_eval) +/* Remap frame (Time modifier) */ +static int gpencil_remap_time_get(Depsgraph *depsgraph, Scene *scene, Object *ob, bGPDlayer *gpl) { - gpf_eval->prev = gpf->prev; - gpf_eval->next = gpf->next; - gpf_eval->framenum = gpf->framenum; - gpf_eval->flag = gpf->flag; - gpf_eval->key_type = gpf->key_type; - gpf_eval->runtime = gpf->runtime; - copy_m4_m4(gpf_eval->runtime.parent_obmat, gpf->runtime.parent_obmat); + const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const bool time_remap = BKE_gpencil_has_time_modifiers(ob); + int cfra_eval = (int)DEG_get_ctime(depsgraph); - /* copy strokes */ - BLI_listbase_clear(&gpf_eval->strokes); - for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) { - /* make copy of source stroke */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + int remap_cfra = cfra_eval; + if (time_remap) { + remap_cfra = gpencil_time_modifier(depsgraph, scene, ob, gpl, cfra_eval, is_render); + } - /* copy color to temp fields to apply temporal changes in the stroke */ - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps_src->mat_nr + 1); - if (gp_style) { - copy_v4_v4(gps_dst->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); - copy_v4_v4(gps_dst->runtime.tmp_fill_rgba, gp_style->fill_rgba); - } + return remap_cfra; +} - /* Save original pointers for using in edit and select operators. */ - gps_dst->runtime.gps_orig = gps_src; - for (int i = 0; i < gps_src->totpoints; i++) { - bGPDspoint *pt_dst = &gps_dst->points[i]; - pt_dst->runtime.pt_orig = &gps_src->points[i]; - pt_dst->runtime.idx_orig = i; - } +static void gpencil_assign_object_eval(Object *object) +{ + BLI_assert(object->id.tag & LIB_TAG_COPIED_ON_WRITE); + + bGPdata *gpd_eval = object->runtime.gpd_eval; - BLI_addtail(&gpf_eval->strokes, gps_dst); + gpd_eval->id.tag |= LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT; + + if (object->id.tag & LIB_TAG_COPIED_ON_WRITE) { + object->data = gpd_eval; } } -/* Ensure there is a evaluated frame */ -static void gpencil_evaluated_frame_ensure(int idx, - Object *ob, - bGPDframe *gpf, - bGPDframe **gpf_eval) +/* Helper: Copy active frame from original datablock to evaluated datablock for modifiers. */ +static void gpencil_copy_activeframe_to_eval( + Depsgraph *depsgraph, Scene *scene, Object *ob, bGPdata *gpd_orig, bGPdata *gpd_eval) { - /* Create evaluated frames array data or expand. */ - bGPDframe *evaluated_frames = ob->runtime.gpencil_evaluated_frames; - *gpf_eval = &evaluated_frames[idx]; - /* If already exist a evaluated frame create a new one. */ - if (*gpf_eval != NULL) { - /* first clear temp data */ - BKE_gpencil_free_frame_runtime_data(*gpf_eval); + bGPDlayer *gpl_eval = gpd_eval->layers.first; + LISTBASE_FOREACH (bGPDlayer *, gpl_orig, &gpd_orig->layers) { + + if (gpl_eval != NULL) { + int remap_cfra = gpencil_remap_time_get(depsgraph, scene, ob, gpl_orig); + + bGPDframe *gpf_orig = BKE_gpencil_layer_frame_get( + gpl_orig, remap_cfra, GP_GETFRAME_USE_PREV); + + if (gpf_orig != NULL) { + int gpf_index = BLI_findindex(&gpl_orig->frames, gpf_orig); + bGPDframe *gpf_eval = BLI_findlink(&gpl_eval->frames, gpf_index); + + if (gpf_eval != NULL) { + /* Delete old strokes. */ + BKE_gpencil_free_strokes(gpf_eval); + /* Copy again strokes. */ + BKE_gpencil_frame_copy_strokes(gpf_orig, gpf_eval); + + gpf_eval->runtime.gpf_orig = (bGPDframe *)gpf_orig; + BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval); + } + } + + gpl_eval = gpl_eval->next; + } } - /* Copy data (do not assign new memory). */ - gpencil_frame_copy_noalloc(ob, gpf, *gpf_eval); } -/* Calculate gpencil modifiers */ -void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob) +static bGPdata *gpencil_copy_for_eval(bGPdata *gpd) { - /* use original data to set reference pointers to original data */ - Object *ob_orig = DEG_get_original_object(ob); - bGPdata *gpd = (bGPdata *)ob_orig->data; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const bool simplify_modif = GPENCIL_SIMPLIFY_MODIF(scene, false); - const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); - const bool time_remap = BKE_gpencil_has_time_modifiers(ob); - int cfra_eval = (int)DEG_get_ctime(depsgraph); + int flags = LIB_ID_COPY_LOCALIZE; + + bGPdata *result; + BKE_id_copy_ex(NULL, &gpd->id, (ID **)&result, flags); + return result; +} + +void BKE_gpencil_prepare_eval_data(Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + bGPdata *gpd_eval = (bGPdata *)ob->data; + Object *ob_orig = (Object *)DEG_get_original_id(&ob->id); + bGPdata *gpd_orig = (bGPdata *)ob_orig->data; - /* Clear any previous evaluated data. */ - if (ob->runtime.gpencil_tot_layers > 0) { - for (int i = 0; i < ob->runtime.gpencil_tot_layers; i++) { - bGPDframe *gpf_eval = &ob->runtime.gpencil_evaluated_frames[i]; - BKE_gpencil_free_frame_runtime_data(gpf_eval); + /* Need check if some layer is parented. */ + bool do_parent = false; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_orig->layers) { + if (gpl->parent != NULL) { + do_parent = true; + break; } } - /* Create array of evaluated frames equal to number of layers. */ - ob->runtime.gpencil_tot_layers = BLI_listbase_count(&gpd->layers); - CLAMP_MIN(ob->runtime.gpencil_tot_layers, 1); - if (ob->runtime.gpencil_evaluated_frames == NULL) { - ob->runtime.gpencil_evaluated_frames = MEM_callocN( - sizeof(struct bGPDframe) * ob->runtime.gpencil_tot_layers, __func__); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_eval); + const bool do_modifiers = (bool)((!is_multiedit) && (ob->greasepencil_modifiers.first != NULL) && + (!GPENCIL_SIMPLIFY_MODIF(scene))); + if ((!do_modifiers) && (!do_parent)) { + return; } - else { - ob->runtime.gpencil_evaluated_frames = MEM_recallocN(ob->runtime.gpencil_evaluated_frames, - sizeof(struct bGPDframe) * - ob->runtime.gpencil_tot_layers); + DEG_debug_print_eval(depsgraph, __func__, gpd_eval->id.name, gpd_eval); + + /* If only one user, don't need a new copy, just update data of the frame. */ + if (gpd_orig->id.us == 1) { + ob->runtime.gpd_eval = NULL; + gpencil_copy_activeframe_to_eval(depsgraph, scene, ob, ob_orig->data, gpd_eval); + return; } - /* Init general modifiers data. */ - if (ob->greasepencil_modifiers.first) { - BKE_gpencil_lattice_init(ob); + /* Copy full Datablock to evaluated version. */ + ob->runtime.gpd_orig = gpd_orig; + if (ob->runtime.gpd_eval != NULL) { + BKE_gpencil_eval_delete(ob->runtime.gpd_eval); + ob->runtime.gpd_eval = NULL; + ob->data = ob->runtime.gpd_orig; } + ob->runtime.gpd_eval = gpencil_copy_for_eval(ob->runtime.gpd_orig); + gpencil_assign_object_eval(ob); + BKE_gpencil_update_orig_pointers(ob_orig, (Object *)ob); +} + +/* Calculate gpencil modifiers */ +void BKE_gpencil_modifiers_calc(Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + bGPdata *gpd = (bGPdata *)ob->data; + const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool is_render = (bool)(DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + const bool do_modifiers = (bool)((!is_multiedit) && (ob->greasepencil_modifiers.first != NULL) && + (!GPENCIL_SIMPLIFY_MODIF(scene))); + if (!do_modifiers) { + return; + } + + /* Init general modifiers data. */ + BKE_gpencil_lattice_init(ob); - /* ***************************************************************** - * Loop all layers, duplicate data and apply modifiers. - * - * ******************************************************************/ - int idx = 0; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* Loop all layers and apply modifiers. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Remap frame (Time modifier) */ - int remap_cfra = cfra_eval; - if ((time_remap) && (!simplify_modif)) { - remap_cfra = BKE_gpencil_time_modifier(depsgraph, scene, ob, gpl, cfra_eval, is_render); - } - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV); + int remap_cfra = gpencil_remap_time_get(depsgraph, scene, ob, gpl); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, remap_cfra, GP_GETFRAME_USE_PREV); if (gpf == NULL) { - idx++; continue; } - /* Create a duplicate data set of stroke to modify. */ - bGPDframe *gpf_eval = NULL; - gpencil_evaluated_frame_ensure(idx, ob, gpf, &gpf_eval); + LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { - /* Skip all if some disable flag is enabled. */ - if ((ob->greasepencil_modifiers.first == NULL) || (is_multiedit) || (simplify_modif)) { - idx++; - continue; - } + if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); - /* Apply geometry modifiers (create new geometry). */ - if (BKE_gpencil_has_geometry_modifiers(ob)) { - BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, gpf_eval, is_render); - } + if ((GPENCIL_MODIFIER_EDIT(md, is_edit)) && (!is_render)) { + continue; + } - /* Loop all strokes and deform them. */ - for (bGPDstroke *gps = gpf_eval->strokes.first; gps; gps = gps->next) { - /* Apply modifiers that only deform geometry */ - BKE_gpencil_stroke_modifiers(depsgraph, ob, gpl, gpf_eval, gps, is_render); - } + /* Apply geometry modifiers (add new geometry). */ + if (mti->generateStrokes) { + mti->generateStrokes(md, depsgraph, ob, gpl, gpf); + } - idx++; + /* Apply deform modifiers (only change geometry). */ + if (mti && mti->deformStroke) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + mti->deformStroke(md, depsgraph, ob, gpl, gpf, gps); + } + } + } + } } /* Clear any lattice data. */ - if (ob->greasepencil_modifiers.first) { - BKE_gpencil_lattice_clear(ob); - } + BKE_gpencil_lattice_clear(ob); } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 84b3ea27025..e0b7f3114eb 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -106,7 +106,6 @@ void BKE_gpencil_material_attr_init(Material *ma) /* set basic settings */ gp_style->stroke_rgba[3] = 1.0f; gp_style->fill_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); @@ -114,7 +113,7 @@ void BKE_gpencil_material_attr_init(Material *ma) gp_style->texture_opacity = 1.0f; gp_style->texture_pixsize = 100.0f; - gp_style->flag |= GP_STYLE_STROKE_SHOW; + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index cf43dec132a..d666565956e 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -452,7 +452,11 @@ void BKE_object_free_derived_caches(Object *ob) BKE_object_to_mesh_clear(ob); BKE_object_free_curve_cache(ob); - /* clear grease pencil data */ + /* Clear grease pencil data. */ + if (ob->runtime.gpd_eval != NULL) { + BKE_gpencil_eval_delete(ob->runtime.gpd_eval); + ob->runtime.gpd_eval = NULL; + } DRW_gpencil_freecache(ob); } @@ -580,6 +584,9 @@ bool BKE_object_is_in_editmode(const Object *ob) case OB_SURF: case OB_CURVE: return ((Curve *)ob->data)->editnurb != NULL; + case OB_GPENCIL: + /* Grease Pencil object has no edit mode data. */ + return GPENCIL_EDIT_MODE((bGPdata *)ob->data); default: return false; } @@ -857,6 +864,10 @@ void BKE_object_init(Object *ob, const short ob_type) ob->upflag = OB_POSZ; } + if (ob->type == OB_GPENCIL) { + ob->dtx |= OB_USE_GPENCIL_LIGHTS; + } + /* Animation Visualization defaults */ animviz_settings_init(&ob->avs); } @@ -3928,7 +3939,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag)) runtime->mesh_eval = NULL; runtime->mesh_deform_eval = NULL; runtime->curve_cache = NULL; - runtime->gpencil_cache = NULL; } /* diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 366fd0950fa..dbed508bc91 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -24,6 +24,7 @@ #include "DNA_anim_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -150,6 +151,11 @@ void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob) else { ob->transflag &= ~OB_NEG_SCALE; } + + /* Assign evaluated version. */ + if ((ob->type == OB_GPENCIL) && (ob->runtime.gpd_eval != NULL)) { + ob->data = ob->runtime.gpd_eval; + } } void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob) @@ -213,9 +219,12 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o case OB_LATTICE: BKE_lattice_modifiers_calc(depsgraph, scene, ob); break; - case OB_GPENCIL: + case OB_GPENCIL: { + BKE_gpencil_prepare_eval_data(depsgraph, scene, ob); BKE_gpencil_modifiers_calc(depsgraph, scene, ob); + BKE_gpencil_update_layer_parent(depsgraph, ob); break; + } } /* particles */ diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c index f7239f1b9d1..ee9ea15835b 100644 --- a/source/blender/blenlib/intern/BLI_memblock.c +++ b/source/blender/blenlib/intern/BLI_memblock.c @@ -81,7 +81,16 @@ BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) { - BLI_memblock_clear(mblk, free_callback); + int elem_per_chunk = mblk->chunk_size / mblk->elem_size; + + if (free_callback) { + for (int i = 0; i <= mblk->elem_last; i++) { + int chunk_idx = i / elem_per_chunk; + int elem_idx = i - elem_per_chunk * chunk_idx; + void *val = (char *)(mblk->chunk_list[chunk_idx]) + mblk->elem_size * elem_idx; + free_callback(val); + } + } for (int i = 0; i < mblk->chunk_len; i++) { MEM_SAFE_FREE(mblk->chunk_list[i]); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9c7e4a35e1f..37fcf10e553 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6928,7 +6928,7 @@ static void lib_link_gpencil(FileData *fd, Main *UNUSED(bmain), bGPdata *gpd) { /* Relink all data-lock linked by GP data-lock */ /* Layers */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Layer -> Parent References */ gpl->parent = newlibadr(fd, gpd->id.lib, gpl->parent); } @@ -6942,9 +6942,6 @@ static void lib_link_gpencil(FileData *fd, Main *UNUSED(bmain), bGPdata *gpd) /* relinks grease-pencil data - used for direct_link and old file linkage */ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) { - bGPDlayer *gpl; - bGPDframe *gpf; - bGPDstroke *gps; bGPDpalette *palette; /* we must firstly have some grease-pencil data to link! */ @@ -6986,7 +6983,7 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) /* relink layers */ link_list(fd, &gpd->layers); - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* relink frames */ link_list(fd, &gpl->frames); @@ -6994,24 +6991,21 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) gpl->runtime.icon_id = 0; - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* relink strokes (and their points) */ link_list(fd, &gpf->strokes); - for (gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* relink stroke points array */ gps->points = newdataadr(fd, gps->points); + /* Relink geometry*/ + gps->triangles = newdataadr(fd, gps->triangles); /* relink weight data */ if (gps->dvert) { 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_GEOMETRY; } } } @@ -9332,11 +9326,6 @@ static void do_versions_userdef(FileData *fd, BlendFileData *bfd) 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; - } - /* tablet pressure threshold */ if (!DNA_struct_elem_find(fd->filesdna, "UserDef", "float", "pressure_threshold_max")) { user->pressure_threshold_max = 1.0f; @@ -10879,7 +10868,7 @@ static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *li static void expand_gpencil(FileData *fd, Main *mainvar, bGPdata *gpd) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { expand_doit(fd, mainvar, gpl->parent); } diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index a04a2a99c94..87957b550c5 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1130,7 +1130,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) /* Ensure that the datablock's onion-skinning toggle flag * stays in sync with the status of the actual layers */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->flag & GP_LAYER_ONIONSKIN) { enabled = true; } @@ -1358,7 +1358,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) if (BLI_listbase_is_empty(&gpd->palettes)) { /* create palette */ bGPDpalette *palette = BKE_gpencil_palette_addnew(gpd, "GP_Palette"); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* create color using layer name */ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_addnew(palette, gpl->info); if (palcolor != NULL) { @@ -1386,8 +1386,8 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f); /* flush relevant layer-settings to strokes */ - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* set stroke to palette and force recalculation */ BLI_strncpy(gps->colorname, gpl->info, sizeof(gps->colorname)); gps->thickness = gpl->thickness; diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 8ff82407e1c..ff5b98d13a4 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -14,11 +14,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -/** \file - * \ingroup blenloader - */ + /** \file + * \ingroup blenloader + */ -/* allow readfile to use deprecated functionality */ + /* allow readfile to use deprecated functionality */ #define DNA_DEPRECATED_ALLOW #include <string.h> @@ -52,6 +52,7 @@ #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_shader_fx_types.h" #include "DNA_view3d_types.h" #include "DNA_genfile.h" #include "DNA_workspace_types.h" @@ -73,6 +74,7 @@ #include "BKE_freestyle.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" #include "BKE_idprop.h" #include "BKE_key.h" #include "BKE_library.h" @@ -106,73 +108,73 @@ /* Make preferences read-only, use versioning_userdef.c. */ #define U (*((const UserDef *)&U)) -static bScreen *screen_parent_find(const bScreen *screen) +static bScreen* screen_parent_find(const bScreen* screen) { - /* Can avoid lookup if screen state isn't maximized/full - * (parent and child store the same state). */ - if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) { - for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - if (sa->full && sa->full != screen) { - BLI_assert(sa->full->state == screen->state); - return sa->full; - } - } - } - - return NULL; + /* Can avoid lookup if screen state isn't maximized/full + * (parent and child store the same state). */ + if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) { + for (const ScrArea* sa = screen->areabase.first; sa; sa = sa->next) { + if (sa->full && sa->full != screen) { + BLI_assert(sa->full->state == screen->state); + return sa->full; + } + } + } + + return NULL; } -static void do_version_workspaces_create_from_screens(Main *bmain) +static void do_version_workspaces_create_from_screens(Main* bmain) { - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - const bScreen *screen_parent = screen_parent_find(screen); - WorkSpace *workspace; - if (screen->temp) { - continue; - } - - if (screen_parent) { - /* Full-screen with "Back to Previous" option, don't create - * a new workspace, add layout workspace containing parent. */ - workspace = BLI_findstring( - &bmain->workspaces, screen_parent->id.name + 2, offsetof(ID, name) + 2); - } - 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); - } + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + const bScreen* screen_parent = screen_parent_find(screen); + WorkSpace* workspace; + if (screen->temp) { + continue; + } + + if (screen_parent) { + /* Full-screen with "Back to Previous" option, don't create + * a new workspace, add layout workspace containing parent. */ + workspace = BLI_findstring( + &bmain->workspaces, screen_parent->id.name + 2, offsetof(ID, name) + 2); + } + 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); + } } -static void do_version_area_change_space_to_space_action(ScrArea *area, const Scene *scene) +static void do_version_area_change_space_to_space_action(ScrArea* area, const Scene* scene) { - SpaceType *stype = BKE_spacetype_from_id(SPACE_ACTION); - SpaceAction *saction = (SpaceAction *)stype->new (area, scene); - ARegion *region_channels; - - /* Properly free current regions */ - for (ARegion *region = area->regionbase.first; region; region = region->next) { - BKE_area_region_free(area->type, region); - } - BLI_freelistN(&area->regionbase); - - area->type = stype; - area->spacetype = stype->spaceid; - - BLI_addhead(&area->spacedata, saction); - area->regionbase = saction->regionbase; - BLI_listbase_clear(&saction->regionbase); - - /* Different defaults for timeline */ - region_channels = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS); - region_channels->flag |= RGN_FLAG_HIDDEN; - - saction->mode = SACTCONT_TIMELINE; - saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED; - saction->ads.filterflag |= ADS_FILTER_SUMMARY; + SpaceType* stype = BKE_spacetype_from_id(SPACE_ACTION); + SpaceAction* saction = (SpaceAction*)stype->new (area, scene); + ARegion* region_channels; + + /* Properly free current regions */ + for (ARegion* region = area->regionbase.first; region; region = region->next) { + BKE_area_region_free(area->type, region); + } + BLI_freelistN(&area->regionbase); + + area->type = stype; + area->spacetype = stype->spaceid; + + BLI_addhead(&area->spacedata, saction); + area->regionbase = saction->regionbase; + BLI_listbase_clear(&saction->regionbase); + + /* Different defaults for timeline */ + region_channels = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS); + region_channels->flag |= RGN_FLAG_HIDDEN; + + saction->mode = SACTCONT_TIMELINE; + saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED; + saction->ads.filterflag |= ADS_FILTER_SUMMARY; } /** @@ -187,1961 +189,1961 @@ static void do_version_area_change_space_to_space_action(ScrArea *area, const Sc * \note Some of the created workspaces might be deleted again * in case of reading the default `startup.blend`. */ -static void do_version_workspaces_after_lib_link(Main *bmain) +static void do_version_workspaces_after_lib_link(Main* bmain) { - BLI_assert(BLI_listbase_is_empty(&bmain->workspaces)); - - do_version_workspaces_create_from_screens(bmain); - - for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { - for (wmWindow *win = wm->windows.first; win; win = win->next) { - bScreen *screen_parent = screen_parent_find(win->screen); - bScreen *screen = screen_parent ? screen_parent : win->screen; - - if (screen->temp) { - /* We do not generate a new workspace for those screens... - * still need to set some data in win. */ - win->workspace_hook = BKE_workspace_instance_hook_create(bmain); - win->scene = screen->scene; - /* Deprecated from now on! */ - win->screen = NULL; - continue; - } - - WorkSpace *workspace = BLI_findstring( - &bmain->workspaces, screen->id.name + 2, offsetof(ID, name) + 2); - BLI_assert(workspace != NULL); - WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, win->screen); - BLI_assert(layout != NULL); - - win->workspace_hook = BKE_workspace_instance_hook_create(bmain); - - BKE_workspace_active_set(win->workspace_hook, workspace); - BKE_workspace_active_layout_set(win->workspace_hook, layout); - - /* Move scene and view layer to window. */ - Scene *scene = screen->scene; - ViewLayer *layer = BLI_findlink(&scene->view_layers, scene->r.actlay); - if (!layer) { - layer = BKE_view_layer_default_view(scene); - } - - win->scene = scene; - STRNCPY(win->view_layer_name, layer->name); - - /* Deprecated from now on! */ - win->screen = NULL; - } - } - - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - /* Deprecated from now on! */ - BLI_freelistN(&screen->scene->transform_spaces); - screen->scene = NULL; - } + BLI_assert(BLI_listbase_is_empty(&bmain->workspaces)); + + do_version_workspaces_create_from_screens(bmain); + + for (wmWindowManager* wm = bmain->wm.first; wm; wm = wm->id.next) { + for (wmWindow* win = wm->windows.first; win; win = win->next) { + bScreen* screen_parent = screen_parent_find(win->screen); + bScreen* screen = screen_parent ? screen_parent : win->screen; + + if (screen->temp) { + /* We do not generate a new workspace for those screens... + * still need to set some data in win. */ + win->workspace_hook = BKE_workspace_instance_hook_create(bmain); + win->scene = screen->scene; + /* Deprecated from now on! */ + win->screen = NULL; + continue; + } + + WorkSpace* workspace = BLI_findstring( + &bmain->workspaces, screen->id.name + 2, offsetof(ID, name) + 2); + BLI_assert(workspace != NULL); + WorkSpaceLayout* layout = BKE_workspace_layout_find(workspace, win->screen); + BLI_assert(layout != NULL); + + win->workspace_hook = BKE_workspace_instance_hook_create(bmain); + + BKE_workspace_active_set(win->workspace_hook, workspace); + BKE_workspace_active_layout_set(win->workspace_hook, layout); + + /* Move scene and view layer to window. */ + Scene* scene = screen->scene; + ViewLayer* layer = BLI_findlink(&scene->view_layers, scene->r.actlay); + if (!layer) { + layer = BKE_view_layer_default_view(scene); + } + + win->scene = scene; + STRNCPY(win->view_layer_name, layer->name); + + /* Deprecated from now on! */ + win->screen = NULL; + } + } + + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + /* Deprecated from now on! */ + BLI_freelistN(&screen->scene->transform_spaces); + screen->scene = NULL; + } } #ifdef USE_COLLECTION_COMPAT_28 enum { - COLLECTION_DEPRECATED_VISIBLE = (1 << 0), - COLLECTION_DEPRECATED_VIEWPORT = (1 << 0), - COLLECTION_DEPRECATED_SELECTABLE = (1 << 1), - COLLECTION_DEPRECATED_DISABLED = (1 << 2), - COLLECTION_DEPRECATED_RENDER = (1 << 3), + COLLECTION_DEPRECATED_VISIBLE = (1 << 0), + COLLECTION_DEPRECATED_VIEWPORT = (1 << 0), + COLLECTION_DEPRECATED_SELECTABLE = (1 << 1), + COLLECTION_DEPRECATED_DISABLED = (1 << 2), + COLLECTION_DEPRECATED_RENDER = (1 << 3), }; -static void do_version_view_layer_visibility(ViewLayer *view_layer) +static void do_version_view_layer_visibility(ViewLayer* view_layer) { - /* Convert from deprecated VISIBLE flag to DISABLED */ - LayerCollection *lc; - for (lc = view_layer->layer_collections.first; lc; lc = lc->next) { - if (lc->flag & COLLECTION_DEPRECATED_DISABLED) { - lc->flag &= ~COLLECTION_DEPRECATED_DISABLED; - } - - if ((lc->flag & COLLECTION_DEPRECATED_VISIBLE) == 0) { - lc->flag |= COLLECTION_DEPRECATED_DISABLED; - } - - lc->flag |= COLLECTION_DEPRECATED_VIEWPORT | COLLECTION_DEPRECATED_RENDER; - } + /* Convert from deprecated VISIBLE flag to DISABLED */ + LayerCollection* lc; + for (lc = view_layer->layer_collections.first; lc; lc = lc->next) { + if (lc->flag & COLLECTION_DEPRECATED_DISABLED) { + lc->flag &= ~COLLECTION_DEPRECATED_DISABLED; + } + + if ((lc->flag & COLLECTION_DEPRECATED_VISIBLE) == 0) { + lc->flag |= COLLECTION_DEPRECATED_DISABLED; + } + + lc->flag |= COLLECTION_DEPRECATED_VIEWPORT | COLLECTION_DEPRECATED_RENDER; + } } -static void do_version_layer_collection_pre(ViewLayer *view_layer, - ListBase *lb, - GSet *enabled_set, - GSet *selectable_set) +static void do_version_layer_collection_pre(ViewLayer* view_layer, + ListBase* lb, + GSet* enabled_set, + GSet* selectable_set) { - /* Convert from deprecated DISABLED to new layer collection and collection flags */ - for (LayerCollection *lc = lb->first; lc; lc = lc->next) { - if (lc->scene_collection) { - if (!(lc->flag & COLLECTION_DEPRECATED_DISABLED)) { - BLI_gset_insert(enabled_set, lc->scene_collection); - } - if (lc->flag & COLLECTION_DEPRECATED_SELECTABLE) { - BLI_gset_insert(selectable_set, lc->scene_collection); - } - } - - do_version_layer_collection_pre( - view_layer, &lc->layer_collections, enabled_set, selectable_set); - } + /* Convert from deprecated DISABLED to new layer collection and collection flags */ + for (LayerCollection* lc = lb->first; lc; lc = lc->next) { + if (lc->scene_collection) { + if (!(lc->flag & COLLECTION_DEPRECATED_DISABLED)) { + BLI_gset_insert(enabled_set, lc->scene_collection); + } + if (lc->flag & COLLECTION_DEPRECATED_SELECTABLE) { + BLI_gset_insert(selectable_set, lc->scene_collection); + } + } + + do_version_layer_collection_pre( + view_layer, &lc->layer_collections, enabled_set, selectable_set); + } } -static void do_version_layer_collection_post(ViewLayer *view_layer, - ListBase *lb, - GSet *enabled_set, - GSet *selectable_set, - GHash *collection_map) +static void do_version_layer_collection_post(ViewLayer* view_layer, + ListBase* lb, + GSet* enabled_set, + GSet* selectable_set, + GHash* collection_map) { - /* Apply layer collection exclude flags. */ - for (LayerCollection *lc = lb->first; lc; lc = lc->next) { - if (!(lc->collection->flag & COLLECTION_IS_MASTER)) { - SceneCollection *sc = BLI_ghash_lookup(collection_map, lc->collection); - const bool enabled = (sc && BLI_gset_haskey(enabled_set, sc)); - const bool selectable = (sc && BLI_gset_haskey(selectable_set, sc)); - - if (!enabled) { - lc->flag |= LAYER_COLLECTION_EXCLUDE; - } - if (enabled && !selectable) { - lc->collection->flag |= COLLECTION_RESTRICT_SELECT; - } - } - - do_version_layer_collection_post( - view_layer, &lc->layer_collections, enabled_set, selectable_set, collection_map); - } + /* Apply layer collection exclude flags. */ + for (LayerCollection* lc = lb->first; lc; lc = lc->next) { + if (!(lc->collection->flag & COLLECTION_IS_MASTER)) { + SceneCollection* sc = BLI_ghash_lookup(collection_map, lc->collection); + const bool enabled = (sc && BLI_gset_haskey(enabled_set, sc)); + const bool selectable = (sc && BLI_gset_haskey(selectable_set, sc)); + + if (!enabled) { + lc->flag |= LAYER_COLLECTION_EXCLUDE; + } + if (enabled && !selectable) { + lc->collection->flag |= COLLECTION_RESTRICT_SELECT; + } + } + + do_version_layer_collection_post( + view_layer, &lc->layer_collections, enabled_set, selectable_set, collection_map); + } } static void do_version_scene_collection_convert( - Main *bmain, ID *id, SceneCollection *sc, Collection *collection, GHash *collection_map) + Main* bmain, ID* id, SceneCollection* sc, Collection* collection, GHash* collection_map) { - if (collection_map) { - BLI_ghash_insert(collection_map, collection, sc); - } - - for (SceneCollection *nsc = sc->scene_collections.first; nsc;) { - SceneCollection *nsc_next = nsc->next; - Collection *ncollection = BKE_collection_add(bmain, collection, nsc->name); - ncollection->id.lib = id->lib; - do_version_scene_collection_convert(bmain, id, nsc, ncollection, collection_map); - nsc = nsc_next; - } - - for (LinkData *link = sc->objects.first; link; link = link->next) { - Object *ob = link->data; - if (ob) { - BKE_collection_object_add(bmain, collection, ob); - id_us_min(&ob->id); - } - } - - BLI_freelistN(&sc->objects); - MEM_freeN(sc); + if (collection_map) { + BLI_ghash_insert(collection_map, collection, sc); + } + + for (SceneCollection* nsc = sc->scene_collections.first; nsc;) { + SceneCollection* nsc_next = nsc->next; + Collection* ncollection = BKE_collection_add(bmain, collection, nsc->name); + ncollection->id.lib = id->lib; + do_version_scene_collection_convert(bmain, id, nsc, ncollection, collection_map); + nsc = nsc_next; + } + + for (LinkData* link = sc->objects.first; link; link = link->next) { + Object* ob = link->data; + if (ob) { + BKE_collection_object_add(bmain, collection, ob); + id_us_min(&ob->id); + } + } + + BLI_freelistN(&sc->objects); + MEM_freeN(sc); } -static void do_version_group_collection_to_collection(Main *bmain, Collection *group) +static void do_version_group_collection_to_collection(Main* bmain, Collection* group) { - /* Convert old 2.8 group collections to new unified collections. */ - if (group->collection) { - do_version_scene_collection_convert(bmain, &group->id, group->collection, group, NULL); - } - - group->collection = NULL; - group->view_layer = NULL; - id_fake_user_set(&group->id); + /* Convert old 2.8 group collections to new unified collections. */ + if (group->collection) { + do_version_scene_collection_convert(bmain, &group->id, group->collection, group, NULL); + } + + group->collection = NULL; + group->view_layer = NULL; + id_fake_user_set(&group->id); } -static void do_version_scene_collection_to_collection(Main *bmain, Scene *scene) +static void do_version_scene_collection_to_collection(Main* bmain, Scene* scene) { - /* Convert old 2.8 scene collections to new unified collections. */ + /* Convert old 2.8 scene collections to new unified collections. */ - /* Temporarily clear view layers so we don't do any layer collection syncing - * and destroy old flags that we want to restore. */ - ListBase view_layers = scene->view_layers; - BLI_listbase_clear(&scene->view_layers); + /* Temporarily clear view layers so we don't do any layer collection syncing + * and destroy old flags that we want to restore. */ + ListBase view_layers = scene->view_layers; + BLI_listbase_clear(&scene->view_layers); - if (!scene->master_collection) { - scene->master_collection = BKE_collection_master_add(); - } + if (!scene->master_collection) { + scene->master_collection = BKE_collection_master_add(); + } - /* Convert scene collections. */ - GHash *collection_map = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - if (scene->collection) { - do_version_scene_collection_convert( - bmain, &scene->id, scene->collection, scene->master_collection, collection_map); - scene->collection = NULL; - } + /* Convert scene collections. */ + GHash* collection_map = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + if (scene->collection) { + do_version_scene_collection_convert( + bmain, &scene->id, scene->collection, scene->master_collection, collection_map); + scene->collection = NULL; + } - scene->view_layers = view_layers; + scene->view_layers = view_layers; - /* Convert layer collections. */ - ViewLayer *view_layer; - for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - GSet *enabled_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - GSet *selectable_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + /* Convert layer collections. */ + ViewLayer* view_layer; + for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + GSet* enabled_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + GSet* selectable_set = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - do_version_layer_collection_pre( - view_layer, &view_layer->layer_collections, enabled_set, selectable_set); + do_version_layer_collection_pre( + view_layer, &view_layer->layer_collections, enabled_set, selectable_set); - BKE_layer_collection_sync(scene, view_layer); + BKE_layer_collection_sync(scene, view_layer); - do_version_layer_collection_post( - view_layer, &view_layer->layer_collections, enabled_set, selectable_set, collection_map); + do_version_layer_collection_post( + view_layer, &view_layer->layer_collections, enabled_set, selectable_set, collection_map); - BLI_gset_free(enabled_set, NULL); - BLI_gset_free(selectable_set, NULL); + BLI_gset_free(enabled_set, NULL); + BLI_gset_free(selectable_set, NULL); - BKE_layer_collection_sync(scene, view_layer); - } + BKE_layer_collection_sync(scene, view_layer); + } - BLI_ghash_free(collection_map, NULL, NULL); + BLI_ghash_free(collection_map, NULL, NULL); } #endif -static void do_version_layers_to_collections(Main *bmain, Scene *scene) +static void do_version_layers_to_collections(Main* bmain, Scene* scene) { - /* Since we don't have access to FileData we check the (always valid) first - * render layer instead. */ - if (!scene->master_collection) { - scene->master_collection = BKE_collection_master_add(); - } - - if (scene->view_layers.first) { - return; - } - - /* Create collections from layers. */ - Collection *collection_master = scene->master_collection; - Collection *collections[20] = {NULL}; - - for (int layer = 0; layer < 20; layer++) { - for (Base *base = scene->base.first; base; base = base->next) { - if (base->lay & (1 << layer)) { - /* Create collections when needed only. */ - if (collections[layer] == NULL) { - char name[MAX_NAME]; - - BLI_snprintf( - name, sizeof(collection_master->id.name), DATA_("Collection %d"), layer + 1); - - Collection *collection = BKE_collection_add(bmain, collection_master, name); - collection->id.lib = scene->id.lib; - if (collection->id.lib != NULL) { - collection->id.tag |= LIB_TAG_INDIRECT; - } - collections[layer] = collection; - - if (!(scene->lay & (1 << layer))) { - collection->flag |= COLLECTION_RESTRICT_VIEWPORT | COLLECTION_RESTRICT_RENDER; - } - } - - /* Note usually this would do slow collection syncing for view layers, - * but since no view layers exists yet at this point it's fast. */ - BKE_collection_object_add(bmain, collections[layer], base->object); - } - - if (base->flag & SELECT) { - base->object->flag |= SELECT; - } - else { - base->object->flag &= ~SELECT; - } - } - } - - /* Handle legacy render layers. */ - bool have_override = false; - const bool need_default_renderlayer = scene->r.layers.first == NULL; - - for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) { - ViewLayer *view_layer = BKE_view_layer_add(scene, srl->name); - - if (srl->layflag & SCE_LAY_DISABLE) { - view_layer->flag &= ~VIEW_LAYER_RENDER; - } - - if ((srl->layflag & SCE_LAY_FRS) == 0) { - view_layer->flag &= ~VIEW_LAYER_FREESTYLE; - } - - view_layer->layflag = srl->layflag; - view_layer->passflag = srl->passflag; - view_layer->pass_alpha_threshold = srl->pass_alpha_threshold; - view_layer->samples = srl->samples; - view_layer->mat_override = srl->mat_override; - - BKE_freestyle_config_free(&view_layer->freestyle_config, true); - view_layer->freestyle_config = srl->freestyleConfig; - view_layer->id_properties = srl->prop; - - /* Set exclusion and overrides. */ - for (int layer = 0; layer < 20; layer++) { - Collection *collection = collections[layer]; - if (collection) { - LayerCollection *lc = BKE_layer_collection_first_from_scene_collection(view_layer, - collection); - - if (srl->lay_exclude & (1 << layer)) { - /* Disable excluded layer. */ - have_override = true; - lc->flag |= LAYER_COLLECTION_EXCLUDE; - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - nlc->flag |= LAYER_COLLECTION_EXCLUDE; - } - } - else { - if (srl->lay_zmask & (1 << layer)) { - have_override = true; - lc->flag |= LAYER_COLLECTION_HOLDOUT; - } - - if ((srl->lay & (1 << layer)) == 0) { - have_override = true; - lc->flag |= LAYER_COLLECTION_INDIRECT_ONLY; - } - } - } - } - - /* for convenience set the same active object in all the layers */ - if (scene->basact) { - view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object); - } - - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) { - base->flag |= BASE_SELECTED; - } - } - } - - BLI_freelistN(&scene->r.layers); - - /* If render layers included overrides, or there are no render layers, - * we also create a vanilla viewport layer. */ - if (have_override || need_default_renderlayer) { - ViewLayer *view_layer = BKE_view_layer_add(scene, "Viewport"); - - /* If we ported all the original render layers, - * we don't need to make the viewport layer renderable. */ - if (!BLI_listbase_is_single(&scene->view_layers)) { - view_layer->flag &= ~VIEW_LAYER_RENDER; - } - - /* convert active base */ - if (scene->basact) { - view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object); - } - - /* convert selected bases */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) { - base->flag |= BASE_SELECTED; - } - - /* keep lay around for forward compatibility (open those files in 2.79) */ - base->lay = base->object->lay; - } - } - - /* remove bases once and for all */ - for (Base *base = scene->base.first; base; base = base->next) { - id_us_min(&base->object->id); - } - - BLI_freelistN(&scene->base); - scene->basact = NULL; + /* Since we don't have access to FileData we check the (always valid) first + * render layer instead. */ + if (!scene->master_collection) { + scene->master_collection = BKE_collection_master_add(); + } + + if (scene->view_layers.first) { + return; + } + + /* Create collections from layers. */ + Collection* collection_master = scene->master_collection; + Collection* collections[20] = { NULL }; + + for (int layer = 0; layer < 20; layer++) { + for (Base* base = scene->base.first; base; base = base->next) { + if (base->lay & (1 << layer)) { + /* Create collections when needed only. */ + if (collections[layer] == NULL) { + char name[MAX_NAME]; + + BLI_snprintf( + name, sizeof(collection_master->id.name), DATA_("Collection %d"), layer + 1); + + Collection* collection = BKE_collection_add(bmain, collection_master, name); + collection->id.lib = scene->id.lib; + if (collection->id.lib != NULL) { + collection->id.tag |= LIB_TAG_INDIRECT; + } + collections[layer] = collection; + + if (!(scene->lay & (1 << layer))) { + collection->flag |= COLLECTION_RESTRICT_VIEWPORT | COLLECTION_RESTRICT_RENDER; + } + } + + /* Note usually this would do slow collection syncing for view layers, + * but since no view layers exists yet at this point it's fast. */ + BKE_collection_object_add(bmain, collections[layer], base->object); + } + + if (base->flag & SELECT) { + base->object->flag |= SELECT; + } + else { + base->object->flag &= ~SELECT; + } + } + } + + /* Handle legacy render layers. */ + bool have_override = false; + const bool need_default_renderlayer = scene->r.layers.first == NULL; + + for (SceneRenderLayer* srl = scene->r.layers.first; srl; srl = srl->next) { + ViewLayer* view_layer = BKE_view_layer_add(scene, srl->name); + + if (srl->layflag & SCE_LAY_DISABLE) { + view_layer->flag &= ~VIEW_LAYER_RENDER; + } + + if ((srl->layflag & SCE_LAY_FRS) == 0) { + view_layer->flag &= ~VIEW_LAYER_FREESTYLE; + } + + view_layer->layflag = srl->layflag; + view_layer->passflag = srl->passflag; + view_layer->pass_alpha_threshold = srl->pass_alpha_threshold; + view_layer->samples = srl->samples; + view_layer->mat_override = srl->mat_override; + + BKE_freestyle_config_free(&view_layer->freestyle_config, true); + view_layer->freestyle_config = srl->freestyleConfig; + view_layer->id_properties = srl->prop; + + /* Set exclusion and overrides. */ + for (int layer = 0; layer < 20; layer++) { + Collection* collection = collections[layer]; + if (collection) { + LayerCollection* lc = BKE_layer_collection_first_from_scene_collection(view_layer, + collection); + + if (srl->lay_exclude & (1 << layer)) { + /* Disable excluded layer. */ + have_override = true; + lc->flag |= LAYER_COLLECTION_EXCLUDE; + for (LayerCollection* nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + nlc->flag |= LAYER_COLLECTION_EXCLUDE; + } + } + else { + if (srl->lay_zmask & (1 << layer)) { + have_override = true; + lc->flag |= LAYER_COLLECTION_HOLDOUT; + } + + if ((srl->lay & (1 << layer)) == 0) { + have_override = true; + lc->flag |= LAYER_COLLECTION_INDIRECT_ONLY; + } + } + } + } + + /* for convenience set the same active object in all the layers */ + if (scene->basact) { + view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object); + } + + for (Base* base = view_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) { + base->flag |= BASE_SELECTED; + } + } + } + + BLI_freelistN(&scene->r.layers); + + /* If render layers included overrides, or there are no render layers, + * we also create a vanilla viewport layer. */ + if (have_override || need_default_renderlayer) { + ViewLayer* view_layer = BKE_view_layer_add(scene, "Viewport"); + + /* If we ported all the original render layers, + * we don't need to make the viewport layer renderable. */ + if (!BLI_listbase_is_single(&scene->view_layers)) { + view_layer->flag &= ~VIEW_LAYER_RENDER; + } + + /* convert active base */ + if (scene->basact) { + view_layer->basact = BKE_view_layer_base_find(view_layer, scene->basact->object); + } + + /* convert selected bases */ + for (Base* base = view_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLE) && (base->object->flag & SELECT)) { + base->flag |= BASE_SELECTED; + } + + /* keep lay around for forward compatibility (open those files in 2.79) */ + base->lay = base->object->lay; + } + } + + /* remove bases once and for all */ + for (Base* base = scene->base.first; base; base = base->next) { + id_us_min(&base->object->id); + } + + BLI_freelistN(&scene->base); + scene->basact = NULL; } -static void do_version_collection_propagate_lib_to_children(Collection *collection) +static void do_version_collection_propagate_lib_to_children(Collection* collection) { - if (collection->id.lib != NULL) { - for (CollectionChild *collection_child = collection->children.first; collection_child != NULL; - collection_child = collection_child->next) { - if (collection_child->collection->id.lib == NULL) { - collection_child->collection->id.lib = collection->id.lib; - } - do_version_collection_propagate_lib_to_children(collection_child->collection); - } - } + if (collection->id.lib != NULL) { + for (CollectionChild* collection_child = collection->children.first; collection_child != NULL; + collection_child = collection_child->next) { + if (collection_child->collection->id.lib == NULL) { + collection_child->collection->id.lib = collection->id.lib; + } + do_version_collection_propagate_lib_to_children(collection_child->collection); + } + } } /** convert old annotations colors */ -static void do_versions_fix_annotations(bGPdata *gpd) +static void do_versions_fix_annotations(bGPdata* gpd) { - for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) { - for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { - /* fix layers */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* unlock/unhide layer */ - gpl->flag &= ~GP_LAYER_LOCKED; - gpl->flag &= ~GP_LAYER_HIDE; - /* set opacity to 1 */ - gpl->opacity = 1.0f; - /* disable tint */ - gpl->tintcolor[3] = 0.0f; - - 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))) { - /* copy color settings */ - copy_v4_v4(gpl->color, palcolor->color); - } - } - } - } - } - } + for (const bGPDpalette* palette = gpd->palettes.first; palette; palette = palette->next) { + for (bGPDpalettecolor* palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { + /* fix layers */ + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + /* unlock/unhide layer */ + gpl->flag &= ~GP_LAYER_LOCKED; + gpl->flag &= ~GP_LAYER_HIDE; + /* set opacity to 1 */ + gpl->opacity = 1.0f; + /* disable tint */ + gpl->tintcolor[3] = 0.0f; + + LISTBASE_FOREACH(bGPDframe*, gpf, &gpl->frames) { + LISTBASE_FOREACH(bGPDstroke*, gps, &gpf->strokes) { + if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) { + /* copy color settings */ + copy_v4_v4(gpl->color, palcolor->color); + } + } + } + } + } + } } -static void do_versions_remove_region(ListBase *regionbase, ARegion *ar) +static void do_versions_remove_region(ListBase* regionbase, ARegion* ar) { - BLI_freelinkN(regionbase, ar); + BLI_freelinkN(regionbase, ar); } -static void do_versions_remove_regions_by_type(ListBase *regionbase, int regiontype) +static void do_versions_remove_regions_by_type(ListBase* regionbase, int regiontype) { - ARegion *ar, *ar_next; - for (ar = regionbase->first; ar; ar = ar_next) { - ar_next = ar->next; - if (ar->regiontype == regiontype) { - do_versions_remove_region(regionbase, ar); - } - } + ARegion* ar, * ar_next; + for (ar = regionbase->first; ar; ar = ar_next) { + ar_next = ar->next; + if (ar->regiontype == regiontype) { + do_versions_remove_region(regionbase, ar); + } + } } -static ARegion *do_versions_find_region_or_null(ListBase *regionbase, int regiontype) +static ARegion* do_versions_find_region_or_null(ListBase* regionbase, int regiontype) { - for (ARegion *ar = regionbase->first; ar; ar = ar->next) { - if (ar->regiontype == regiontype) { - return ar; - } - } - return NULL; + for (ARegion* ar = regionbase->first; ar; ar = ar->next) { + if (ar->regiontype == regiontype) { + return ar; + } + } + return NULL; } -static ARegion *do_versions_find_region(ListBase *regionbase, int regiontype) +static ARegion* do_versions_find_region(ListBase* regionbase, int regiontype) { - ARegion *ar = do_versions_find_region_or_null(regionbase, regiontype); - if (ar == NULL) { - BLI_assert(!"Did not find expected region in versioning"); - } - return ar; + ARegion* ar = do_versions_find_region_or_null(regionbase, regiontype); + if (ar == NULL) { + BLI_assert(!"Did not find expected region in versioning"); + } + return ar; } -static ARegion *do_versions_add_region(int regiontype, const char *name) +static ARegion* do_versions_add_region(int regiontype, const char* name) { - ARegion *ar = MEM_callocN(sizeof(ARegion), name); - ar->regiontype = regiontype; - return ar; + ARegion* ar = MEM_callocN(sizeof(ARegion), name); + ar->regiontype = regiontype; + return ar; } -static void do_versions_area_ensure_tool_region(Main *bmain, - const short space_type, - const short region_flag) +static void do_versions_area_ensure_tool_region(Main* bmain, + const short space_type, + const short region_flag) { - for (bScreen *screen = bmain->screens.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_type) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); - if (!ar) { - ARegion *header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); - ar = do_versions_add_region(RGN_TYPE_TOOLS, "tools region"); - BLI_insertlinkafter(regionbase, header, ar); - ar->alignment = RGN_ALIGN_LEFT; - ar->flag = region_flag; - } - } - } - } - } + for (bScreen* screen = bmain->screens.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_type) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion* ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS); + if (!ar) { + ARegion* header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); + ar = do_versions_add_region(RGN_TYPE_TOOLS, "tools region"); + BLI_insertlinkafter(regionbase, header, ar); + ar->alignment = RGN_ALIGN_LEFT; + ar->flag = region_flag; + } + } + } + } + } } -static void do_version_bones_split_bbone_scale(ListBase *lb) +static void do_version_bones_split_bbone_scale(ListBase* lb) { - for (Bone *bone = lb->first; bone; bone = bone->next) { - bone->scale_in_y = bone->scale_in_x; - bone->scale_out_y = bone->scale_out_x; + for (Bone* bone = lb->first; bone; bone = bone->next) { + bone->scale_in_y = bone->scale_in_x; + bone->scale_out_y = bone->scale_out_x; - do_version_bones_split_bbone_scale(&bone->childbase); - } + do_version_bones_split_bbone_scale(&bone->childbase); + } } -static void do_version_bones_inherit_scale(ListBase *lb) +static void do_version_bones_inherit_scale(ListBase* lb) { - for (Bone *bone = lb->first; bone; bone = bone->next) { - if (bone->flag & BONE_NO_SCALE) { - bone->inherit_scale_mode = BONE_INHERIT_SCALE_NONE_LEGACY; - bone->flag &= ~BONE_NO_SCALE; - } - - do_version_bones_inherit_scale(&bone->childbase); - } + for (Bone* bone = lb->first; bone; bone = bone->next) { + if (bone->flag & BONE_NO_SCALE) { + bone->inherit_scale_mode = BONE_INHERIT_SCALE_NONE_LEGACY; + bone->flag &= ~BONE_NO_SCALE; + } + + do_version_bones_inherit_scale(&bone->childbase); + } } -static bool replace_bbone_scale_rnapath(char **p_old_path) +static bool replace_bbone_scale_rnapath(char** p_old_path) { - char *old_path = *p_old_path; + char* old_path = *p_old_path; - if (old_path == NULL) { - return false; - } + if (old_path == NULL) { + return false; + } - if (BLI_str_endswith(old_path, "bbone_scalein") || - BLI_str_endswith(old_path, "bbone_scaleout")) { - *p_old_path = BLI_strdupcat(old_path, "x"); + if (BLI_str_endswith(old_path, "bbone_scalein") || + BLI_str_endswith(old_path, "bbone_scaleout")) { + *p_old_path = BLI_strdupcat(old_path, "x"); - MEM_freeN(old_path); - return true; - } + MEM_freeN(old_path); + return true; + } - return false; + return false; } -static void do_version_bbone_scale_fcurve_fix(ListBase *curves, FCurve *fcu) +static void do_version_bbone_scale_fcurve_fix(ListBase* curves, FCurve* fcu) { - /* Update driver variable paths. */ - if (fcu->driver) { - LISTBASE_FOREACH (DriverVar *, dvar, &fcu->driver->variables) { - DRIVER_TARGETS_LOOPER_BEGIN (dvar) { - replace_bbone_scale_rnapath(&dtar->rna_path); - } - DRIVER_TARGETS_LOOPER_END; - } - } - - /* Update F-Curve's path. */ - if (replace_bbone_scale_rnapath(&fcu->rna_path)) { - /* If matched, duplicate the curve and tweak name. */ - FCurve *second = copy_fcurve(fcu); - - second->rna_path[strlen(second->rna_path) - 1] = 'y'; - - BLI_insertlinkafter(curves, fcu, second); - - /* Add to the curve group. */ - second->grp = fcu->grp; - - if (fcu->grp != NULL && fcu->grp->channels.last == fcu) { - fcu->grp->channels.last = second; - } - } + /* Update driver variable paths. */ + if (fcu->driver) { + LISTBASE_FOREACH(DriverVar*, dvar, &fcu->driver->variables) { + DRIVER_TARGETS_LOOPER_BEGIN(dvar) { + replace_bbone_scale_rnapath(&dtar->rna_path); + } + DRIVER_TARGETS_LOOPER_END; + } + } + + /* Update F-Curve's path. */ + if (replace_bbone_scale_rnapath(&fcu->rna_path)) { + /* If matched, duplicate the curve and tweak name. */ + FCurve* second = copy_fcurve(fcu); + + second->rna_path[strlen(second->rna_path) - 1] = 'y'; + + BLI_insertlinkafter(curves, fcu, second); + + /* Add to the curve group. */ + second->grp = fcu->grp; + + if (fcu->grp != NULL && fcu->grp->channels.last == fcu) { + fcu->grp->channels.last = second; + } + } } -static void do_version_bbone_scale_animdata_cb(ID *UNUSED(id), - AnimData *adt, - void *UNUSED(wrapper_data)) +static void do_version_bbone_scale_animdata_cb(ID* UNUSED(id), + AnimData* adt, + void* UNUSED(wrapper_data)) { - LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &adt->drivers) { - do_version_bbone_scale_fcurve_fix(&adt->drivers, fcu); - } + LISTBASE_FOREACH_MUTABLE(FCurve*, fcu, &adt->drivers) { + do_version_bbone_scale_fcurve_fix(&adt->drivers, fcu); + } } -static void do_version_constraints_maintain_volume_mode_uniform(ListBase *lb) +static void do_version_constraints_maintain_volume_mode_uniform(ListBase* lb) { - for (bConstraint *con = lb->first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_SAMEVOL) { - bSameVolumeConstraint *data = (bSameVolumeConstraint *)con->data; - data->mode = SAMEVOL_UNIFORM; - } - } + for (bConstraint* con = lb->first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SAMEVOL) { + bSameVolumeConstraint* data = (bSameVolumeConstraint*)con->data; + data->mode = SAMEVOL_UNIFORM; + } + } } -static void do_version_constraints_copy_scale_power(ListBase *lb) +static void do_version_constraints_copy_scale_power(ListBase* lb) { - for (bConstraint *con = lb->first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_SIZELIKE) { - bSizeLikeConstraint *data = (bSizeLikeConstraint *)con->data; - data->power = 1.0f; - } - } + for (bConstraint* con = lb->first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SIZELIKE) { + bSizeLikeConstraint* data = (bSizeLikeConstraint*)con->data; + data->power = 1.0f; + } + } } -static void do_version_constraints_copy_rotation_mix_mode(ListBase *lb) +static void do_version_constraints_copy_rotation_mix_mode(ListBase* lb) { - for (bConstraint *con = lb->first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_ROTLIKE) { - bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data; - data->mix_mode = (data->flag & ROTLIKE_OFFSET) ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE; - data->flag &= ~ROTLIKE_OFFSET; - } - } + for (bConstraint* con = lb->first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_ROTLIKE) { + bRotateLikeConstraint* data = (bRotateLikeConstraint*)con->data; + data->mix_mode = (data->flag & ROTLIKE_OFFSET) ? ROTLIKE_MIX_OFFSET : ROTLIKE_MIX_REPLACE; + data->flag &= ~ROTLIKE_OFFSET; + } + } } -static void do_versions_seq_alloc_transform_and_crop(ListBase *seqbase) +static void do_versions_seq_alloc_transform_and_crop(ListBase* seqbase) { - for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) { - if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) == 0) { - if (seq->strip->transform == NULL) { - seq->strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform"); - } - - if (seq->strip->crop == NULL) { - seq->strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop"); - } - - if (seq->seqbase.first != NULL) { - do_versions_seq_alloc_transform_and_crop(&seq->seqbase); - } - } - } + for (Sequence* seq = seqbase->first; seq != NULL; seq = seq->next) { + if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) == 0) { + if (seq->strip->transform == NULL) { + seq->strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform"); + } + + if (seq->strip->crop == NULL) { + seq->strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop"); + } + + if (seq->seqbase.first != NULL) { + do_versions_seq_alloc_transform_and_crop(&seq->seqbase); + } + } + } } /* Return true if there is something to convert. */ -static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, char blend_method) +static void do_versions_material_convert_legacy_blend_mode(bNodeTree* ntree, char blend_method) { - bool need_update = false; + bool need_update = false; - /* Iterate backwards from end so we don't encounter newly added links. */ - bNodeLink *prevlink; - for (bNodeLink *link = ntree->links.last; link; link = prevlink) { - prevlink = link->prev; + /* Iterate backwards from end so we don't encounter newly added links. */ + bNodeLink* prevlink; + for (bNodeLink* link = ntree->links.last; link; link = prevlink) { + prevlink = link->prev; - /* Detect link to replace. */ - bNode *fromnode = link->fromnode; - bNodeSocket *fromsock = link->fromsock; - bNode *tonode = link->tonode; - bNodeSocket *tosock = link->tosock; + /* Detect link to replace. */ + bNode* fromnode = link->fromnode; + bNodeSocket* fromsock = link->fromsock; + bNode* tonode = link->tonode; + bNodeSocket* tosock = link->tosock; - if (!(tonode->type == SH_NODE_OUTPUT_MATERIAL && STREQ(tosock->identifier, "Surface"))) { - continue; - } + if (!(tonode->type == SH_NODE_OUTPUT_MATERIAL && STREQ(tosock->identifier, "Surface"))) { + continue; + } - /* Only do outputs that are enabled for EEVEE */ - if (!ELEM(tonode->custom1, SHD_OUTPUT_ALL, SHD_OUTPUT_EEVEE)) { - continue; - } + /* Only do outputs that are enabled for EEVEE */ + if (!ELEM(tonode->custom1, SHD_OUTPUT_ALL, SHD_OUTPUT_EEVEE)) { + continue; + } - if (blend_method == 1 /* MA_BM_ADD */) { - nodeRemLink(ntree, link); + if (blend_method == 1 /* MA_BM_ADD */) { + nodeRemLink(ntree, link); - bNode *add_node = nodeAddStaticNode(NULL, ntree, SH_NODE_ADD_SHADER); - add_node->locx = 0.5f * (fromnode->locx + tonode->locx); - add_node->locy = 0.5f * (fromnode->locy + tonode->locy); + bNode* add_node = nodeAddStaticNode(NULL, ntree, SH_NODE_ADD_SHADER); + add_node->locx = 0.5f * (fromnode->locx + tonode->locx); + add_node->locy = 0.5f * (fromnode->locy + tonode->locy); - bNodeSocket *shader1_socket = add_node->inputs.first; - bNodeSocket *shader2_socket = add_node->inputs.last; - bNodeSocket *add_socket = nodeFindSocket(add_node, SOCK_OUT, "Shader"); + bNodeSocket* shader1_socket = add_node->inputs.first; + bNodeSocket* shader2_socket = add_node->inputs.last; + bNodeSocket* add_socket = nodeFindSocket(add_node, SOCK_OUT, "Shader"); - bNode *transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT); - transp_node->locx = add_node->locx; - transp_node->locy = add_node->locy - 110.0f; + bNode* transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT); + transp_node->locx = add_node->locx; + transp_node->locy = add_node->locy - 110.0f; - bNodeSocket *transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF"); + bNodeSocket* transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF"); - /* Link to input and material output node. */ - nodeAddLink(ntree, fromnode, fromsock, add_node, shader1_socket); - nodeAddLink(ntree, transp_node, transp_socket, add_node, shader2_socket); - nodeAddLink(ntree, add_node, add_socket, tonode, tosock); + /* Link to input and material output node. */ + nodeAddLink(ntree, fromnode, fromsock, add_node, shader1_socket); + nodeAddLink(ntree, transp_node, transp_socket, add_node, shader2_socket); + nodeAddLink(ntree, add_node, add_socket, tonode, tosock); - need_update = true; - } - else if (blend_method == 2 /* MA_BM_MULTIPLY */) { - nodeRemLink(ntree, link); + need_update = true; + } + else if (blend_method == 2 /* MA_BM_MULTIPLY */) { + nodeRemLink(ntree, link); - bNode *transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT); + bNode* transp_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT); - bNodeSocket *color_socket = nodeFindSocket(transp_node, SOCK_IN, "Color"); - bNodeSocket *transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF"); + bNodeSocket* color_socket = nodeFindSocket(transp_node, SOCK_IN, "Color"); + bNodeSocket* transp_socket = nodeFindSocket(transp_node, SOCK_OUT, "BSDF"); - /* If incomming link is from a closure socket, we need to convert it. */ - if (fromsock->type == SOCK_SHADER) { - transp_node->locx = 0.33f * fromnode->locx + 0.66f * tonode->locx; - transp_node->locy = 0.33f * fromnode->locy + 0.66f * tonode->locy; + /* If incomming link is from a closure socket, we need to convert it. */ + if (fromsock->type == SOCK_SHADER) { + transp_node->locx = 0.33f * fromnode->locx + 0.66f * tonode->locx; + transp_node->locy = 0.33f * fromnode->locy + 0.66f * tonode->locy; - bNode *shtorgb_node = nodeAddStaticNode(NULL, ntree, SH_NODE_SHADERTORGB); - shtorgb_node->locx = 0.66f * fromnode->locx + 0.33f * tonode->locx; - shtorgb_node->locy = 0.66f * fromnode->locy + 0.33f * tonode->locy; + bNode* shtorgb_node = nodeAddStaticNode(NULL, ntree, SH_NODE_SHADERTORGB); + shtorgb_node->locx = 0.66f * fromnode->locx + 0.33f * tonode->locx; + shtorgb_node->locy = 0.66f * fromnode->locy + 0.33f * tonode->locy; - bNodeSocket *shader_socket = nodeFindSocket(shtorgb_node, SOCK_IN, "Shader"); - bNodeSocket *rgba_socket = nodeFindSocket(shtorgb_node, SOCK_OUT, "Color"); + bNodeSocket* shader_socket = nodeFindSocket(shtorgb_node, SOCK_IN, "Shader"); + bNodeSocket* rgba_socket = nodeFindSocket(shtorgb_node, SOCK_OUT, "Color"); - nodeAddLink(ntree, fromnode, fromsock, shtorgb_node, shader_socket); - nodeAddLink(ntree, shtorgb_node, rgba_socket, transp_node, color_socket); - } - else { - transp_node->locx = 0.5f * (fromnode->locx + tonode->locx); - transp_node->locy = 0.5f * (fromnode->locy + tonode->locy); + nodeAddLink(ntree, fromnode, fromsock, shtorgb_node, shader_socket); + nodeAddLink(ntree, shtorgb_node, rgba_socket, transp_node, color_socket); + } + else { + transp_node->locx = 0.5f * (fromnode->locx + tonode->locx); + transp_node->locy = 0.5f * (fromnode->locy + tonode->locy); - nodeAddLink(ntree, fromnode, fromsock, transp_node, color_socket); - } + nodeAddLink(ntree, fromnode, fromsock, transp_node, color_socket); + } - /* Link to input and material output node. */ - nodeAddLink(ntree, transp_node, transp_socket, tonode, tosock); + /* Link to input and material output node. */ + nodeAddLink(ntree, transp_node, transp_socket, tonode, tosock); - need_update = true; - } - } + need_update = true; + } + } - if (need_update) { - ntreeUpdateTree(NULL, ntree); - } + if (need_update) { + ntreeUpdateTree(NULL, ntree); + } } -static void do_versions_local_collection_bits_set(LayerCollection *layer_collection) +static void do_versions_local_collection_bits_set(LayerCollection* layer_collection) { - layer_collection->local_collections_bits = ~(0); - LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) { - do_versions_local_collection_bits_set(child); - } + layer_collection->local_collections_bits = ~(0); + LISTBASE_FOREACH(LayerCollection*, child, &layer_collection->layer_collections) { + do_versions_local_collection_bits_set(child); + } } -static void do_version_curvemapping_flag_extend_extrapolate(CurveMapping *cumap) +static void do_version_curvemapping_flag_extend_extrapolate(CurveMapping* cumap) { #define CUMA_EXTEND_EXTRAPOLATE_OLD 1 - for (int curve_map_index = 0; curve_map_index < 4; curve_map_index++) { - CurveMap *cuma = &cumap->cm[curve_map_index]; - if (cuma->flag & CUMA_EXTEND_EXTRAPOLATE_OLD) { - cumap->flag |= CUMA_EXTEND_EXTRAPOLATE; - return; - } - } + for (int curve_map_index = 0; curve_map_index < 4; curve_map_index++) { + CurveMap* cuma = &cumap->cm[curve_map_index]; + if (cuma->flag & CUMA_EXTEND_EXTRAPOLATE_OLD) { + cumap->flag |= CUMA_EXTEND_EXTRAPOLATE; + return; + } + } #undef CUMA_EXTEND_EXTRAPOLATE_OLD } /* Util version to walk over all CurveMappings in the given `bmain` */ -static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMapping *cumap)) +static void do_version_curvemapping_walker(Main* bmain, void (*callback)(CurveMapping* cumap)) { - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - callback(&scene->r.mblur_shutter_curve); - - if (scene->view_settings.curve_mapping) { - callback(scene->view_settings.curve_mapping); - } - - if (scene->ed != NULL) { - LISTBASE_FOREACH (Sequence *, seq, &scene->ed->seqbase) { - LISTBASE_FOREACH (SequenceModifierData *, smd, &seq->modifiers) { - const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); - - if (smti) { - if (smd->type == seqModifierType_Curves) { - CurvesModifierData *cmd = (CurvesModifierData *)smd; - callback(&cmd->curve_mapping); - } - else if (smd->type == seqModifierType_HueCorrect) { - HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd; - callback(&hcmd->curve_mapping); - } - } - } - } - } - - // toolsettings - ToolSettings *ts = scene->toolsettings; - if (ts->vpaint) { - callback(ts->vpaint->paint.cavity_curve); - } - if (ts->wpaint) { - callback(ts->wpaint->paint.cavity_curve); - } - if (ts->sculpt) { - callback(ts->sculpt->paint.cavity_curve); - } - if (ts->uvsculpt) { - callback(ts->uvsculpt->paint.cavity_curve); - } - if (ts->gp_paint) { - callback(ts->gp_paint->paint.cavity_curve); - } - if (ts->gp_interpolate.custom_ipo) { - callback(ts->gp_interpolate.custom_ipo); - } - if (ts->gp_sculpt.cur_falloff) { - callback(ts->gp_sculpt.cur_falloff); - } - if (ts->gp_sculpt.cur_primitive) { - callback(ts->gp_sculpt.cur_primitive); - } - callback(ts->imapaint.paint.cavity_curve); - } - - FOREACH_NODETREE_BEGIN (bmain, node_tree, id) { - LISTBASE_FOREACH (bNode *, node, &node_tree->nodes) { - if (ELEM(node->type, - SH_NODE_CURVE_VEC, - SH_NODE_CURVE_RGB, - CMP_NODE_CURVE_VEC, - CMP_NODE_CURVE_RGB, - CMP_NODE_TIME, - CMP_NODE_HUECORRECT, - TEX_NODE_CURVE_RGB, - TEX_NODE_CURVE_TIME)) { - callback((CurveMapping *)node->storage); - } - } - } - FOREACH_NODETREE_END; - - LISTBASE_FOREACH (Light *, light, &bmain->lights) { - if (light->curfalloff) { - callback(light->curfalloff); - } - } - - LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { - if (brush->curve) { - callback(brush->curve); - } - if (brush->gpencil_settings) { - if (brush->gpencil_settings->curve_sensitivity) { - callback(brush->gpencil_settings->curve_sensitivity); - } - if (brush->gpencil_settings->curve_strength) { - callback(brush->gpencil_settings->curve_strength); - } - if (brush->gpencil_settings->curve_jitter) { - callback(brush->gpencil_settings->curve_jitter); - } - } - } - - LISTBASE_FOREACH (ParticleSettings *, part, &bmain->particles) { - if (part->clumpcurve) { - callback(part->clumpcurve); - } - if (part->roughcurve) { - callback(part->roughcurve); - } - if (part->twistcurve) { - callback(part->twistcurve); - } - } - - /* Object */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - /* Object modifiers */ - LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - - if (hmd->curfalloff) { - callback(hmd->curfalloff); - } - } - else if (md->type == eModifierType_Warp) { - WarpModifierData *tmd = (WarpModifierData *)md; - if (tmd->curfalloff) { - callback(tmd->curfalloff); - } - } - else if (md->type == eModifierType_WeightVGEdit) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - - if (wmd->cmap_curve) { - callback(wmd->cmap_curve); - } - } - } - /* Grease pencil modifiers */ - LISTBASE_FOREACH (ModifierData *, md, &ob->greasepencil_modifiers) { - if (md->type == eGpencilModifierType_Thick) { - ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; - - if (gpmd->curve_thickness) { - callback(gpmd->curve_thickness); - } - } - else if (md->type == eGpencilModifierType_Hook) { - HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md; - - if (gpmd->curfalloff) { - callback(gpmd->curfalloff); - } - } - } - } - - /* Free Style */ - LISTBASE_FOREACH (struct FreestyleLineStyle *, linestyle, &bmain->linestyles) { - LISTBASE_FOREACH (LineStyleModifier *, m, &linestyle->alpha_modifiers) { - switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - callback(((LineStyleAlphaModifier_AlongStroke *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - callback(((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - callback(((LineStyleAlphaModifier_DistanceFromObject *)m)->curve); - break; - case LS_MODIFIER_MATERIAL: - callback(((LineStyleAlphaModifier_Material *)m)->curve); - break; - case LS_MODIFIER_TANGENT: - callback(((LineStyleAlphaModifier_Tangent *)m)->curve); - break; - case LS_MODIFIER_NOISE: - callback(((LineStyleAlphaModifier_Noise *)m)->curve); - break; - case LS_MODIFIER_CREASE_ANGLE: - callback(((LineStyleAlphaModifier_CreaseAngle *)m)->curve); - break; - case LS_MODIFIER_CURVATURE_3D: - callback(((LineStyleAlphaModifier_Curvature_3D *)m)->curve); - break; - } - } - - LISTBASE_FOREACH (LineStyleModifier *, m, &linestyle->thickness_modifiers) { - switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - callback(((LineStyleThicknessModifier_AlongStroke *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - callback(((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - callback(((LineStyleThicknessModifier_DistanceFromObject *)m)->curve); - break; - case LS_MODIFIER_MATERIAL: - callback(((LineStyleThicknessModifier_Material *)m)->curve); - break; - case LS_MODIFIER_TANGENT: - callback(((LineStyleThicknessModifier_Tangent *)m)->curve); - break; - case LS_MODIFIER_CREASE_ANGLE: - callback(((LineStyleThicknessModifier_CreaseAngle *)m)->curve); - break; - case LS_MODIFIER_CURVATURE_3D: - callback(((LineStyleThicknessModifier_Curvature_3D *)m)->curve); - break; - } - } - } + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + callback(&scene->r.mblur_shutter_curve); + + if (scene->view_settings.curve_mapping) { + callback(scene->view_settings.curve_mapping); + } + + if (scene->ed != NULL) { + LISTBASE_FOREACH(Sequence*, seq, &scene->ed->seqbase) { + LISTBASE_FOREACH(SequenceModifierData*, smd, &seq->modifiers) { + const SequenceModifierTypeInfo* smti = BKE_sequence_modifier_type_info_get(smd->type); + + if (smti) { + if (smd->type == seqModifierType_Curves) { + CurvesModifierData* cmd = (CurvesModifierData*)smd; + callback(&cmd->curve_mapping); + } + else if (smd->type == seqModifierType_HueCorrect) { + HueCorrectModifierData* hcmd = (HueCorrectModifierData*)smd; + callback(&hcmd->curve_mapping); + } + } + } + } + } + + // toolsettings + ToolSettings* ts = scene->toolsettings; + if (ts->vpaint) { + callback(ts->vpaint->paint.cavity_curve); + } + if (ts->wpaint) { + callback(ts->wpaint->paint.cavity_curve); + } + if (ts->sculpt) { + callback(ts->sculpt->paint.cavity_curve); + } + if (ts->uvsculpt) { + callback(ts->uvsculpt->paint.cavity_curve); + } + if (ts->gp_paint) { + callback(ts->gp_paint->paint.cavity_curve); + } + if (ts->gp_interpolate.custom_ipo) { + callback(ts->gp_interpolate.custom_ipo); + } + if (ts->gp_sculpt.cur_falloff) { + callback(ts->gp_sculpt.cur_falloff); + } + if (ts->gp_sculpt.cur_primitive) { + callback(ts->gp_sculpt.cur_primitive); + } + callback(ts->imapaint.paint.cavity_curve); + } + + FOREACH_NODETREE_BEGIN(bmain, node_tree, id) { + LISTBASE_FOREACH(bNode*, node, &node_tree->nodes) { + if (ELEM(node->type, + SH_NODE_CURVE_VEC, + SH_NODE_CURVE_RGB, + CMP_NODE_CURVE_VEC, + CMP_NODE_CURVE_RGB, + CMP_NODE_TIME, + CMP_NODE_HUECORRECT, + TEX_NODE_CURVE_RGB, + TEX_NODE_CURVE_TIME)) { + callback((CurveMapping*)node->storage); + } + } + } + FOREACH_NODETREE_END; + + LISTBASE_FOREACH(Light*, light, &bmain->lights) { + if (light->curfalloff) { + callback(light->curfalloff); + } + } + + LISTBASE_FOREACH(Brush*, brush, &bmain->brushes) { + if (brush->curve) { + callback(brush->curve); + } + if (brush->gpencil_settings) { + if (brush->gpencil_settings->curve_sensitivity) { + callback(brush->gpencil_settings->curve_sensitivity); + } + if (brush->gpencil_settings->curve_strength) { + callback(brush->gpencil_settings->curve_strength); + } + if (brush->gpencil_settings->curve_jitter) { + callback(brush->gpencil_settings->curve_jitter); + } + } + } + + LISTBASE_FOREACH(ParticleSettings*, part, &bmain->particles) { + if (part->clumpcurve) { + callback(part->clumpcurve); + } + if (part->roughcurve) { + callback(part->roughcurve); + } + if (part->twistcurve) { + callback(part->twistcurve); + } + } + + /* Object */ + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + /* Object modifiers */ + LISTBASE_FOREACH(ModifierData*, md, &ob->modifiers) { + if (md->type == eModifierType_Hook) { + HookModifierData* hmd = (HookModifierData*)md; + + if (hmd->curfalloff) { + callback(hmd->curfalloff); + } + } + else if (md->type == eModifierType_Warp) { + WarpModifierData* tmd = (WarpModifierData*)md; + if (tmd->curfalloff) { + callback(tmd->curfalloff); + } + } + else if (md->type == eModifierType_WeightVGEdit) { + WeightVGEditModifierData* wmd = (WeightVGEditModifierData*)md; + + if (wmd->cmap_curve) { + callback(wmd->cmap_curve); + } + } + } + /* Grease pencil modifiers */ + LISTBASE_FOREACH(ModifierData*, md, &ob->greasepencil_modifiers) { + if (md->type == eGpencilModifierType_Thick) { + ThickGpencilModifierData* gpmd = (ThickGpencilModifierData*)md; + + if (gpmd->curve_thickness) { + callback(gpmd->curve_thickness); + } + } + else if (md->type == eGpencilModifierType_Hook) { + HookGpencilModifierData* gpmd = (HookGpencilModifierData*)md; + + if (gpmd->curfalloff) { + callback(gpmd->curfalloff); + } + } + } + } + + /* Free Style */ + LISTBASE_FOREACH(struct FreestyleLineStyle*, linestyle, &bmain->linestyles) { + LISTBASE_FOREACH(LineStyleModifier*, m, &linestyle->alpha_modifiers) { + switch (m->type) { + case LS_MODIFIER_ALONG_STROKE: + callback(((LineStyleAlphaModifier_AlongStroke*)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + callback(((LineStyleAlphaModifier_DistanceFromCamera*)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + callback(((LineStyleAlphaModifier_DistanceFromObject*)m)->curve); + break; + case LS_MODIFIER_MATERIAL: + callback(((LineStyleAlphaModifier_Material*)m)->curve); + break; + case LS_MODIFIER_TANGENT: + callback(((LineStyleAlphaModifier_Tangent*)m)->curve); + break; + case LS_MODIFIER_NOISE: + callback(((LineStyleAlphaModifier_Noise*)m)->curve); + break; + case LS_MODIFIER_CREASE_ANGLE: + callback(((LineStyleAlphaModifier_CreaseAngle*)m)->curve); + break; + case LS_MODIFIER_CURVATURE_3D: + callback(((LineStyleAlphaModifier_Curvature_3D*)m)->curve); + break; + } + } + + LISTBASE_FOREACH(LineStyleModifier*, m, &linestyle->thickness_modifiers) { + switch (m->type) { + case LS_MODIFIER_ALONG_STROKE: + callback(((LineStyleThicknessModifier_AlongStroke*)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + callback(((LineStyleThicknessModifier_DistanceFromCamera*)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + callback(((LineStyleThicknessModifier_DistanceFromObject*)m)->curve); + break; + case LS_MODIFIER_MATERIAL: + callback(((LineStyleThicknessModifier_Material*)m)->curve); + break; + case LS_MODIFIER_TANGENT: + callback(((LineStyleThicknessModifier_Tangent*)m)->curve); + break; + case LS_MODIFIER_CREASE_ANGLE: + callback(((LineStyleThicknessModifier_CreaseAngle*)m)->curve); + break; + case LS_MODIFIER_CURVATURE_3D: + callback(((LineStyleThicknessModifier_Curvature_3D*)m)->curve); + break; + } + } + } } -static void do_version_fcurve_hide_viewport_fix(struct ID *UNUSED(id), - struct FCurve *fcu, - void *UNUSED(user_data)) +static void do_version_fcurve_hide_viewport_fix(struct ID* UNUSED(id), + struct FCurve* fcu, + void* UNUSED(user_data)) { - if (strcmp(fcu->rna_path, "hide")) { - return; - } + if (strcmp(fcu->rna_path, "hide")) { + return; + } - MEM_freeN(fcu->rna_path); - fcu->rna_path = BLI_strdupn("hide_viewport", 13); + MEM_freeN(fcu->rna_path); + fcu->rna_path = BLI_strdupn("hide_viewport", 13); } -void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports)) +void do_versions_after_linking_280(Main* bmain, ReportList* UNUSED(reports)) { - bool use_collection_compat_28 = true; - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { - use_collection_compat_28 = false; - - /* Convert group layer visibility flags to hidden nested collection. */ - for (Collection *collection = bmain->collections.first; collection; - collection = collection->id.next) { - /* Add fake user for all existing groups. */ - id_fake_user_set(&collection->id); - - if (collection->flag & (COLLECTION_RESTRICT_VIEWPORT | COLLECTION_RESTRICT_RENDER)) { - continue; - } - - Collection *hidden_collection_array[20] = {NULL}; - for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; - cob = cob_next) { - cob_next = cob->next; - Object *ob = cob->ob; - - if (!(ob->lay & collection->layer)) { - /* Find or create hidden collection matching object's first layer. */ - Collection **collection_hidden = NULL; - int coll_idx = 0; - for (; coll_idx < 20; coll_idx++) { - if (ob->lay & (1 << coll_idx)) { - collection_hidden = &hidden_collection_array[coll_idx]; - break; - } - } - BLI_assert(collection_hidden != NULL); - - if (*collection_hidden == NULL) { - char name[MAX_ID_NAME]; - BLI_snprintf(name, sizeof(name), DATA_("Hidden %d"), coll_idx + 1); - *collection_hidden = BKE_collection_add(bmain, collection, name); - (*collection_hidden)->flag |= COLLECTION_RESTRICT_VIEWPORT | - COLLECTION_RESTRICT_RENDER; - } - - BKE_collection_object_add(bmain, *collection_hidden, ob); - BKE_collection_object_remove(bmain, collection, ob, true); - } - } - } - - /* We need to assign lib pointer to generated hidden collections *after* all have been - * created, otherwise we'll end up with several data-blocks sharing same name/library, - * which is FORBIDDEN! Note: we need this to be recursive, since a child collection may be - * sorted before its parent in bmain. */ - for (Collection *collection = bmain->collections.first; collection != NULL; - collection = collection->id.next) { - do_version_collection_propagate_lib_to_children(collection); - } - - /* Convert layers to collections. */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - do_version_layers_to_collections(bmain, scene); - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - /* same render-layer as do_version_workspaces_after_lib_link will activate, - * so same layer as BKE_view_layer_default_view would return */ - ViewLayer *layer = screen->scene->view_layers.first; - - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - for (SpaceLink *space = sa->spacedata.first; space; space = space->next) { - if (space->spacetype == SPACE_OUTLINER) { - SpaceOutliner *soutliner = (SpaceOutliner *)space; - - soutliner->outlinevis = SO_VIEW_LAYER; - - if (BLI_listbase_count_at_most(&layer->layer_collections, 2) == 1) { - if (soutliner->treestore == NULL) { - soutliner->treestore = BLI_mempool_create( - sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); - } - - /* Create a tree store element for the collection. This is normally - * done in check_persistent (outliner_tree.c), but we need to access - * it here :/ (expand element if it's the only one) */ - TreeStoreElem *tselem = BLI_mempool_calloc(soutliner->treestore); - tselem->type = TSE_LAYER_COLLECTION; - tselem->id = layer->layer_collections.first; - tselem->nr = tselem->used = 0; - tselem->flag &= ~TSE_CLOSED; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - for (SpaceLink *space = sa->spacedata.first; space; space = space->next) { - if (space->spacetype == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)space; - if ((sima) && (sima->gpd)) { - sima->gpd->flag |= GP_DATA_ANNOTATIONS; - do_versions_fix_annotations(sima->gpd); - } - } - if (space->spacetype == SPACE_CLIP) { - SpaceClip *spclip = (SpaceClip *)space; - MovieClip *clip = spclip->clip; - if ((clip) && (clip->gpd)) { - clip->gpd->flag |= GP_DATA_ANNOTATIONS; - do_versions_fix_annotations(clip->gpd); - } - } - } - } - } - } - - /* New workspace design */ - if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) { - do_version_workspaces_after_lib_link(bmain); - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) { - /* Cleanup any remaining SceneRenderLayer data for files that were created - * with Blender 2.8 before the SceneRenderLayer > RenderLayer refactor. */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - for (SceneRenderLayer *srl = scene->r.layers.first; srl; srl = srl->next) { - if (srl->prop) { - IDP_FreeProperty(srl->prop); - } - BKE_freestyle_config_free(&srl->freestyleConfig, true); - } - BLI_freelistN(&scene->r.layers); - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) { - /* Due to several changes to particle RNA and draw code particles from older files may - * no longer be visible. - * Here we correct this by setting a default draw size for those files. */ - for (Object *object = bmain->objects.first; object; object = object->id.next) { - for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) { - if (psys->part->draw_size == 0.0f) { - psys->part->draw_size = 0.1f; - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 4)) { - for (Object *object = bmain->objects.first; object; object = object->id.next) { - if (object->particlesystem.first) { - object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; - for (ParticleSystem *psys = object->particlesystem.first; psys; psys = psys->next) { - if (psys->part->draw & PART_DRAW_EMITTER) { - object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER; - break; - } - } - } - else if (object->transflag & OB_DUPLI) { - object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; - } - else { - object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER; - } - } - - /* Cleanup deprecated flag from particlesettings data-blocks. */ - for (ParticleSettings *part = bmain->particles.first; part; part = part->id.next) { - part->draw &= ~PART_DRAW_EMITTER; - } - } - - /* SpaceTime & SpaceLogic removal/replacing */ - if (!MAIN_VERSION_ATLEAST(bmain, 280, 9)) { - const wmWindowManager *wm = bmain->wm.first; - const Scene *scene = bmain->scenes.first; - - if (wm != NULL) { - /* Action editors need a scene for creation. First, update active - * screens using the active scene of the window they're displayed in. - * Next, update remaining screens using first scene in main listbase. */ - - for (wmWindow *win = wm->windows.first; win; win = win->next) { - const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); - for (ScrArea *area = screen->areabase.first; area; area = area->next) { - if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) { - do_version_area_change_space_to_space_action(area, win->scene); - - /* Don't forget to unset! */ - area->butspacetype = SPACE_EMPTY; - } - } - } - } - if (scene != NULL) { - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *area = screen->areabase.first; area; area = area->next) { - if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) { - /* Areas that were already handled won't be handled again */ - do_version_area_change_space_to_space_action(area, scene); - - /* Don't forget to unset! */ - area->butspacetype = SPACE_EMPTY; - } - } - } - } - } + bool use_collection_compat_28 = true; + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + use_collection_compat_28 = false; + + /* Convert group layer visibility flags to hidden nested collection. */ + for (Collection* collection = bmain->collections.first; collection; + collection = collection->id.next) { + /* Add fake user for all existing groups. */ + id_fake_user_set(&collection->id); + + if (collection->flag & (COLLECTION_RESTRICT_VIEWPORT | COLLECTION_RESTRICT_RENDER)) { + continue; + } + + Collection* hidden_collection_array[20] = { NULL }; + for (CollectionObject* cob = collection->gobject.first, *cob_next = NULL; cob; + cob = cob_next) { + cob_next = cob->next; + Object* ob = cob->ob; + + if (!(ob->lay & collection->layer)) { + /* Find or create hidden collection matching object's first layer. */ + Collection** collection_hidden = NULL; + int coll_idx = 0; + for (; coll_idx < 20; coll_idx++) { + if (ob->lay & (1 << coll_idx)) { + collection_hidden = &hidden_collection_array[coll_idx]; + break; + } + } + BLI_assert(collection_hidden != NULL); + + if (*collection_hidden == NULL) { + char name[MAX_ID_NAME]; + BLI_snprintf(name, sizeof(name), DATA_("Hidden %d"), coll_idx + 1); + *collection_hidden = BKE_collection_add(bmain, collection, name); + (*collection_hidden)->flag |= COLLECTION_RESTRICT_VIEWPORT | + COLLECTION_RESTRICT_RENDER; + } + + BKE_collection_object_add(bmain, *collection_hidden, ob); + BKE_collection_object_remove(bmain, collection, ob, true); + } + } + } + + /* We need to assign lib pointer to generated hidden collections *after* all have been + * created, otherwise we'll end up with several data-blocks sharing same name/library, + * which is FORBIDDEN! Note: we need this to be recursive, since a child collection may be + * sorted before its parent in bmain. */ + for (Collection* collection = bmain->collections.first; collection != NULL; + collection = collection->id.next) { + do_version_collection_propagate_lib_to_children(collection); + } + + /* Convert layers to collections. */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + do_version_layers_to_collections(bmain, scene); + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + /* same render-layer as do_version_workspaces_after_lib_link will activate, + * so same layer as BKE_view_layer_default_view would return */ + ViewLayer* layer = screen->scene->view_layers.first; + + for (ScrArea* sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink* space = sa->spacedata.first; space; space = space->next) { + if (space->spacetype == SPACE_OUTLINER) { + SpaceOutliner* soutliner = (SpaceOutliner*)space; + + soutliner->outlinevis = SO_VIEW_LAYER; + + if (BLI_listbase_count_at_most(&layer->layer_collections, 2) == 1) { + if (soutliner->treestore == NULL) { + soutliner->treestore = BLI_mempool_create( + sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); + } + + /* Create a tree store element for the collection. This is normally + * done in check_persistent (outliner_tree.c), but we need to access + * it here :/ (expand element if it's the only one) */ + TreeStoreElem* tselem = BLI_mempool_calloc(soutliner->treestore); + tselem->type = TSE_LAYER_COLLECTION; + tselem->id = layer->layer_collections.first; + tselem->nr = tselem->used = 0; + tselem->flag &= ~TSE_CLOSED; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea* sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink* space = sa->spacedata.first; space; space = space->next) { + if (space->spacetype == SPACE_IMAGE) { + SpaceImage* sima = (SpaceImage*)space; + if ((sima) && (sima->gpd)) { + sima->gpd->flag |= GP_DATA_ANNOTATIONS; + do_versions_fix_annotations(sima->gpd); + } + } + if (space->spacetype == SPACE_CLIP) { + SpaceClip* spclip = (SpaceClip*)space; + MovieClip* clip = spclip->clip; + if ((clip) && (clip->gpd)) { + clip->gpd->flag |= GP_DATA_ANNOTATIONS; + do_versions_fix_annotations(clip->gpd); + } + } + } + } + } + } + + /* New workspace design */ + if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) { + do_version_workspaces_after_lib_link(bmain); + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) { + /* Cleanup any remaining SceneRenderLayer data for files that were created + * with Blender 2.8 before the SceneRenderLayer > RenderLayer refactor. */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + for (SceneRenderLayer* srl = scene->r.layers.first; srl; srl = srl->next) { + if (srl->prop) { + IDP_FreeProperty(srl->prop); + } + BKE_freestyle_config_free(&srl->freestyleConfig, true); + } + BLI_freelistN(&scene->r.layers); + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) { + /* Due to several changes to particle RNA and draw code particles from older files may + * no longer be visible. + * Here we correct this by setting a default draw size for those files. */ + for (Object* object = bmain->objects.first; object; object = object->id.next) { + for (ParticleSystem* psys = object->particlesystem.first; psys; psys = psys->next) { + if (psys->part->draw_size == 0.0f) { + psys->part->draw_size = 0.1f; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 4)) { + for (Object* object = bmain->objects.first; object; object = object->id.next) { + if (object->particlesystem.first) { + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; + for (ParticleSystem* psys = object->particlesystem.first; psys; psys = psys->next) { + if (psys->part->draw & PART_DRAW_EMITTER) { + object->duplicator_visibility_flag |= OB_DUPLI_FLAG_RENDER; + break; + } + } + } + else if (object->transflag & OB_DUPLI) { + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT; + } + else { + object->duplicator_visibility_flag = OB_DUPLI_FLAG_VIEWPORT | OB_DUPLI_FLAG_RENDER; + } + } + + /* Cleanup deprecated flag from particlesettings data-blocks. */ + for (ParticleSettings* part = bmain->particles.first; part; part = part->id.next) { + part->draw &= ~PART_DRAW_EMITTER; + } + } + + /* SpaceTime & SpaceLogic removal/replacing */ + if (!MAIN_VERSION_ATLEAST(bmain, 280, 9)) { + const wmWindowManager* wm = bmain->wm.first; + const Scene* scene = bmain->scenes.first; + + if (wm != NULL) { + /* Action editors need a scene for creation. First, update active + * screens using the active scene of the window they're displayed in. + * Next, update remaining screens using first scene in main listbase. */ + + for (wmWindow* win = wm->windows.first; win; win = win->next) { + const bScreen* screen = BKE_workspace_active_screen_get(win->workspace_hook); + for (ScrArea* area = screen->areabase.first; area; area = area->next) { + if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) { + do_version_area_change_space_to_space_action(area, win->scene); + + /* Don't forget to unset! */ + area->butspacetype = SPACE_EMPTY; + } + } + } + } + if (scene != NULL) { + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea* area = screen->areabase.first; area; area = area->next) { + if (ELEM(area->butspacetype, SPACE_TIME, SPACE_LOGIC)) { + /* Areas that were already handled won't be handled again */ + do_version_area_change_space_to_space_action(area, scene); + + /* Don't forget to unset! */ + area->butspacetype = SPACE_EMPTY; + } + } + } + } + } #ifdef USE_COLLECTION_COMPAT_28 - if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 14)) { - for (Collection *group = bmain->collections.first; group; group = group->id.next) { - do_version_group_collection_to_collection(bmain, group); - } - - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - do_version_scene_collection_to_collection(bmain, scene); - } - } + if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 14)) { + for (Collection* group = bmain->collections.first; group; group = group->id.next) { + do_version_group_collection_to_collection(bmain, group); + } + + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + do_version_scene_collection_to_collection(bmain, scene); + } + } #endif - /* Update Curve object Shape Key data layout to include the Radius property */ - if (!MAIN_VERSION_ATLEAST(bmain, 280, 23)) { - for (Curve *cu = bmain->curves.first; cu; cu = cu->id.next) { - if (!cu->key || cu->key->elemsize != sizeof(float[4])) { - continue; - } - - cu->key->elemstr[0] = 3; /*KEYELEM_ELEM_SIZE_CURVE*/ - cu->key->elemsize = sizeof(float[3]); - - int new_count = BKE_keyblock_curve_element_count(&cu->nurb); - - for (KeyBlock *block = cu->key->block.first; block; block = block->next) { - int old_count = block->totelem; - void *old_data = block->data; - - if (!old_data || old_count <= 0) { - continue; - } - - block->totelem = new_count; - block->data = MEM_callocN(sizeof(float[3]) * new_count, __func__); - - float *oldptr = old_data; - float(*newptr)[3] = block->data; - - for (Nurb *nu = cu->nurb.first; nu; nu = nu->next) { - if (nu->bezt) { - BezTriple *bezt = nu->bezt; - - for (int a = 0; a < nu->pntsu; a++, bezt++) { - if ((old_count -= 3) < 0) { - memcpy(newptr, bezt->vec, sizeof(float[3][3])); - newptr[3][0] = bezt->tilt; - } - else { - memcpy(newptr, oldptr, sizeof(float[3][4])); - } - - newptr[3][1] = bezt->radius; - - oldptr += 3 * 4; - newptr += 4; /*KEYELEM_ELEM_LEN_BEZTRIPLE*/ - } - } - else if (nu->bp) { - BPoint *bp = nu->bp; - - for (int a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { - if (--old_count < 0) { - copy_v3_v3(newptr[0], bp->vec); - newptr[1][0] = bp->tilt; - } - else { - memcpy(newptr, oldptr, sizeof(float[4])); - } - - newptr[1][1] = bp->radius; - - oldptr += 4; - newptr += 2; /*KEYELEM_ELEM_LEN_BPOINT*/ - } - } - } - - MEM_freeN(old_data); - } - } - } - - /* Move B-Bone custom handle settings from bPoseChannel to Bone. */ - if (!MAIN_VERSION_ATLEAST(bmain, 280, 25)) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - bArmature *arm = ob->data; - - /* If it is an armature from the same file. */ - if (ob->pose && arm && arm->id.lib == ob->id.lib) { - bool rebuild = false; - - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - /* If the 2.7 flag is enabled, processing is needed. */ - if (pchan->bone && (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES)) { - /* If the settings in the Bone are not set, copy. */ - if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO && - pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO && - pchan->bone->bbone_prev == NULL && pchan->bone->bbone_next == NULL) { - pchan->bone->bbone_prev_type = (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL) ? - BBONE_HANDLE_RELATIVE : - BBONE_HANDLE_ABSOLUTE; - pchan->bone->bbone_next_type = (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL) ? - BBONE_HANDLE_RELATIVE : - BBONE_HANDLE_ABSOLUTE; - - if (pchan->bbone_prev) { - pchan->bone->bbone_prev = pchan->bbone_prev->bone; - } - if (pchan->bbone_next) { - pchan->bone->bbone_next = pchan->bbone_next->bone; - } - } - - rebuild = true; - pchan->bboneflag = 0; - } - } - - /* Tag pose rebuild for all objects that use this armature. */ - if (rebuild) { - for (Object *ob2 = bmain->objects.first; ob2; ob2 = ob2->id.next) { - if (ob2->pose && ob2->data == arm) { - ob2->pose->flag |= POSE_RECALC; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 30)) { - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->gpencil_settings != NULL) { - brush->gpencil_tool = brush->gpencil_settings->brush_type; - } - } - BKE_paint_toolslots_init_from_main(bmain); - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 38)) { - /* Ensure we get valid rigidbody object/constraint data in relevant collections' objects. - */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - RigidBodyWorld *rbw = scene->rigidbody_world; - - if (rbw == NULL) { - continue; - } - - BKE_rigidbody_objects_collection_validate(scene, rbw); - BKE_rigidbody_constraints_collection_validate(scene, rbw); - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 69)) { - /* Unify DOF settings (EEVEE part only) */ - const int SCE_EEVEE_DOF_ENABLED = (1 << 7); - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - if (STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE)) { - if (scene->eevee.flag & SCE_EEVEE_DOF_ENABLED) { - Object *cam_ob = scene->camera; - if (cam_ob && cam_ob->type == OB_CAMERA) { - Camera *cam = cam_ob->data; - cam->dof.flag |= CAM_DOF_ENABLED; - } - } - } - } - - LISTBASE_FOREACH (Camera *, camera, &bmain->cameras) { - camera->dof.focus_object = camera->dof_ob; - camera->dof.focus_distance = camera->dof_distance; - camera->dof.aperture_fstop = camera->gpu_dof.fstop; - camera->dof.aperture_rotation = camera->gpu_dof.rotation; - camera->dof.aperture_ratio = camera->gpu_dof.ratio; - camera->dof.aperture_blades = camera->gpu_dof.num_blades; - camera->dof_ob = NULL; - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) { - /* Replace Multiply and Additive blend mode by Alpha Blend - * now that we use dualsource blending. */ - /* We take care of doing only nodetrees that are always part of materials - * with old blending modes. */ - for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) { - bNodeTree *ntree = ma->nodetree; - if (ma->blend_method == 1 /* MA_BM_ADD */) { - if (ma->use_nodes) { - do_versions_material_convert_legacy_blend_mode(ntree, 1 /* MA_BM_ADD */); - } - ma->blend_method = MA_BM_BLEND; - } - else if (ma->blend_method == 2 /* MA_BM_MULTIPLY */) { - if (ma->use_nodes) { - do_versions_material_convert_legacy_blend_mode(ntree, 2 /* MA_BM_MULTIPLY */); - } - ma->blend_method = MA_BM_BLEND; - } - } - - /* Update all ruler layers to set new flag. */ - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - bGPdata *gpd = scene->gpd; - if (gpd == NULL) { - continue; - } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (STREQ(gpl->info, "RulerData3D")) { - gpl->flag |= GP_LAYER_IS_RULER; - break; - } - } - } - - /* This versionning could probably be done only on earlier versions, not sure however - * which exact version fully deprecated tessfaces, so think we can keep that one here, no - * harm to be expected anyway for being over-conservative. */ - for (Mesh *me = bmain->meshes.first; me != NULL; me = me->id.next) { - /*check if we need to convert mfaces to mpolys*/ - if (me->totface && !me->totpoly) { - /* temporarily switch main so that reading from - * external CustomData works */ - Main *gmain = G_MAIN; - G_MAIN = bmain; - - BKE_mesh_do_versions_convert_mfaces_to_mpolys(me); - - G_MAIN = gmain; - } - - /* Deprecated, only kept for conversion. */ - BKE_mesh_tessface_clear(me); - - /* Moved from do_versions because we need updated polygons for calculating normals. */ - if (MAIN_VERSION_OLDER(bmain, 256, 6)) { - BKE_mesh_calc_normals(me); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 282, 2)) { - /* Init all Vertex/Sculpt and Weight Paint brushes. */ - Brush *brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2); - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - ToolSettings *ts = scene->toolsettings; - - BKE_brush_gpencil_vertex_presets(bmain, ts); - BKE_brush_gpencil_sculpt_presets(bmain, ts); - BKE_brush_gpencil_weight_presets(bmain, ts); - - /* Ensure new Paint modes. */ - BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_GPENCIL); - BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL); - BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL); - BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL); - - /* Set default Draw brush. */ - Paint *paint = &ts->gp_paint->paint; - BKE_paint_brush_set(paint, brush); - /* Enable cursor by default. */ - paint->flags |= PAINT_SHOW_BRUSH; - - /* Ensure Palette by default. */ - BKE_gpencil_palette_ensure(bmain, scene); - } - } - - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ - - /* During development of Blender 2.80 the "Object.hide" property was - * removed, and reintroduced in 5e968a996a53 as "Object.hide_viewport". */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - BKE_fcurves_id_cb(&ob->id, do_version_fcurve_hide_viewport_fix, NULL); - } - } + /* Update Curve object Shape Key data layout to include the Radius property */ + if (!MAIN_VERSION_ATLEAST(bmain, 280, 23)) { + for (Curve* cu = bmain->curves.first; cu; cu = cu->id.next) { + if (!cu->key || cu->key->elemsize != sizeof(float[4])) { + continue; + } + + cu->key->elemstr[0] = 3; /*KEYELEM_ELEM_SIZE_CURVE*/ + cu->key->elemsize = sizeof(float[3]); + + int new_count = BKE_keyblock_curve_element_count(&cu->nurb); + + for (KeyBlock* block = cu->key->block.first; block; block = block->next) { + int old_count = block->totelem; + void* old_data = block->data; + + if (!old_data || old_count <= 0) { + continue; + } + + block->totelem = new_count; + block->data = MEM_callocN(sizeof(float[3]) * new_count, __func__); + + float* oldptr = old_data; + float(*newptr)[3] = block->data; + + for (Nurb* nu = cu->nurb.first; nu; nu = nu->next) { + if (nu->bezt) { + BezTriple* bezt = nu->bezt; + + for (int a = 0; a < nu->pntsu; a++, bezt++) { + if ((old_count -= 3) < 0) { + memcpy(newptr, bezt->vec, sizeof(float[3][3])); + newptr[3][0] = bezt->tilt; + } + else { + memcpy(newptr, oldptr, sizeof(float[3][4])); + } + + newptr[3][1] = bezt->radius; + + oldptr += 3 * 4; + newptr += 4; /*KEYELEM_ELEM_LEN_BEZTRIPLE*/ + } + } + else if (nu->bp) { + BPoint* bp = nu->bp; + + for (int a = 0; a < nu->pntsu * nu->pntsv; a++, bp++) { + if (--old_count < 0) { + copy_v3_v3(newptr[0], bp->vec); + newptr[1][0] = bp->tilt; + } + else { + memcpy(newptr, oldptr, sizeof(float[4])); + } + + newptr[1][1] = bp->radius; + + oldptr += 4; + newptr += 2; /*KEYELEM_ELEM_LEN_BPOINT*/ + } + } + } + + MEM_freeN(old_data); + } + } + } + + /* Move B-Bone custom handle settings from bPoseChannel to Bone. */ + if (!MAIN_VERSION_ATLEAST(bmain, 280, 25)) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + bArmature* arm = ob->data; + + /* If it is an armature from the same file. */ + if (ob->pose && arm && arm->id.lib == ob->id.lib) { + bool rebuild = false; + + for (bPoseChannel* pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + /* If the 2.7 flag is enabled, processing is needed. */ + if (pchan->bone && (pchan->bboneflag & PCHAN_BBONE_CUSTOM_HANDLES)) { + /* If the settings in the Bone are not set, copy. */ + if (pchan->bone->bbone_prev_type == BBONE_HANDLE_AUTO && + pchan->bone->bbone_next_type == BBONE_HANDLE_AUTO && + pchan->bone->bbone_prev == NULL && pchan->bone->bbone_next == NULL) { + pchan->bone->bbone_prev_type = (pchan->bboneflag & PCHAN_BBONE_CUSTOM_START_REL) ? + BBONE_HANDLE_RELATIVE : + BBONE_HANDLE_ABSOLUTE; + pchan->bone->bbone_next_type = (pchan->bboneflag & PCHAN_BBONE_CUSTOM_END_REL) ? + BBONE_HANDLE_RELATIVE : + BBONE_HANDLE_ABSOLUTE; + + if (pchan->bbone_prev) { + pchan->bone->bbone_prev = pchan->bbone_prev->bone; + } + if (pchan->bbone_next) { + pchan->bone->bbone_next = pchan->bbone_next->bone; + } + } + + rebuild = true; + pchan->bboneflag = 0; + } + } + + /* Tag pose rebuild for all objects that use this armature. */ + if (rebuild) { + for (Object* ob2 = bmain->objects.first; ob2; ob2 = ob2->id.next) { + if (ob2->pose && ob2->data == arm) { + ob2->pose->flag |= POSE_RECALC; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 30)) { + for (Brush* brush = bmain->brushes.first; brush; brush = brush->id.next) { + if (brush->gpencil_settings != NULL) { + brush->gpencil_tool = brush->gpencil_settings->brush_type; + } + } + BKE_paint_toolslots_init_from_main(bmain); + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 38)) { + /* Ensure we get valid rigidbody object/constraint data in relevant collections' objects. + */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + RigidBodyWorld* rbw = scene->rigidbody_world; + + if (rbw == NULL) { + continue; + } + + BKE_rigidbody_objects_collection_validate(scene, rbw); + BKE_rigidbody_constraints_collection_validate(scene, rbw); + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 69)) { + /* Unify DOF settings (EEVEE part only) */ + const int SCE_EEVEE_DOF_ENABLED = (1 << 7); + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + if (STREQ(scene->r.engine, RE_engine_id_BLENDER_EEVEE)) { + if (scene->eevee.flag & SCE_EEVEE_DOF_ENABLED) { + Object* cam_ob = scene->camera; + if (cam_ob && cam_ob->type == OB_CAMERA) { + Camera* cam = cam_ob->data; + cam->dof.flag |= CAM_DOF_ENABLED; + } + } + } + } + + LISTBASE_FOREACH(Camera*, camera, &bmain->cameras) { + camera->dof.focus_object = camera->dof_ob; + camera->dof.focus_distance = camera->dof_distance; + camera->dof.aperture_fstop = camera->gpu_dof.fstop; + camera->dof.aperture_rotation = camera->gpu_dof.rotation; + camera->dof.aperture_ratio = camera->gpu_dof.ratio; + camera->dof.aperture_blades = camera->gpu_dof.num_blades; + camera->dof_ob = NULL; + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) { + /* Replace Multiply and Additive blend mode by Alpha Blend + * now that we use dualsource blending. */ + /* We take care of doing only nodetrees that are always part of materials + * with old blending modes. */ + for (Material* ma = bmain->materials.first; ma; ma = ma->id.next) { + bNodeTree* ntree = ma->nodetree; + if (ma->blend_method == 1 /* MA_BM_ADD */) { + if (ma->use_nodes) { + do_versions_material_convert_legacy_blend_mode(ntree, 1 /* MA_BM_ADD */); + } + ma->blend_method = MA_BM_BLEND; + } + else if (ma->blend_method == 2 /* MA_BM_MULTIPLY */) { + if (ma->use_nodes) { + do_versions_material_convert_legacy_blend_mode(ntree, 2 /* MA_BM_MULTIPLY */); + } + ma->blend_method = MA_BM_BLEND; + } + } + + /* Update all ruler layers to set new flag. */ + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + bGPdata* gpd = scene->gpd; + if (gpd == NULL) { + continue; + } + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + if (STREQ(gpl->info, "RulerData3D")) { + gpl->flag |= GP_LAYER_IS_RULER; + break; + } + } + } + + /* This versionning could probably be done only on earlier versions, not sure however + * which exact version fully deprecated tessfaces, so think we can keep that one here, no + * harm to be expected anyway for being over-conservative. */ + for (Mesh* me = bmain->meshes.first; me != NULL; me = me->id.next) { + /*check if we need to convert mfaces to mpolys*/ + if (me->totface && !me->totpoly) { + /* temporarily switch main so that reading from + * external CustomData works */ + Main* gmain = G_MAIN; + G_MAIN = bmain; + + BKE_mesh_do_versions_convert_mfaces_to_mpolys(me); + + G_MAIN = gmain; + } + + /* Deprecated, only kept for conversion. */ + BKE_mesh_tessface_clear(me); + + /* Moved from do_versions because we need updated polygons for calculating normals. */ + if (MAIN_VERSION_OLDER(bmain, 256, 6)) { + BKE_mesh_calc_normals(me); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 282, 2)) { + /* Init all Vertex/Sculpt and Weight Paint brushes. */ + Brush* brush = BLI_findstring(&bmain->brushes, "Pencil", offsetof(ID, name) + 2); + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + ToolSettings* ts = scene->toolsettings; + + BKE_brush_gpencil_vertex_presets(bmain, ts); + BKE_brush_gpencil_sculpt_presets(bmain, ts); + BKE_brush_gpencil_weight_presets(bmain, ts); + + /* Ensure new Paint modes. */ + BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_GPENCIL); + BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL); + BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL); + BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL); + + /* Set default Draw brush. */ + Paint* paint = &ts->gp_paint->paint; + BKE_paint_brush_set(paint, brush); + /* Enable cursor by default. */ + paint->flags |= PAINT_SHOW_BRUSH; + + /* Ensure Palette by default. */ + BKE_gpencil_palette_ensure(bmain, scene); + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + + /* During development of Blender 2.80 the "Object.hide" property was + * removed, and reintroduced in 5e968a996a53 as "Object.hide_viewport". */ + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + BKE_fcurves_id_cb(&ob->id, do_version_fcurve_hide_viewport_fix, NULL); + } + } } /* 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) +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); - } - } + 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_versions_seq_set_cache_defaults(Editing *ed) +static void do_versions_seq_set_cache_defaults(Editing* ed) { - ed->cache_flag = SEQ_CACHE_STORE_FINAL_OUT; - ed->cache_flag |= SEQ_CACHE_VIEW_FINAL_OUT; - ed->cache_flag |= SEQ_CACHE_VIEW_ENABLE; - ed->recycle_max_cost = 10.0f; + ed->cache_flag = SEQ_CACHE_STORE_FINAL_OUT; + ed->cache_flag |= SEQ_CACHE_VIEW_FINAL_OUT; + ed->cache_flag |= SEQ_CACHE_VIEW_ENABLE; + ed->recycle_max_cost = 10.0f; } -void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) +void blo_do_versions_280(FileData* fd, Library* UNUSED(lib), Main* bmain) { - bool use_collection_compat_28 = true; - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { - use_collection_compat_28 = false; - - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->r.gauss = 1.5f; - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) { - if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "bleedexp")) { - for (Light *la = bmain->lights.first; la; la = la->id.next) { - la->bleedexp = 2.5f; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) { - for (Camera *ca = bmain->cameras.first; ca; ca = ca->id.next) { - ca->gpu_dof.ratio = 1.0f; - } - } - - /* MTexPoly now removed. */ - if (DNA_struct_find(fd->filesdna, "MTexPoly")) { - for (Mesh *me = bmain->meshes.first; me; me = me->id.next) { - /* If we have UV's, so this file will have MTexPoly layers too! */ - if (me->mloopuv != NULL) { - CustomData_update_typemap(&me->pdata); - CustomData_free_layers(&me->pdata, CD_MTEXPOLY, me->totpoly); - BKE_mesh_update_customdata_pointers(me, false); - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) { - if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "cascade_max_dist")) { - for (Light *la = bmain->lights.first; la; la = la->id.next) { - la->cascade_max_dist = 1000.0f; - la->cascade_count = 4; - la->cascade_exponent = 0.8f; - la->cascade_fade = 0.1f; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "contact_dist")) { - for (Light *la = bmain->lights.first; la; la = la->id.next) { - la->contact_dist = 0.2f; - la->contact_bias = 0.03f; - la->contact_spread = 0.2f; - la->contact_thickness = 0.2f; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) { - for (LightProbe *probe = bmain->lightprobes.first; probe; probe = probe->id.next) { - probe->vis_bias = 1.0f; - probe->vis_blur = 0.2f; - } - } - - typedef enum eNTreeDoVersionErrors { - NTREE_DOVERSION_NO_ERROR = 0, - NTREE_DOVERSION_NEED_OUTPUT = (1 << 0), - NTREE_DOVERSION_TRANSPARENCY_EMISSION = (1 << 1), - } eNTreeDoVersionErrors; - - /* Eevee shader nodes renamed because of the output node system. - * Note that a new output node is not being added here, because it would be overkill - * to handle this case in lib_verify_nodetree. - * - * Also, metallic node is now unified into the principled node. */ - eNTreeDoVersionErrors error = NTREE_DOVERSION_NO_ERROR; - - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - 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")) { - BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname)); - error |= NTREE_DOVERSION_NEED_OUTPUT; - } - - else if (node->type == SH_NODE_EEVEE_SPECULAR && - STREQ(node->idname, "ShaderNodeOutputSpecular")) { - BLI_strncpy(node->idname, "ShaderNodeEeveeSpecular", sizeof(node->idname)); - error |= NTREE_DOVERSION_NEED_OUTPUT; - } - - else if (node->type == 196 /* SH_NODE_OUTPUT_EEVEE_MATERIAL */ && - 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")) { - node->type = SH_NODE_BSDF_PRINCIPLED; - BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname)); - node->custom1 = SHD_GLOSSY_MULTI_GGX; - error |= NTREE_DOVERSION_TRANSPARENCY_EMISSION; - } - } - } - } - 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_TRANSPARENCY_EMISSION) { - BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console"); - printf( - "You need to combine transparency and emission shaders to the converted Principled " - "shader nodes.\n"); - } + bool use_collection_compat_28 = true; + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + use_collection_compat_28 = false; + + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->r.gauss = 1.5f; + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 1)) { + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "bleedexp")) { + for (Light* la = bmain->lights.first; la; la = la->id.next) { + la->bleedexp = 2.5f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "GPUDOFSettings", "float", "ratio")) { + for (Camera* ca = bmain->cameras.first; ca; ca = ca->id.next) { + ca->gpu_dof.ratio = 1.0f; + } + } + + /* MTexPoly now removed. */ + if (DNA_struct_find(fd->filesdna, "MTexPoly")) { + for (Mesh* me = bmain->meshes.first; me; me = me->id.next) { + /* If we have UV's, so this file will have MTexPoly layers too! */ + if (me->mloopuv != NULL) { + CustomData_update_typemap(&me->pdata); + CustomData_free_layers(&me->pdata, CD_MTEXPOLY, me->totpoly); + BKE_mesh_update_customdata_pointers(me, false); + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 2)) { + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "cascade_max_dist")) { + for (Light* la = bmain->lights.first; la; la = la->id.next) { + la->cascade_max_dist = 1000.0f; + la->cascade_count = 4; + la->cascade_exponent = 0.8f; + la->cascade_fade = 0.1f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "contact_dist")) { + for (Light* la = bmain->lights.first; la; la = la->id.next) { + la->contact_dist = 0.2f; + la->contact_bias = 0.03f; + la->contact_spread = 0.2f; + la->contact_thickness = 0.2f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "vis_bias")) { + for (LightProbe* probe = bmain->lightprobes.first; probe; probe = probe->id.next) { + probe->vis_bias = 1.0f; + probe->vis_blur = 0.2f; + } + } + + typedef enum eNTreeDoVersionErrors { + NTREE_DOVERSION_NO_ERROR = 0, + NTREE_DOVERSION_NEED_OUTPUT = (1 << 0), + NTREE_DOVERSION_TRANSPARENCY_EMISSION = (1 << 1), + } eNTreeDoVersionErrors; + + /* Eevee shader nodes renamed because of the output node system. + * Note that a new output node is not being added here, because it would be overkill + * to handle this case in lib_verify_nodetree. + * + * Also, metallic node is now unified into the principled node. */ + eNTreeDoVersionErrors error = NTREE_DOVERSION_NO_ERROR; + + FOREACH_NODETREE_BEGIN(bmain, ntree, id) { + 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")) { + BLI_strncpy(node->idname, "ShaderNodeEeveeMetallic", sizeof(node->idname)); + error |= NTREE_DOVERSION_NEED_OUTPUT; + } + + else if (node->type == SH_NODE_EEVEE_SPECULAR && + STREQ(node->idname, "ShaderNodeOutputSpecular")) { + BLI_strncpy(node->idname, "ShaderNodeEeveeSpecular", sizeof(node->idname)); + error |= NTREE_DOVERSION_NEED_OUTPUT; + } + + else if (node->type == 196 /* SH_NODE_OUTPUT_EEVEE_MATERIAL */ && + 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")) { + node->type = SH_NODE_BSDF_PRINCIPLED; + BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname)); + node->custom1 = SHD_GLOSSY_MULTI_GGX; + error |= NTREE_DOVERSION_TRANSPARENCY_EMISSION; + } + } + } + } + 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_TRANSPARENCY_EMISSION) { + BKE_report(fd->reports, RPT_ERROR, "Eevee material conversion problem. Error in console"); + printf( + "You need to combine transparency and emission shaders to the converted Principled " + "shader nodes.\n"); + } #ifdef USE_COLLECTION_COMPAT_28 - if (use_collection_compat_28 && - (DNA_struct_elem_find(fd->filesdna, "ViewLayer", "FreestyleConfig", "freestyle_config") == - false) && - DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "view_layers")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - ViewLayer *view_layer; - for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - view_layer->flag |= VIEW_LAYER_FREESTYLE; - view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */ - view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z; - view_layer->pass_alpha_threshold = 0.5f; - BKE_freestyle_config_init(&view_layer->freestyle_config); - } - } - } + if (use_collection_compat_28 && + (DNA_struct_elem_find(fd->filesdna, "ViewLayer", "FreestyleConfig", "freestyle_config") == + false) && + DNA_struct_elem_find(fd->filesdna, "Scene", "ListBase", "view_layers")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + ViewLayer* view_layer; + for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + view_layer->flag |= VIEW_LAYER_FREESTYLE; + view_layer->layflag = 0x7FFF; /* solid ztra halo edge strand */ + view_layer->passflag = SCE_PASS_COMBINED | SCE_PASS_Z; + view_layer->pass_alpha_threshold = 0.5f; + BKE_freestyle_config_init(&view_layer->freestyle_config); + } + } + } #endif - { - /* Init grease pencil edit line color */ - if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "line_color[4]")) { - for (bGPdata *gpd = bmain->gpencils.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, "bGPdata", "float", "pixfactor")) { - for (bGPdata *gpd = bmain->gpencils.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_Sculpt_Settings", "CurveMapping", "cur_falloff")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - /* sculpt brushes */ - GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt; - if ((gset) && (gset->cur_falloff == NULL)) { - gset->cur_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - BKE_curvemapping_initialize(gset->cur_falloff); - BKE_curvemap_reset(gset->cur_falloff->cm, - &gset->cur_falloff->clipr, - CURVE_PRESET_GAUSS, - CURVEMAP_SLOPE_POSITIVE); - } - } - } - } - - /* 2.79 style Maintain Volume mode. */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - do_version_constraints_maintain_volume_mode_uniform(&ob->constraints); - if (ob->pose) { - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { - do_version_constraints_maintain_volume_mode_uniform(&pchan->constraints); - } - } - } - } + { + /* Init grease pencil edit line color */ + if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "line_color[4]")) { + for (bGPdata* gpd = bmain->gpencils.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, "bGPdata", "float", "pixfactor")) { + for (bGPdata* gpd = bmain->gpencils.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_Sculpt_Settings", "CurveMapping", "cur_falloff")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + /* sculpt brushes */ + GP_Sculpt_Settings* gset = &scene->toolsettings->gp_sculpt; + if ((gset) && (gset->cur_falloff == NULL)) { + gset->cur_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(gset->cur_falloff); + BKE_curvemap_reset(gset->cur_falloff->cm, + &gset->cur_falloff->clipr, + CURVE_PRESET_GAUSS, + CURVEMAP_SLOPE_POSITIVE); + } + } + } + } + + /* 2.79 style Maintain Volume mode. */ + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + do_version_constraints_maintain_volume_mode_uniform(&ob->constraints); + if (ob->pose) { + LISTBASE_FOREACH(bPoseChannel*, pchan, &ob->pose->chanbase) { + do_version_constraints_maintain_volume_mode_uniform(&pchan->constraints); + } + } + } + } #ifdef USE_COLLECTION_COMPAT_28 - if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 3)) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - ViewLayer *view_layer; - for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - do_version_view_layer_visibility(view_layer); - } - } - - for (Collection *group = bmain->collections.first; group; group = group->id.next) { - if (group->view_layer != NULL) { - do_version_view_layer_visibility(group->view_layer); - } - } - } + if (use_collection_compat_28 && !MAIN_VERSION_ATLEAST(bmain, 280, 3)) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + ViewLayer* view_layer; + for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + do_version_view_layer_visibility(view_layer); + } + } + + for (Collection* group = bmain->collections.first; group; group = group->id.next) { + if (group->view_layer != NULL) { + do_version_view_layer_visibility(group->view_layer); + } + } + } #endif - if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) { - /* init grease pencil grids and paper */ - if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_color[3]")) { - for (bScreen *screen = bmain->screens.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_paper_opacity = 0.5f; - v3d->overlay.gpencil_grid_opacity = 0.9f; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) { - if (DNA_struct_elem_find(fd->filesdna, "SpaceOutliner", "int", "filter") == false) { - bScreen *sc; - ScrArea *sa; - SpaceLink *sl; - - /* Update files using invalid (outdated) outlinevis Outliner values. */ - for (sc = bmain->screens.first; sc; sc = sc->id.next) { - for (sa = sc->areabase.first; sa; sa = sa->next) { - for (sl = sa->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_OUTLINER) { - SpaceOutliner *so = (SpaceOutliner *)sl; - - if (!ELEM(so->outlinevis, - SO_SCENES, - SO_LIBRARIES, - SO_SEQUENCE, - SO_DATA_API, - SO_ID_ORPHANS)) { - so->outlinevis = SO_VIEW_LAYER; - } - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) { - for (LightProbe *probe = bmain->lightprobes.first; probe; probe = probe->id.next) { - probe->intensity = 1.0f; - } - } - - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - bConstraint *con, *con_next; - con = ob->constraints.first; - while (con) { - con_next = con->next; - if (con->type == 17) { /* CONSTRAINT_TYPE_RIGIDBODYJOINT */ - BLI_remlink(&ob->constraints, con); - BKE_constraint_free_data(con); - MEM_freeN(con); - } - con = con_next; - } - } - - for (bScreen *sc = bmain->screens.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->shading.light = V3D_LIGHTING_STUDIO; - v3d->shading.flag |= V3D_SHADING_OBJECT_OUTLINE; - - /* Assume (demo) files written with 2.8 want to show - * Eevee renders in the viewport. */ - if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { - v3d->drawtype = OB_MATERIAL; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 7)) { - /* Render engine storage moved elsewhere and back during 2.8 - * development, we assume any files saved in 2.8 had Eevee set - * as scene render engine. */ - if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine)); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 8)) { - /* Blender Internal removal */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (STREQ(scene->r.engine, "BLENDER_RENDER") || STREQ(scene->r.engine, "BLENDER_GAME")) { - BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine)); - } - - scene->r.bake_mode = 0; - } - - for (Tex *tex = bmain->textures.first; tex; tex = tex->id.next) { - /* Removed envmap, pointdensity, voxeldata, ocean textures. */ - if (ELEM(tex->type, 10, 14, 15, 16)) { - tex->type = 0; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) { - - /* Remove info editor, but only if at the top of the window. */ - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - /* Calculate window width/height from screen vertices */ - int win_width = 0, win_height = 0; - for (ScrVert *vert = screen->vertbase.first; vert; vert = vert->next) { - win_width = MAX2(win_width, vert->vec.x); - win_height = MAX2(win_height, vert->vec.y); - } - - for (ScrArea *area = screen->areabase.first, *area_next; area; area = area_next) { - area_next = area->next; - - if (area->spacetype == SPACE_INFO) { - if ((area->v2->vec.y == win_height) && (area->v1->vec.x == 0) && - (area->v4->vec.x == win_width)) { - BKE_screen_area_free(area); - - BLI_remlink(&screen->areabase, area); - - BKE_screen_remove_double_scredges(screen); - BKE_screen_remove_unused_scredges(screen); - BKE_screen_remove_unused_scrverts(screen); - - MEM_freeN(area); - } - } - /* AREA_TEMP_INFO is deprecated from now on, it should only be set for info areas - * which are deleted above, so don't need to unset it. Its slot/bit can be reused */ - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) { - for (Light *la = bmain->lights.first; la; la = la->id.next) { - if (la->mode & (1 << 13)) { /* LA_SHAD_RAY */ - la->mode |= LA_SHADOW; - la->mode &= ~(1 << 13); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 12)) { - /* Remove tool property regions. */ - for (bScreen *screen = bmain->screens.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 (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_CLIP)) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - - for (ARegion *region = regionbase->first, *region_next; region; region = region_next) { - region_next = region->next; - - if (region->regiontype == RGN_TYPE_TOOL_PROPS) { - BKE_area_region_free(NULL, region); - BLI_freelinkN(regionbase, region); - } - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 13)) { - /* Initialize specular factor. */ - if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "spec_fac")) { - for (Light *la = bmain->lights.first; la; la = la->id.next) { - la->spec_fac = 1.0f; - } - } - - /* Initialize new view3D options. */ - for (bScreen *screen = bmain->screens.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.light = V3D_LIGHTING_STUDIO; - v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR; - copy_v3_fl(v3d->shading.single_color, 0.8f); - v3d->shading.shadow_intensity = 0.5; - - v3d->overlay.backwire_opacity = 0.5f; - v3d->overlay.normals_length = 0.1f; - v3d->overlay.flag = 0; - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 14)) { - if (!DNA_struct_elem_find(fd->filesdna, "Scene", "SceneDisplay", "display")) { - /* Initialize new scene.SceneDisplay */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - copy_v3_v3(scene->display.light_direction, (float[3]){-M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3}); - } - } - if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_shift")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->display.shadow_shift = 0.1; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "transform_pivot_point")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEDIAN; - } - } - - if (!DNA_struct_find(fd->filesdna, "SceneEEVEE")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - /* First set the default for all the properties. */ - - scene->eevee.gi_diffuse_bounces = 3; - scene->eevee.gi_cubemap_resolution = 512; - scene->eevee.gi_visibility_resolution = 32; - - scene->eevee.taa_samples = 16; - scene->eevee.taa_render_samples = 64; - - scene->eevee.sss_samples = 7; - scene->eevee.sss_jitter_threshold = 0.3f; - - scene->eevee.ssr_quality = 0.25f; - scene->eevee.ssr_max_roughness = 0.5f; - scene->eevee.ssr_thickness = 0.2f; - scene->eevee.ssr_border_fade = 0.075f; - scene->eevee.ssr_firefly_fac = 10.0f; - - scene->eevee.volumetric_start = 0.1f; - scene->eevee.volumetric_end = 100.0f; - scene->eevee.volumetric_tile_size = 8; - scene->eevee.volumetric_samples = 64; - scene->eevee.volumetric_sample_distribution = 0.8f; - scene->eevee.volumetric_light_clamp = 0.0f; - scene->eevee.volumetric_shadow_samples = 16; - - scene->eevee.gtao_distance = 0.2f; - scene->eevee.gtao_factor = 1.0f; - scene->eevee.gtao_quality = 0.25f; - - scene->eevee.bokeh_max_size = 100.0f; - scene->eevee.bokeh_threshold = 1.0f; - - copy_v3_fl(scene->eevee.bloom_color, 1.0f); - scene->eevee.bloom_threshold = 0.8f; - scene->eevee.bloom_knee = 0.5f; - scene->eevee.bloom_intensity = 0.05f; - scene->eevee.bloom_radius = 6.5f; - scene->eevee.bloom_clamp = 0.0f; - - scene->eevee.motion_blur_samples = 8; - scene->eevee.motion_blur_shutter = 0.5f; - - scene->eevee.shadow_method = SHADOW_ESM; - scene->eevee.shadow_cube_size = 512; - scene->eevee.shadow_cascade_size = 1024; - - scene->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS | - SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION | - SCE_EEVEE_SSR_HALF_RESOLUTION; - - /* If the file is pre-2.80 move on. */ - if (scene->layer_properties == NULL) { - continue; - } - - /* Now we handle eventual properties that may be set in the file. */ + if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) { + /* init grease pencil grids and paper */ + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_paper_color[3]")) { + for (bScreen* screen = bmain->screens.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_paper_opacity = 0.5f; + v3d->overlay.gpencil_grid_opacity = 0.9f; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 6)) { + if (DNA_struct_elem_find(fd->filesdna, "SpaceOutliner", "int", "filter") == false) { + bScreen* sc; + ScrArea* sa; + SpaceLink* sl; + + /* Update files using invalid (outdated) outlinevis Outliner values. */ + for (sc = bmain->screens.first; sc; sc = sc->id.next) { + for (sa = sc->areabase.first; sa; sa = sa->next) { + for (sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_OUTLINER) { + SpaceOutliner* so = (SpaceOutliner*)sl; + + if (!ELEM(so->outlinevis, + SO_SCENES, + SO_LIBRARIES, + SO_SEQUENCE, + SO_DATA_API, + SO_ID_ORPHANS)) { + so->outlinevis = SO_VIEW_LAYER; + } + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "LightProbe", "float", "intensity")) { + for (LightProbe* probe = bmain->lightprobes.first; probe; probe = probe->id.next) { + probe->intensity = 1.0f; + } + } + + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + bConstraint* con, * con_next; + con = ob->constraints.first; + while (con) { + con_next = con->next; + if (con->type == 17) { /* CONSTRAINT_TYPE_RIGIDBODYJOINT */ + BLI_remlink(&ob->constraints, con); + BKE_constraint_free_data(con); + MEM_freeN(con); + } + con = con_next; + } + } + + for (bScreen* sc = bmain->screens.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->shading.light = V3D_LIGHTING_STUDIO; + v3d->shading.flag |= V3D_SHADING_OBJECT_OUTLINE; + + /* Assume (demo) files written with 2.8 want to show + * Eevee renders in the viewport. */ + if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + v3d->drawtype = OB_MATERIAL; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 7)) { + /* Render engine storage moved elsewhere and back during 2.8 + * development, we assume any files saved in 2.8 had Eevee set + * as scene render engine. */ + if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine)); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 8)) { + /* Blender Internal removal */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + if (STREQ(scene->r.engine, "BLENDER_RENDER") || STREQ(scene->r.engine, "BLENDER_GAME")) { + BLI_strncpy(scene->r.engine, RE_engine_id_BLENDER_EEVEE, sizeof(scene->r.engine)); + } + + scene->r.bake_mode = 0; + } + + for (Tex* tex = bmain->textures.first; tex; tex = tex->id.next) { + /* Removed envmap, pointdensity, voxeldata, ocean textures. */ + if (ELEM(tex->type, 10, 14, 15, 16)) { + tex->type = 0; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) { + + /* Remove info editor, but only if at the top of the window. */ + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + /* Calculate window width/height from screen vertices */ + int win_width = 0, win_height = 0; + for (ScrVert* vert = screen->vertbase.first; vert; vert = vert->next) { + win_width = MAX2(win_width, vert->vec.x); + win_height = MAX2(win_height, vert->vec.y); + } + + for (ScrArea* area = screen->areabase.first, *area_next; area; area = area_next) { + area_next = area->next; + + if (area->spacetype == SPACE_INFO) { + if ((area->v2->vec.y == win_height) && (area->v1->vec.x == 0) && + (area->v4->vec.x == win_width)) { + BKE_screen_area_free(area); + + BLI_remlink(&screen->areabase, area); + + BKE_screen_remove_double_scredges(screen); + BKE_screen_remove_unused_scredges(screen); + BKE_screen_remove_unused_scrverts(screen); + + MEM_freeN(area); + } + } + /* AREA_TEMP_INFO is deprecated from now on, it should only be set for info areas + * which are deleted above, so don't need to unset it. Its slot/bit can be reused */ + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 11)) { + for (Light* la = bmain->lights.first; la; la = la->id.next) { + if (la->mode & (1 << 13)) { /* LA_SHAD_RAY */ + la->mode |= LA_SHADOW; + la->mode &= ~(1 << 13); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 12)) { + /* Remove tool property regions. */ + for (bScreen* screen = bmain->screens.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 (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_CLIP)) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + + for (ARegion* region = regionbase->first, *region_next; region; region = region_next) { + region_next = region->next; + + if (region->regiontype == RGN_TYPE_TOOL_PROPS) { + BKE_area_region_free(NULL, region); + BLI_freelinkN(regionbase, region); + } + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 13)) { + /* Initialize specular factor. */ + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "spec_fac")) { + for (Light* la = bmain->lights.first; la; la = la->id.next) { + la->spec_fac = 1.0f; + } + } + + /* Initialize new view3D options. */ + for (bScreen* screen = bmain->screens.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.light = V3D_LIGHTING_STUDIO; + v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR; + copy_v3_fl(v3d->shading.single_color, 0.8f); + v3d->shading.shadow_intensity = 0.5; + + v3d->overlay.backwire_opacity = 0.5f; + v3d->overlay.normals_length = 0.1f; + v3d->overlay.flag = 0; + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 14)) { + if (!DNA_struct_elem_find(fd->filesdna, "Scene", "SceneDisplay", "display")) { + /* Initialize new scene.SceneDisplay */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + copy_v3_v3(scene->display.light_direction, (float[3]) { -M_SQRT1_3, -M_SQRT1_3, M_SQRT1_3 }); + } + } + if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_shift")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->display.shadow_shift = 0.1; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "transform_pivot_point")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->toolsettings->transform_pivot_point = V3D_AROUND_CENTER_MEDIAN; + } + } + + if (!DNA_struct_find(fd->filesdna, "SceneEEVEE")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + /* First set the default for all the properties. */ + + scene->eevee.gi_diffuse_bounces = 3; + scene->eevee.gi_cubemap_resolution = 512; + scene->eevee.gi_visibility_resolution = 32; + + scene->eevee.taa_samples = 16; + scene->eevee.taa_render_samples = 64; + + scene->eevee.sss_samples = 7; + scene->eevee.sss_jitter_threshold = 0.3f; + + scene->eevee.ssr_quality = 0.25f; + scene->eevee.ssr_max_roughness = 0.5f; + scene->eevee.ssr_thickness = 0.2f; + scene->eevee.ssr_border_fade = 0.075f; + scene->eevee.ssr_firefly_fac = 10.0f; + + scene->eevee.volumetric_start = 0.1f; + scene->eevee.volumetric_end = 100.0f; + scene->eevee.volumetric_tile_size = 8; + scene->eevee.volumetric_samples = 64; + scene->eevee.volumetric_sample_distribution = 0.8f; + scene->eevee.volumetric_light_clamp = 0.0f; + scene->eevee.volumetric_shadow_samples = 16; + + scene->eevee.gtao_distance = 0.2f; + scene->eevee.gtao_factor = 1.0f; + scene->eevee.gtao_quality = 0.25f; + + scene->eevee.bokeh_max_size = 100.0f; + scene->eevee.bokeh_threshold = 1.0f; + + copy_v3_fl(scene->eevee.bloom_color, 1.0f); + scene->eevee.bloom_threshold = 0.8f; + scene->eevee.bloom_knee = 0.5f; + scene->eevee.bloom_intensity = 0.05f; + scene->eevee.bloom_radius = 6.5f; + scene->eevee.bloom_clamp = 0.0f; + + scene->eevee.motion_blur_samples = 8; + scene->eevee.motion_blur_shutter = 0.5f; + + scene->eevee.shadow_method = SHADOW_ESM; + scene->eevee.shadow_cube_size = 512; + scene->eevee.shadow_cascade_size = 1024; + + scene->eevee.flag = SCE_EEVEE_VOLUMETRIC_LIGHTS | SCE_EEVEE_GTAO_BENT_NORMALS | + SCE_EEVEE_GTAO_BOUNCE | SCE_EEVEE_TAA_REPROJECTION | + SCE_EEVEE_SSR_HALF_RESOLUTION; + + /* If the file is pre-2.80 move on. */ + if (scene->layer_properties == NULL) { + continue; + } + + /* Now we handle eventual properties that may be set in the file. */ #define EEVEE_GET_BOOL(_props, _name, _flag) \ { \ IDProperty *_idprop = IDP_GetPropertyFromGroup(_props, #_name); \ @@ -2186,812 +2188,812 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) } \ } \ ((void)0) - const int SCE_EEVEE_DOF_ENABLED = (1 << 7); - IDProperty *props = IDP_GetPropertyFromGroup(scene->layer_properties, - RE_engine_id_BLENDER_EEVEE); - // 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, 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); - EEVEE_GET_BOOL(props, dof_enable, SCE_EEVEE_DOF_ENABLED); - EEVEE_GET_BOOL(props, bloom_enable, SCE_EEVEE_BLOOM_ENABLED); - EEVEE_GET_BOOL(props, motion_blur_enable, SCE_EEVEE_MOTION_BLUR_ENABLED); - EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH); - EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION); - // EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED); - // EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO); - EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED); - EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION); - EEVEE_GET_BOOL(props, ssr_halfres, SCE_EEVEE_SSR_HALF_RESOLUTION); - - EEVEE_GET_INT(props, gi_diffuse_bounces); - EEVEE_GET_INT(props, gi_diffuse_bounces); - EEVEE_GET_INT(props, gi_cubemap_resolution); - EEVEE_GET_INT(props, gi_visibility_resolution); - - EEVEE_GET_INT(props, taa_samples); - EEVEE_GET_INT(props, taa_render_samples); - - EEVEE_GET_INT(props, sss_samples); - EEVEE_GET_FLOAT(props, sss_jitter_threshold); - - EEVEE_GET_FLOAT(props, ssr_quality); - EEVEE_GET_FLOAT(props, ssr_max_roughness); - EEVEE_GET_FLOAT(props, ssr_thickness); - EEVEE_GET_FLOAT(props, ssr_border_fade); - EEVEE_GET_FLOAT(props, ssr_firefly_fac); - - EEVEE_GET_FLOAT(props, volumetric_start); - EEVEE_GET_FLOAT(props, volumetric_end); - EEVEE_GET_INT(props, volumetric_tile_size); - EEVEE_GET_INT(props, volumetric_samples); - EEVEE_GET_FLOAT(props, volumetric_sample_distribution); - EEVEE_GET_FLOAT(props, volumetric_light_clamp); - EEVEE_GET_INT(props, volumetric_shadow_samples); - - EEVEE_GET_FLOAT(props, gtao_distance); - EEVEE_GET_FLOAT(props, gtao_factor); - EEVEE_GET_FLOAT(props, gtao_quality); - - EEVEE_GET_FLOAT(props, bokeh_max_size); - EEVEE_GET_FLOAT(props, bokeh_threshold); - - EEVEE_GET_FLOAT_ARRAY(props, bloom_color, 3); - EEVEE_GET_FLOAT(props, bloom_threshold); - EEVEE_GET_FLOAT(props, bloom_knee); - EEVEE_GET_FLOAT(props, bloom_intensity); - EEVEE_GET_FLOAT(props, bloom_radius); - EEVEE_GET_FLOAT(props, bloom_clamp); - - EEVEE_GET_INT(props, motion_blur_samples); - EEVEE_GET_FLOAT(props, motion_blur_shutter); - - EEVEE_GET_INT(props, shadow_method); - EEVEE_GET_INT(props, shadow_cube_size); - EEVEE_GET_INT(props, shadow_cascade_size); - - /* Cleanup. */ - IDP_FreeProperty(scene->layer_properties); - scene->layer_properties = NULL; + const int SCE_EEVEE_DOF_ENABLED = (1 << 7); + IDProperty* props = IDP_GetPropertyFromGroup(scene->layer_properties, + RE_engine_id_BLENDER_EEVEE); + // 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, 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); + EEVEE_GET_BOOL(props, dof_enable, SCE_EEVEE_DOF_ENABLED); + EEVEE_GET_BOOL(props, bloom_enable, SCE_EEVEE_BLOOM_ENABLED); + EEVEE_GET_BOOL(props, motion_blur_enable, SCE_EEVEE_MOTION_BLUR_ENABLED); + EEVEE_GET_BOOL(props, shadow_high_bitdepth, SCE_EEVEE_SHADOW_HIGH_BITDEPTH); + EEVEE_GET_BOOL(props, taa_reprojection, SCE_EEVEE_TAA_REPROJECTION); + // EEVEE_GET_BOOL(props, sss_enable, SCE_EEVEE_SSS_ENABLED); + // EEVEE_GET_BOOL(props, sss_separate_albedo, SCE_EEVEE_SSS_SEPARATE_ALBEDO); + EEVEE_GET_BOOL(props, ssr_enable, SCE_EEVEE_SSR_ENABLED); + EEVEE_GET_BOOL(props, ssr_refraction, SCE_EEVEE_SSR_REFRACTION); + EEVEE_GET_BOOL(props, ssr_halfres, SCE_EEVEE_SSR_HALF_RESOLUTION); + + EEVEE_GET_INT(props, gi_diffuse_bounces); + EEVEE_GET_INT(props, gi_diffuse_bounces); + EEVEE_GET_INT(props, gi_cubemap_resolution); + EEVEE_GET_INT(props, gi_visibility_resolution); + + EEVEE_GET_INT(props, taa_samples); + EEVEE_GET_INT(props, taa_render_samples); + + EEVEE_GET_INT(props, sss_samples); + EEVEE_GET_FLOAT(props, sss_jitter_threshold); + + EEVEE_GET_FLOAT(props, ssr_quality); + EEVEE_GET_FLOAT(props, ssr_max_roughness); + EEVEE_GET_FLOAT(props, ssr_thickness); + EEVEE_GET_FLOAT(props, ssr_border_fade); + EEVEE_GET_FLOAT(props, ssr_firefly_fac); + + EEVEE_GET_FLOAT(props, volumetric_start); + EEVEE_GET_FLOAT(props, volumetric_end); + EEVEE_GET_INT(props, volumetric_tile_size); + EEVEE_GET_INT(props, volumetric_samples); + EEVEE_GET_FLOAT(props, volumetric_sample_distribution); + EEVEE_GET_FLOAT(props, volumetric_light_clamp); + EEVEE_GET_INT(props, volumetric_shadow_samples); + + EEVEE_GET_FLOAT(props, gtao_distance); + EEVEE_GET_FLOAT(props, gtao_factor); + EEVEE_GET_FLOAT(props, gtao_quality); + + EEVEE_GET_FLOAT(props, bokeh_max_size); + EEVEE_GET_FLOAT(props, bokeh_threshold); + + EEVEE_GET_FLOAT_ARRAY(props, bloom_color, 3); + EEVEE_GET_FLOAT(props, bloom_threshold); + EEVEE_GET_FLOAT(props, bloom_knee); + EEVEE_GET_FLOAT(props, bloom_intensity); + EEVEE_GET_FLOAT(props, bloom_radius); + EEVEE_GET_FLOAT(props, bloom_clamp); + + EEVEE_GET_INT(props, motion_blur_samples); + EEVEE_GET_FLOAT(props, motion_blur_shutter); + + EEVEE_GET_INT(props, shadow_method); + EEVEE_GET_INT(props, shadow_cube_size); + EEVEE_GET_INT(props, shadow_cascade_size); + + /* Cleanup. */ + IDP_FreeProperty(scene->layer_properties); + scene->layer_properties = NULL; #undef EEVEE_GET_FLOAT_ARRAY #undef EEVEE_GET_FLOAT #undef EEVEE_GET_INT #undef EEVEE_GET_BOOL - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 15)) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->display.matcap_ssao_distance = 0.2f; - scene->display.matcap_ssao_attenuation = 1.0f; - scene->display.matcap_ssao_samples = 16; - } - - for (bScreen *screen = bmain->screens.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_OUTLINER) { - SpaceOutliner *soops = (SpaceOutliner *)sl; - soops->filter_id_type = ID_GR; - soops->outlinevis = SO_VIEW_LAYER; - } - } - } - } - - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - switch (scene->toolsettings->snap_mode) { - case 0: - scene->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; - break; - case 1: - scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX; - break; - case 2: - scene->toolsettings->snap_mode = SCE_SNAP_MODE_EDGE; - break; - case 3: - scene->toolsettings->snap_mode = SCE_SNAP_MODE_FACE; - break; - case 4: - scene->toolsettings->snap_mode = SCE_SNAP_MODE_VOLUME; - break; - } - switch (scene->toolsettings->snap_node_mode) { - case 5: - scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X; - break; - case 6: - scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_Y; - break; - case 7: - scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y; - break; - case 8: - scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; - break; - } - switch (scene->toolsettings->snap_uv_mode) { - case 0: - scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT; - break; - case 1: - scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_VERTEX; - break; - } - } - - ParticleSettings *part; - for (part = bmain->particles.first; part; part = part->id.next) { - part->shape_flag = PART_SHAPE_CLOSE_TIP; - part->shape = 0.0f; - part->rad_root = 1.0f; - part->rad_tip = 0.0f; - part->rad_scale = 0.01f; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 18)) { - if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "roughness")) { - for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) { - if (mat->use_nodes) { - if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { - mat->roughness = mat->gloss_mir; - } - else { - mat->roughness = 0.25f; - } - } - else { - mat->roughness = 1.0f - mat->gloss_mir; - } - mat->metallic = mat->ray_mirror; - } - - for (bScreen *screen = bmain->screens.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.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT; - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha")) { - for (bScreen *screen = bmain->screens.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.xray_alpha = 0.5f; - } - } - } - } - } - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "matcap[256]")) { - StudioLight *default_matcap = BKE_studiolight_find_default(STUDIOLIGHT_TYPE_MATCAP); - /* when loading the internal file is loaded before the matcaps */ - if (default_matcap) { - for (bScreen *screen = bmain->screens.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; - BLI_strncpy(v3d->shading.matcap, default_matcap->name, FILE_MAXFILE); - } - } - } - } - } - } - if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_threshold")) { - for (bScreen *screen = bmain->screens.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.wireframe_threshold = 0.5f; - } - } - } - } - } - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) { - for (bScreen *screen = bmain->screens.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.cavity_valley_factor = 1.0f; - v3d->shading.cavity_ridge_factor = 1.0f; - } - } - } - } - } - if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "xray_alpha_bone")) { - for (bScreen *screen = bmain->screens.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.xray_alpha_bone = 0.5f; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 19)) { - if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "renderslot")) { - for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { - if (ima->type == IMA_TYPE_R_RESULT) { - for (int i = 0; i < 8; i++) { - RenderSlot *slot = MEM_callocN(sizeof(RenderSlot), "Image Render Slot Init"); - BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", i + 1); - BLI_addtail(&ima->renderslots, slot); - } - } - } - } - if (!DNA_struct_elem_find(fd->filesdna, "SpaceAction", "char", "mode_prev")) { - for (bScreen *screen = bmain->screens.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_ACTION) { - SpaceAction *saction = (SpaceAction *)sl; - /* "Dopesheet" should be default here, - * unless it looks like the Action Editor was active instead. */ - if ((saction->mode_prev == 0) && (saction->action == NULL)) { - saction->mode_prev = SACTCONT_DOPESHEET; - } - } - } - } - } - } - - for (bScreen *screen = bmain->screens.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; - if (v3d->drawtype == OB_TEXTURE) { - v3d->drawtype = OB_SOLID; - v3d->shading.light = V3D_LIGHTING_STUDIO; - v3d->shading.color_type = V3D_SHADING_TEXTURE_COLOR; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 21)) { - for (Scene *sce = bmain->scenes.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); - } - } - - if (!DNA_struct_elem_find( - fd->filesdna, "View3DOverlay", "float", "texture_paint_mode_opacity")) { - for (bScreen *screen = bmain->screens.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) { - enum { - V3D_SHOW_MODE_SHADE_OVERRIDE = (1 << 15), - }; - View3D *v3d = (View3D *)sl; - float alpha = v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE ? 0.0f : 1.0f; - v3d->overlay.texture_paint_mode_opacity = alpha; - v3d->overlay.vertex_paint_mode_opacity = alpha; - v3d->overlay.weight_paint_mode_opacity = alpha; - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "background_type")) { - for (bScreen *screen = bmain->screens.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; - 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->scenes.first; scene; scene = scene->id.next) { - scene->eevee.gi_irradiance_draw_size = 0.1f; - scene->eevee.gi_cubemap_draw_size = 0.3f; - } - } - - if (!DNA_struct_elem_find( - fd->filesdna, "RigidBodyWorld", "RigidBodyWorld_Shared", "*shared")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - RigidBodyWorld *rbw = scene->rigidbody_world; - - if (rbw == NULL) { - continue; - } - - if (rbw->shared == NULL) { - rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared"); - } - - /* Move shared pointers from deprecated location to current location */ - rbw->shared->pointcache = rbw->pointcache; - rbw->shared->ptcaches = rbw->ptcaches; - - rbw->pointcache = NULL; - BLI_listbase_clear(&rbw->ptcaches); - - if (rbw->shared->pointcache == NULL) { - rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches)); - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "SoftBody", "SoftBody_Shared", "*shared")) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - SoftBody *sb = ob->soft; - if (sb == NULL) { - continue; - } - if (sb->shared == NULL) { - sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared"); - } - - /* Move shared pointers from deprecated location to current location */ - sb->shared->pointcache = sb->pointcache; - sb->shared->ptcaches = sb->ptcaches; - - sb->pointcache = NULL; - BLI_listbase_clear(&sb->ptcaches); - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "short", "type")) { - for (bScreen *screen = bmain->screens.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; - if (v3d->drawtype == OB_RENDER) { - v3d->drawtype = OB_SOLID; - } - v3d->shading.type = v3d->drawtype; - v3d->shading.prev_type = OB_SOLID; - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "View3DShading", "shading")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - 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->screens.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->gp_flag |= 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->scenes.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->gpencils.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_paper_opacity")) { - for (bScreen *screen = bmain->screens.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->screens.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; - } - } - } - } - } - - /* default loc axis */ - if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "lock_axis")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - /* lock axis */ - GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt; - if (gset) { - gset->lock_axis = GP_LOCKAXIS_Y; - } - } - } - - /* Versioning code for Subsurf modifier. */ - if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "uv_smooth")) { - for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { - for (ModifierData *md = object->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Subsurf) { - SubsurfModifierData *smd = (SubsurfModifierData *)md; - if (smd->flags & eSubsurfModifierFlag_SubsurfUv_DEPRECATED) { - smd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; - } - else { - smd->uv_smooth = SUBSURF_UV_SMOOTH_NONE; - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "quality")) { - for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { - for (ModifierData *md = object->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Subsurf) { - SubsurfModifierData *smd = (SubsurfModifierData *)md; - smd->quality = min_ii(smd->renderLevels, 3); - } - } - } - } - /* Versioning code for Multires modifier. */ - if (!DNA_struct_elem_find(fd->filesdna, "MultiresModifier", "short", "quality")) { - for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { - for (ModifierData *md = object->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Multires) { - MultiresModifierData *mmd = (MultiresModifierData *)md; - mmd->quality = 3; - if (mmd->flags & eMultiresModifierFlag_PlainUv_DEPRECATED) { - mmd->uv_smooth = SUBSURF_UV_SMOOTH_NONE; - } - else { - mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "short", "bending_model")) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - ClothModifierData *clmd = NULL; - if (md->type == eModifierType_Cloth) { - clmd = (ClothModifierData *)md; - } - else if (md->type == eModifierType_ParticleSystem) { - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; - ParticleSystem *psys = psmd->psys; - clmd = psys->clmd; - } - if (clmd != NULL) { - clmd->sim_parms->bending_model = CLOTH_BENDING_LINEAR; - clmd->sim_parms->tension = clmd->sim_parms->structural; - clmd->sim_parms->compression = clmd->sim_parms->structural; - clmd->sim_parms->shear = clmd->sim_parms->structural; - clmd->sim_parms->max_tension = clmd->sim_parms->max_struct; - clmd->sim_parms->max_compression = clmd->sim_parms->max_struct; - clmd->sim_parms->max_shear = clmd->sim_parms->max_struct; - clmd->sim_parms->vgroup_shear = clmd->sim_parms->vgroup_struct; - clmd->sim_parms->tension_damp = clmd->sim_parms->Cdis; - clmd->sim_parms->compression_damp = clmd->sim_parms->Cdis; - clmd->sim_parms->shear_damp = clmd->sim_parms->Cdis; - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "era_strength_f")) { - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->gpencil_settings != NULL) { - BrushGpencilSettings *gp = brush->gpencil_settings; - if (gp->brush_type == GPAINT_TOOL_ERASE) { - gp->era_strength_f = 100.0f; - gp->era_thickness_f = 10.0f; - } - } - } - } - - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData *)md; - - if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL)) { - clmd->sim_parms->vgroup_mass = 0; - } - - if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING)) { - clmd->sim_parms->vgroup_struct = 0; - clmd->sim_parms->vgroup_shear = 0; - clmd->sim_parms->vgroup_bend = 0; - } - - if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW)) { - clmd->sim_parms->shrink_min = 0.0f; - clmd->sim_parms->vgroup_shrink = 0; - } - - if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED)) { - clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF; - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 24)) { - for (bScreen *screen = bmain->screens.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.edit_flag |= V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | - V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | - V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | - V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | - V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS; - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "ShrinkwrapModifierData", "char", "shrinkMode")) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Shrinkwrap) { - ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md; - if (smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) { - smd->shrinkMode = MOD_SHRINKWRAP_ABOVE_SURFACE; - smd->shrinkOpts &= ~MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE; - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "PartDeflect", "float", "pdef_cfrict")) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->pd) { - ob->pd->pdef_cfrict = 5.0f; - } - - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData *)md; - - clmd->coll_parms->selfepsilon = 0.015f; - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha_wire")) { - for (bScreen *screen = bmain->screens.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.flag |= V3D_SHADING_XRAY_WIREFRAME; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 25)) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - UnitSettings *unit = &scene->unit; - if (unit->system != USER_UNIT_NONE) { - unit->length_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_LENGTH); - unit->mass_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_MASS); - } - unit->time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_NONE, B_UNIT_TIME); - } - - /* gpencil grid settings */ - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color - ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale - gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 28)) { - for (Mesh *mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) { - BKE_mesh_calc_edges_loose(mesh); - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 29)) { - for (bScreen *screen = bmain->screens.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) { - enum { V3D_OCCLUDE_WIRE = (1 << 14) }; - View3D *v3d = (View3D *)sl; - if (v3d->flag2 & V3D_OCCLUDE_WIRE) { - v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_OCCLUDE_WIRE; - v3d->flag2 &= ~V3D_OCCLUDE_WIRE; - } - } - } - } - } - - /* Files stored pre 2.5 (possibly re-saved with newer versions) may have non-visible - * spaces without a header (visible/active ones are properly versioned). - * Multiple version patches below assume there's always a header though. So inserting this - * patch in-between older ones to add a header when needed. - * - * From here on it should be fine to assume there always is a header. - */ - if (!MAIN_VERSION_ATLEAST(bmain, 283, 1)) { - for (bScreen *screen = bmain->screens.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) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - ARegion *ar_header = do_versions_find_region_or_null(regionbase, RGN_TYPE_HEADER); - - if (!ar_header) { - /* Headers should always be first in the region list, except if there's also a - * tool-header. These were only introduced in later versions though, so should be - * fine to always insert headers first. */ - BLI_assert(!do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)); - - ARegion *ar = do_versions_add_region(RGN_TYPE_HEADER, "header 2.83.1 versioning"); - ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; - BLI_addhead(regionbase, ar); - } - } - } - } - } - - for (bScreen *screen = bmain->screens.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_PROPERTIES) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - ARegion *ar = MEM_callocN(sizeof(ARegion), "navigation bar for properties"); - ARegion *ar_header = NULL; - - for (ar_header = regionbase->first; ar_header; ar_header = ar_header->next) { - if (ar_header->regiontype == RGN_TYPE_HEADER) { - break; - } - } - BLI_assert(ar_header); - - BLI_insertlinkafter(regionbase, ar_header, ar); - - ar->regiontype = RGN_TYPE_NAV_BAR; - ar->alignment = RGN_ALIGN_LEFT; - } - } - } - } - - /* grease pencil fade layer opacity */ - if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_fade_layer")) { - for (bScreen *screen = bmain->screens.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_fade_layer = 0.5f; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 30)) { - /* grease pencil main material show switches */ - for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) { - if (mat->gp_style) { - mat->gp_style->flag |= GP_STYLE_STROKE_SHOW; - mat->gp_style->flag |= GP_STYLE_FILL_SHOW; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 33)) { - - if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "overscan")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->eevee.overscan = 3.0f; - } - } - - for (Light *la = bmain->lights.first; la; la = la->id.next) { - /* Removed Hemi lights. */ - if (!ELEM(la->type, LA_LOCAL, LA_SUN, LA_SPOT, LA_AREA)) { - la->type = LA_SUN; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "light_threshold")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->eevee.light_threshold = 0.01f; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_irradiance_smoothing")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->eevee.gi_irradiance_smoothing = 0.1f; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_filter_quality")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->eevee.gi_filter_quality = 1.0f; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "att_dist")) { - for (Light *la = bmain->lights.first; la; la = la->id.next) { - la->att_dist = la->clipend; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "Brush", "char", "weightpaint_tool")) { - /* Magic defines from old files (2.7x) */ + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 15)) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->display.matcap_ssao_distance = 0.2f; + scene->display.matcap_ssao_attenuation = 1.0f; + scene->display.matcap_ssao_samples = 16; + } + + for (bScreen* screen = bmain->screens.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_OUTLINER) { + SpaceOutliner* soops = (SpaceOutliner*)sl; + soops->filter_id_type = ID_GR; + soops->outlinevis = SO_VIEW_LAYER; + } + } + } + } + + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + switch (scene->toolsettings->snap_mode) { + case 0: + scene->toolsettings->snap_mode = SCE_SNAP_MODE_INCREMENT; + break; + case 1: + scene->toolsettings->snap_mode = SCE_SNAP_MODE_VERTEX; + break; + case 2: + scene->toolsettings->snap_mode = SCE_SNAP_MODE_EDGE; + break; + case 3: + scene->toolsettings->snap_mode = SCE_SNAP_MODE_FACE; + break; + case 4: + scene->toolsettings->snap_mode = SCE_SNAP_MODE_VOLUME; + break; + } + switch (scene->toolsettings->snap_node_mode) { + case 5: + scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X; + break; + case 6: + scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_Y; + break; + case 7: + scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_NODE_X | SCE_SNAP_MODE_NODE_Y; + break; + case 8: + scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; + break; + } + switch (scene->toolsettings->snap_uv_mode) { + case 0: + scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_INCREMENT; + break; + case 1: + scene->toolsettings->snap_uv_mode = SCE_SNAP_MODE_VERTEX; + break; + } + } + + ParticleSettings* part; + for (part = bmain->particles.first; part; part = part->id.next) { + part->shape_flag = PART_SHAPE_CLOSE_TIP; + part->shape = 0.0f; + part->rad_root = 1.0f; + part->rad_tip = 0.0f; + part->rad_scale = 0.01f; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 18)) { + if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "roughness")) { + for (Material* mat = bmain->materials.first; mat; mat = mat->id.next) { + if (mat->use_nodes) { + if (MAIN_VERSION_ATLEAST(bmain, 280, 0)) { + mat->roughness = mat->gloss_mir; + } + else { + mat->roughness = 0.25f; + } + } + else { + mat->roughness = 1.0f - mat->gloss_mir; + } + mat->metallic = mat->ray_mirror; + } + + for (bScreen* screen = bmain->screens.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.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT; + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha")) { + for (bScreen* screen = bmain->screens.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.xray_alpha = 0.5f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "matcap[256]")) { + StudioLight* default_matcap = BKE_studiolight_find_default(STUDIOLIGHT_TYPE_MATCAP); + /* when loading the internal file is loaded before the matcaps */ + if (default_matcap) { + for (bScreen* screen = bmain->screens.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; + BLI_strncpy(v3d->shading.matcap, default_matcap->name, FILE_MAXFILE); + } + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "wireframe_threshold")) { + for (bScreen* screen = bmain->screens.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.wireframe_threshold = 0.5f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "cavity_valley_factor")) { + for (bScreen* screen = bmain->screens.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.cavity_valley_factor = 1.0f; + v3d->shading.cavity_ridge_factor = 1.0f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "xray_alpha_bone")) { + for (bScreen* screen = bmain->screens.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.xray_alpha_bone = 0.5f; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 19)) { + if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "renderslot")) { + for (Image* ima = bmain->images.first; ima; ima = ima->id.next) { + if (ima->type == IMA_TYPE_R_RESULT) { + for (int i = 0; i < 8; i++) { + RenderSlot* slot = MEM_callocN(sizeof(RenderSlot), "Image Render Slot Init"); + BLI_snprintf(slot->name, sizeof(slot->name), "Slot %d", i + 1); + BLI_addtail(&ima->renderslots, slot); + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "SpaceAction", "char", "mode_prev")) { + for (bScreen* screen = bmain->screens.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_ACTION) { + SpaceAction* saction = (SpaceAction*)sl; + /* "Dopesheet" should be default here, + * unless it looks like the Action Editor was active instead. */ + if ((saction->mode_prev == 0) && (saction->action == NULL)) { + saction->mode_prev = SACTCONT_DOPESHEET; + } + } + } + } + } + } + + for (bScreen* screen = bmain->screens.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; + if (v3d->drawtype == OB_TEXTURE) { + v3d->drawtype = OB_SOLID; + v3d->shading.light = V3D_LIGHTING_STUDIO; + v3d->shading.color_type = V3D_SHADING_TEXTURE_COLOR; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 21)) { + for (Scene* sce = bmain->scenes.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); + } + } + + if (!DNA_struct_elem_find( + fd->filesdna, "View3DOverlay", "float", "texture_paint_mode_opacity")) { + for (bScreen* screen = bmain->screens.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) { + enum { + V3D_SHOW_MODE_SHADE_OVERRIDE = (1 << 15), + }; + View3D* v3d = (View3D*)sl; + float alpha = v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE ? 0.0f : 1.0f; + v3d->overlay.texture_paint_mode_opacity = alpha; + v3d->overlay.vertex_paint_mode_opacity = alpha; + v3d->overlay.weight_paint_mode_opacity = alpha; + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "background_type")) { + for (bScreen* screen = bmain->screens.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; + 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->scenes.first; scene; scene = scene->id.next) { + scene->eevee.gi_irradiance_draw_size = 0.1f; + scene->eevee.gi_cubemap_draw_size = 0.3f; + } + } + + if (!DNA_struct_elem_find( + fd->filesdna, "RigidBodyWorld", "RigidBodyWorld_Shared", "*shared")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + RigidBodyWorld* rbw = scene->rigidbody_world; + + if (rbw == NULL) { + continue; + } + + if (rbw->shared == NULL) { + rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared"); + } + + /* Move shared pointers from deprecated location to current location */ + rbw->shared->pointcache = rbw->pointcache; + rbw->shared->ptcaches = rbw->ptcaches; + + rbw->pointcache = NULL; + BLI_listbase_clear(&rbw->ptcaches); + + if (rbw->shared->pointcache == NULL) { + rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches)); + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "SoftBody", "SoftBody_Shared", "*shared")) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + SoftBody* sb = ob->soft; + if (sb == NULL) { + continue; + } + if (sb->shared == NULL) { + sb->shared = MEM_callocN(sizeof(*sb->shared), "SoftBody_Shared"); + } + + /* Move shared pointers from deprecated location to current location */ + sb->shared->pointcache = sb->pointcache; + sb->shared->ptcaches = sb->ptcaches; + + sb->pointcache = NULL; + BLI_listbase_clear(&sb->ptcaches); + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "short", "type")) { + for (bScreen* screen = bmain->screens.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; + if (v3d->drawtype == OB_RENDER) { + v3d->drawtype = OB_SOLID; + } + v3d->shading.type = v3d->drawtype; + v3d->shading.prev_type = OB_SOLID; + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "View3DShading", "shading")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + 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->screens.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->gp_flag |= 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->scenes.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->gpencils.first; gpd; gpd = gpd->id.next) { + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + 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_paper_opacity")) { + for (bScreen* screen = bmain->screens.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->screens.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; + } + } + } + } + } + + /* default loc axis */ + if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "lock_axis")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + /* lock axis */ + GP_Sculpt_Settings* gset = &scene->toolsettings->gp_sculpt; + if (gset) { + gset->lock_axis = GP_LOCKAXIS_Y; + } + } + } + + /* Versioning code for Subsurf modifier. */ + if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "uv_smooth")) { + for (Object* object = bmain->objects.first; object != NULL; object = object->id.next) { + for (ModifierData* md = object->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Subsurf) { + SubsurfModifierData* smd = (SubsurfModifierData*)md; + if (smd->flags & eSubsurfModifierFlag_SubsurfUv_DEPRECATED) { + smd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + } + else { + smd->uv_smooth = SUBSURF_UV_SMOOTH_NONE; + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "SubsurfModifier", "short", "quality")) { + for (Object* object = bmain->objects.first; object != NULL; object = object->id.next) { + for (ModifierData* md = object->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Subsurf) { + SubsurfModifierData* smd = (SubsurfModifierData*)md; + smd->quality = min_ii(smd->renderLevels, 3); + } + } + } + } + /* Versioning code for Multires modifier. */ + if (!DNA_struct_elem_find(fd->filesdna, "MultiresModifier", "short", "quality")) { + for (Object* object = bmain->objects.first; object != NULL; object = object->id.next) { + for (ModifierData* md = object->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Multires) { + MultiresModifierData* mmd = (MultiresModifierData*)md; + mmd->quality = 3; + if (mmd->flags & eMultiresModifierFlag_PlainUv_DEPRECATED) { + mmd->uv_smooth = SUBSURF_UV_SMOOTH_NONE; + } + else { + mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "short", "bending_model")) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + ClothModifierData* clmd = NULL; + if (md->type == eModifierType_Cloth) { + clmd = (ClothModifierData*)md; + } + else if (md->type == eModifierType_ParticleSystem) { + ParticleSystemModifierData* psmd = (ParticleSystemModifierData*)md; + ParticleSystem* psys = psmd->psys; + clmd = psys->clmd; + } + if (clmd != NULL) { + clmd->sim_parms->bending_model = CLOTH_BENDING_LINEAR; + clmd->sim_parms->tension = clmd->sim_parms->structural; + clmd->sim_parms->compression = clmd->sim_parms->structural; + clmd->sim_parms->shear = clmd->sim_parms->structural; + clmd->sim_parms->max_tension = clmd->sim_parms->max_struct; + clmd->sim_parms->max_compression = clmd->sim_parms->max_struct; + clmd->sim_parms->max_shear = clmd->sim_parms->max_struct; + clmd->sim_parms->vgroup_shear = clmd->sim_parms->vgroup_struct; + clmd->sim_parms->tension_damp = clmd->sim_parms->Cdis; + clmd->sim_parms->compression_damp = clmd->sim_parms->Cdis; + clmd->sim_parms->shear_damp = clmd->sim_parms->Cdis; + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "era_strength_f")) { + for (Brush* brush = bmain->brushes.first; brush; brush = brush->id.next) { + if (brush->gpencil_settings != NULL) { + BrushGpencilSettings* gp = brush->gpencil_settings; + if (gp->brush_type == GPAINT_TOOL_ERASE) { + gp->era_strength_f = 100.0f; + gp->era_thickness_f = 10.0f; + } + } + } + } + + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Cloth) { + ClothModifierData* clmd = (ClothModifierData*)md; + + if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL)) { + clmd->sim_parms->vgroup_mass = 0; + } + + if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SCALING)) { + clmd->sim_parms->vgroup_struct = 0; + clmd->sim_parms->vgroup_shear = 0; + clmd->sim_parms->vgroup_bend = 0; + } + + if (!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW)) { + clmd->sim_parms->shrink_min = 0.0f; + clmd->sim_parms->vgroup_shrink = 0; + } + + if (!(clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED)) { + clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF; + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 24)) { + for (bScreen* screen = bmain->screens.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.edit_flag |= V3D_OVERLAY_EDIT_FACES | V3D_OVERLAY_EDIT_SEAMS | + V3D_OVERLAY_EDIT_SHARP | V3D_OVERLAY_EDIT_FREESTYLE_EDGE | + V3D_OVERLAY_EDIT_FREESTYLE_FACE | V3D_OVERLAY_EDIT_EDGES | + V3D_OVERLAY_EDIT_CREASES | V3D_OVERLAY_EDIT_BWEIGHTS | + V3D_OVERLAY_EDIT_CU_HANDLES | V3D_OVERLAY_EDIT_CU_NORMALS; + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "ShrinkwrapModifierData", "char", "shrinkMode")) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Shrinkwrap) { + ShrinkwrapModifierData* smd = (ShrinkwrapModifierData*)md; + if (smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) { + smd->shrinkMode = MOD_SHRINKWRAP_ABOVE_SURFACE; + smd->shrinkOpts &= ~MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE; + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "PartDeflect", "float", "pdef_cfrict")) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + if (ob->pd) { + ob->pd->pdef_cfrict = 5.0f; + } + + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Cloth) { + ClothModifierData* clmd = (ClothModifierData*)md; + + clmd->coll_parms->selfepsilon = 0.015f; + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "xray_alpha_wire")) { + for (bScreen* screen = bmain->screens.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.flag |= V3D_SHADING_XRAY_WIREFRAME; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 25)) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + UnitSettings* unit = &scene->unit; + if (unit->system != USER_UNIT_NONE) { + unit->length_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_LENGTH); + unit->mass_unit = bUnit_GetBaseUnitOfType(scene->unit.system, B_UNIT_MASS); + } + unit->time_unit = bUnit_GetBaseUnitOfType(USER_UNIT_NONE, B_UNIT_TIME); + } + + /* gpencil grid settings */ + for (bGPdata* gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + ARRAY_SET_ITEMS(gpd->grid.color, 0.5f, 0.5f, 0.5f); // Color + ARRAY_SET_ITEMS(gpd->grid.scale, 1.0f, 1.0f); // Scale + gpd->grid.lines = GP_DEFAULT_GRID_LINES; // Number of lines + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 28)) { + for (Mesh* mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) { + BKE_mesh_calc_edges_loose(mesh); + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 29)) { + for (bScreen* screen = bmain->screens.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) { + enum { V3D_OCCLUDE_WIRE = (1 << 14) }; + View3D* v3d = (View3D*)sl; + if (v3d->flag2 & V3D_OCCLUDE_WIRE) { + v3d->overlay.edit_flag |= V3D_OVERLAY_EDIT_OCCLUDE_WIRE; + v3d->flag2 &= ~V3D_OCCLUDE_WIRE; + } + } + } + } + } + + /* Files stored pre 2.5 (possibly re-saved with newer versions) may have non-visible + * spaces without a header (visible/active ones are properly versioned). + * Multiple version patches below assume there's always a header though. So inserting this + * patch in-between older ones to add a header when needed. + * + * From here on it should be fine to assume there always is a header. + */ + if (!MAIN_VERSION_ATLEAST(bmain, 283, 1)) { + for (bScreen* screen = bmain->screens.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) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion* ar_header = do_versions_find_region_or_null(regionbase, RGN_TYPE_HEADER); + + if (!ar_header) { + /* Headers should always be first in the region list, except if there's also a + * tool-header. These were only introduced in later versions though, so should be + * fine to always insert headers first. */ + BLI_assert(!do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)); + + ARegion* ar = do_versions_add_region(RGN_TYPE_HEADER, "header 2.83.1 versioning"); + ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + BLI_addhead(regionbase, ar); + } + } + } + } + } + + for (bScreen* screen = bmain->screens.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_PROPERTIES) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion* ar = MEM_callocN(sizeof(ARegion), "navigation bar for properties"); + ARegion* ar_header = NULL; + + for (ar_header = regionbase->first; ar_header; ar_header = ar_header->next) { + if (ar_header->regiontype == RGN_TYPE_HEADER) { + break; + } + } + BLI_assert(ar_header); + + BLI_insertlinkafter(regionbase, ar_header, ar); + + ar->regiontype = RGN_TYPE_NAV_BAR; + ar->alignment = RGN_ALIGN_LEFT; + } + } + } + } + + /* grease pencil fade layer opacity */ + if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "gpencil_fade_layer")) { + for (bScreen* screen = bmain->screens.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_fade_layer = 0.5f; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 30)) { + /* grease pencil main material show switches */ + for (Material* mat = bmain->materials.first; mat; mat = mat->id.next) { + if (mat->gp_style) { + mat->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + mat->gp_style->flag |= GP_MATERIAL_FILL_SHOW; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 33)) { + + if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "overscan")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->eevee.overscan = 3.0f; + } + } + + for (Light* la = bmain->lights.first; la; la = la->id.next) { + /* Removed Hemi lights. */ + if (!ELEM(la->type, LA_LOCAL, LA_SUN, LA_SPOT, LA_AREA)) { + la->type = LA_SUN; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "light_threshold")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->eevee.light_threshold = 0.01f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_irradiance_smoothing")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->eevee.gi_irradiance_smoothing = 0.1f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "gi_filter_quality")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->eevee.gi_filter_quality = 1.0f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "att_dist")) { + for (Light* la = bmain->lights.first; la; la = la->id.next) { + la->att_dist = la->clipend; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "Brush", "char", "weightpaint_tool")) { + /* Magic defines from old files (2.7x) */ #define PAINT_BLEND_MIX 0 #define PAINT_BLEND_ADD 1 @@ -3015,98 +3017,98 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) #define PAINT_BLEND_ALPHA_SUB 19 #define PAINT_BLEND_ALPHA_ADD 20 - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->ob_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { - const char tool_init = brush->vertexpaint_tool; - bool is_blend = false; - - { - char tool = tool_init; - switch (tool_init) { - case PAINT_BLEND_MIX: - tool = VPAINT_TOOL_DRAW; - break; - case PAINT_BLEND_BLUR: - tool = VPAINT_TOOL_BLUR; - break; - case PAINT_BLEND_AVERAGE: - tool = VPAINT_TOOL_AVERAGE; - break; - case PAINT_BLEND_SMEAR: - tool = VPAINT_TOOL_SMEAR; - break; - default: - tool = VPAINT_TOOL_DRAW; - is_blend = true; - break; - } - brush->vertexpaint_tool = tool; - } - - if (is_blend == false) { - brush->blend = IMB_BLEND_MIX; - } - else { - short blend = IMB_BLEND_MIX; - switch (tool_init) { - case PAINT_BLEND_ADD: - blend = IMB_BLEND_ADD; - break; - case PAINT_BLEND_SUB: - blend = IMB_BLEND_SUB; - break; - case PAINT_BLEND_MUL: - blend = IMB_BLEND_MUL; - break; - case PAINT_BLEND_LIGHTEN: - blend = IMB_BLEND_LIGHTEN; - break; - case PAINT_BLEND_DARKEN: - blend = IMB_BLEND_DARKEN; - break; - case PAINT_BLEND_COLORDODGE: - blend = IMB_BLEND_COLORDODGE; - break; - case PAINT_BLEND_DIFFERENCE: - blend = IMB_BLEND_DIFFERENCE; - break; - case PAINT_BLEND_SCREEN: - blend = IMB_BLEND_SCREEN; - break; - case PAINT_BLEND_HARDLIGHT: - blend = IMB_BLEND_HARDLIGHT; - break; - case PAINT_BLEND_OVERLAY: - blend = IMB_BLEND_OVERLAY; - break; - case PAINT_BLEND_SOFTLIGHT: - blend = IMB_BLEND_SOFTLIGHT; - break; - case PAINT_BLEND_EXCLUSION: - blend = IMB_BLEND_EXCLUSION; - break; - case PAINT_BLEND_LUMINOSITY: - blend = IMB_BLEND_LUMINOSITY; - break; - case PAINT_BLEND_SATURATION: - blend = IMB_BLEND_SATURATION; - break; - case PAINT_BLEND_HUE: - blend = IMB_BLEND_HUE; - break; - case PAINT_BLEND_ALPHA_SUB: - blend = IMB_BLEND_ERASE_ALPHA; - break; - case PAINT_BLEND_ALPHA_ADD: - blend = IMB_BLEND_ADD_ALPHA; - break; - } - brush->blend = blend; - } - } - /* For now these match, in the future new items may not. */ - brush->weightpaint_tool = brush->vertexpaint_tool; - } + for (Brush* brush = bmain->brushes.first; brush; brush = brush->id.next) { + if (brush->ob_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { + const char tool_init = brush->vertexpaint_tool; + bool is_blend = false; + + { + char tool = tool_init; + switch (tool_init) { + case PAINT_BLEND_MIX: + tool = VPAINT_TOOL_DRAW; + break; + case PAINT_BLEND_BLUR: + tool = VPAINT_TOOL_BLUR; + break; + case PAINT_BLEND_AVERAGE: + tool = VPAINT_TOOL_AVERAGE; + break; + case PAINT_BLEND_SMEAR: + tool = VPAINT_TOOL_SMEAR; + break; + default: + tool = VPAINT_TOOL_DRAW; + is_blend = true; + break; + } + brush->vertexpaint_tool = tool; + } + + if (is_blend == false) { + brush->blend = IMB_BLEND_MIX; + } + else { + short blend = IMB_BLEND_MIX; + switch (tool_init) { + case PAINT_BLEND_ADD: + blend = IMB_BLEND_ADD; + break; + case PAINT_BLEND_SUB: + blend = IMB_BLEND_SUB; + break; + case PAINT_BLEND_MUL: + blend = IMB_BLEND_MUL; + break; + case PAINT_BLEND_LIGHTEN: + blend = IMB_BLEND_LIGHTEN; + break; + case PAINT_BLEND_DARKEN: + blend = IMB_BLEND_DARKEN; + break; + case PAINT_BLEND_COLORDODGE: + blend = IMB_BLEND_COLORDODGE; + break; + case PAINT_BLEND_DIFFERENCE: + blend = IMB_BLEND_DIFFERENCE; + break; + case PAINT_BLEND_SCREEN: + blend = IMB_BLEND_SCREEN; + break; + case PAINT_BLEND_HARDLIGHT: + blend = IMB_BLEND_HARDLIGHT; + break; + case PAINT_BLEND_OVERLAY: + blend = IMB_BLEND_OVERLAY; + break; + case PAINT_BLEND_SOFTLIGHT: + blend = IMB_BLEND_SOFTLIGHT; + break; + case PAINT_BLEND_EXCLUSION: + blend = IMB_BLEND_EXCLUSION; + break; + case PAINT_BLEND_LUMINOSITY: + blend = IMB_BLEND_LUMINOSITY; + break; + case PAINT_BLEND_SATURATION: + blend = IMB_BLEND_SATURATION; + break; + case PAINT_BLEND_HUE: + blend = IMB_BLEND_HUE; + break; + case PAINT_BLEND_ALPHA_SUB: + blend = IMB_BLEND_ERASE_ALPHA; + break; + case PAINT_BLEND_ALPHA_ADD: + blend = IMB_BLEND_ADD_ALPHA; + break; + } + brush->blend = blend; + } + } + /* For now these match, in the future new items may not. */ + brush->weightpaint_tool = brush->vertexpaint_tool; + } #undef PAINT_BLEND_MIX #undef PAINT_BLEND_ADD @@ -3129,1344 +3131,1468 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) #undef PAINT_BLEND_HUE #undef PAINT_BLEND_ALPHA_SUB #undef PAINT_BLEND_ALPHA_ADD - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 34)) { - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *area = screen->areabase.first; area; area = area->next) { - for (SpaceLink *slink = area->spacedata.first; slink; slink = slink->next) { - if (slink->spacetype == SPACE_USERPREF) { - ARegion *navigation_region = BKE_spacedata_find_region_type( - slink, area, RGN_TYPE_NAV_BAR); - - if (!navigation_region) { - ARegion *main_region = BKE_spacedata_find_region_type(slink, area, RGN_TYPE_WINDOW); - ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase : - &slink->regionbase; - - navigation_region = MEM_callocN(sizeof(ARegion), - "userpref navigation-region do_versions"); - - /* Order matters, addhead not addtail! */ - BLI_insertlinkbefore(regionbase, main_region, navigation_region); - - navigation_region->regiontype = RGN_TYPE_NAV_BAR; - navigation_region->alignment = RGN_ALIGN_LEFT; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 36)) { - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "curvature_ridge_factor")) { - for (bScreen *screen = bmain->screens.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.curvature_ridge_factor = 1.0f; - v3d->shading.curvature_valley_factor = 1.0f; - } - } - } - } - } - - /* Rename OpenGL to Workbench. */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (STREQ(scene->r.engine, "BLENDER_OPENGL")) { - STRNCPY(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH); - } - } - - /* init Annotations onion skin */ - if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "int", "gstep")) { - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f); - ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f); - } - } - } - - /* Move studio_light selection to lookdev_light. */ - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "lookdev_light[256]")) { - for (bScreen *screen = bmain->screens.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; - memcpy(v3d->shading.lookdev_light, v3d->shading.studio_light, sizeof(char) * 256); - } - } - } - } - } - - /* Change Solid mode shadow orientation. */ - if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_focus")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - float *dir = scene->display.light_direction; - SWAP(float, dir[2], dir[1]); - dir[2] = -dir[2]; - dir[0] = -dir[0]; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 37)) { - for (Camera *ca = bmain->cameras.first; ca; ca = ca->id.next) { - ca->drawsize *= 2.0f; - } - - /* Grease pencil primitive curve */ - if (!DNA_struct_elem_find( - fd->filesdna, "GP_Sculpt_Settings", "CurveMapping", "cur_primitive")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt; - if ((gset) && (gset->cur_primitive == NULL)) { - gset->cur_primitive = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); - BKE_curvemapping_initialize(gset->cur_primitive); - BKE_curvemap_reset(gset->cur_primitive->cm, - &gset->cur_primitive->clipr, - CURVE_PRESET_BELL, - CURVEMAP_SLOPE_POSITIVE); - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 38)) { - if (DNA_struct_elem_find(fd->filesdna, "Object", "char", "empty_image_visibility_flag")) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - ob->empty_image_visibility_flag ^= (OB_EMPTY_IMAGE_HIDE_PERSPECTIVE | - OB_EMPTY_IMAGE_HIDE_ORTHOGRAPHIC | - OB_EMPTY_IMAGE_HIDE_BACK); - } - } - - for (bScreen *screen = bmain->screens.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) { - switch (sl->spacetype) { - case SPACE_IMAGE: { - SpaceImage *sima = (SpaceImage *)sl; - sima->flag &= ~(SI_FLAG_UNUSED_0 | SI_FLAG_UNUSED_1 | SI_FLAG_UNUSED_3 | - SI_FLAG_UNUSED_6 | SI_FLAG_UNUSED_7 | SI_FLAG_UNUSED_8 | - SI_FLAG_UNUSED_17 | SI_FLAG_UNUSED_18 | SI_FLAG_UNUSED_23 | - SI_FLAG_UNUSED_24); - break; - } - case SPACE_VIEW3D: { - View3D *v3d = (View3D *)sl; - v3d->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 | - V3D_FLAG_UNUSED_12); - v3d->flag2 &= ~(V3D_FLAG2_UNUSED_3 | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 | - V3D_FLAG2_UNUSED_13 | V3D_FLAG2_UNUSED_14 | V3D_FLAG2_UNUSED_15); - break; - } - case SPACE_OUTLINER: { - SpaceOutliner *so = (SpaceOutliner *)sl; - so->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_UNUSED_5 | SO_FILTER_UNUSED_12); - so->storeflag &= ~(SO_TREESTORE_UNUSED_1); - break; - } - case SPACE_FILE: { - SpaceFile *sfile = (SpaceFile *)sl; - if (sfile->params) { - sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_6 | - FILE_PARAMS_FLAG_UNUSED_9); - } - break; - } - case SPACE_NODE: { - SpaceNode *snode = (SpaceNode *)sl; - snode->flag &= ~(SNODE_FLAG_UNUSED_6 | SNODE_FLAG_UNUSED_10 | SNODE_FLAG_UNUSED_11); - break; - } - case SPACE_PROPERTIES: { - SpaceProperties *sbuts = (SpaceProperties *)sl; - sbuts->flag &= ~(SB_FLAG_UNUSED_2 | SB_FLAG_UNUSED_3); - break; - } - case SPACE_NLA: { - SpaceNla *snla = (SpaceNla *)sl; - snla->flag &= ~(SNLA_FLAG_UNUSED_0 | SNLA_FLAG_UNUSED_1 | SNLA_FLAG_UNUSED_3); - break; - } - } - } - } - } - - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->r.mode &= ~(R_MODE_UNUSED_1 | R_MODE_UNUSED_2 | R_MODE_UNUSED_3 | R_MODE_UNUSED_4 | - R_MODE_UNUSED_5 | R_MODE_UNUSED_6 | R_MODE_UNUSED_7 | R_MODE_UNUSED_8 | - R_MODE_UNUSED_10 | R_MODE_UNUSED_13 | R_MODE_UNUSED_16 | - R_MODE_UNUSED_17 | R_MODE_UNUSED_18 | R_MODE_UNUSED_19 | - R_MODE_UNUSED_20 | R_MODE_UNUSED_21 | R_MODE_UNUSED_27); - - scene->r.scemode &= ~(R_SCEMODE_UNUSED_8 | R_SCEMODE_UNUSED_11 | R_SCEMODE_UNUSED_13 | - R_SCEMODE_UNUSED_16 | R_SCEMODE_UNUSED_17 | R_SCEMODE_UNUSED_19); - - if (scene->toolsettings->sculpt) { - scene->toolsettings->sculpt->flags &= ~(SCULPT_FLAG_UNUSED_0 | SCULPT_FLAG_UNUSED_1 | - SCULPT_FLAG_UNUSED_2); - } - - if (scene->ed) { - Sequence *seq; - SEQ_BEGIN (scene->ed, seq) { - seq->flag &= ~(SEQ_FLAG_UNUSED_6 | SEQ_FLAG_UNUSED_18 | SEQ_FLAG_UNUSED_19 | - SEQ_FLAG_UNUSED_21); - if (seq->type == SEQ_TYPE_SPEED) { - SpeedControlVars *s = (SpeedControlVars *)seq->effectdata; - s->flags &= ~(SEQ_SPEED_UNUSED_1); - } - } - SEQ_END; - } - } - - for (World *world = bmain->worlds.first; world; world = world->id.next) { - world->flag &= ~(WO_MODE_UNUSED_1 | WO_MODE_UNUSED_2 | WO_MODE_UNUSED_3 | WO_MODE_UNUSED_4 | - WO_MODE_UNUSED_5 | WO_MODE_UNUSED_7); - } - - for (Image *image = bmain->images.first; image; image = image->id.next) { - image->flag &= ~(IMA_FLAG_UNUSED_0 | IMA_FLAG_UNUSED_1 | IMA_FLAG_UNUSED_4 | - IMA_FLAG_UNUSED_6 | IMA_FLAG_UNUSED_8 | IMA_FLAG_UNUSED_15 | - IMA_FLAG_UNUSED_16); - } - - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - ob->flag &= ~(OB_FLAG_UNUSED_11 | OB_FLAG_UNUSED_12); - ob->transflag &= ~(OB_TRANSFLAG_UNUSED_0 | OB_TRANSFLAG_UNUSED_1); - ob->shapeflag &= ~OB_SHAPE_FLAG_UNUSED_1; - } - - for (Mesh *me = bmain->meshes.first; me; me = me->id.next) { - me->flag &= ~(ME_FLAG_UNUSED_0 | ME_FLAG_UNUSED_1 | ME_FLAG_UNUSED_3 | ME_FLAG_UNUSED_4 | - ME_FLAG_UNUSED_6 | ME_FLAG_UNUSED_7 | ME_FLAG_UNUSED_8); - } - - for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) { - mat->blend_flag &= ~(1 << 2); /* UNUSED */ - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 40)) { - if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "snap_transform_mode_flag")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->toolsettings->snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE; - } - } - - for (bScreen *screen = bmain->screens.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) { - switch (sl->spacetype) { - case SPACE_VIEW3D: { - enum { V3D_BACKFACE_CULLING = (1 << 10) }; - View3D *v3d = (View3D *)sl; - if (v3d->flag2 & V3D_BACKFACE_CULLING) { - v3d->flag2 &= ~V3D_BACKFACE_CULLING; - v3d->shading.flag |= V3D_SHADING_BACKFACE_CULLING; - } - break; - } - } - } - } - } - - if (!DNA_struct_find(fd->filesdna, "TransformOrientationSlot")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - for (int i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) { - scene->orientation_slots[i].index_custom = -1; - } - } - } - - /* Grease pencil cutter/select segment intersection threshold */ - if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "float", "isect_threshold")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt; - if (gset) { - gset->isect_threshold = 0.1f; - } - } - } - - /* Fix anamorphic bokeh eevee rna limits.*/ - for (Camera *ca = bmain->cameras.first; ca; ca = ca->id.next) { - if (ca->gpu_dof.ratio < 0.01f) { - ca->gpu_dof.ratio = 0.01f; - } - } - - for (bScreen *screen = bmain->screens.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_USERPREF) { - ARegion *execute_region = BKE_spacedata_find_region_type(sl, area, RGN_TYPE_EXECUTE); - - if (!execute_region) { - ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : - &sl->regionbase; - ARegion *ar_navbar = BKE_spacedata_find_region_type(sl, area, RGN_TYPE_NAV_BAR); - - execute_region = MEM_callocN(sizeof(ARegion), "execute region for properties"); - - BLI_assert(ar_navbar); - - BLI_insertlinkafter(regionbase, ar_navbar, execute_region); - - execute_region->regiontype = RGN_TYPE_EXECUTE; - execute_region->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - execute_region->flag |= RGN_FLAG_DYNAMIC_SIZE; - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 43)) { - ListBase *lb = which_libbase(bmain, ID_BR); - BKE_main_id_repair_duplicate_names_listbase(lb); - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 44)) { - if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "a")) { - for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) { - mat->a = 1.0f; - } - } - - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - enum { - R_ALPHAKEY = 2, - }; - scene->r.seq_flag &= ~(R_SEQ_UNUSED_0 | R_SEQ_UNUSED_1 | R_SEQ_UNUSED_2); - scene->r.color_mgt_flag &= ~R_COLOR_MANAGEMENT_UNUSED_1; - if (scene->r.alphamode == R_ALPHAKEY) { - scene->r.alphamode = R_ADDSKY; - } - ToolSettings *ts = scene->toolsettings; - ts->particle.flag &= ~PE_UNUSED_6; - if (ts->sculpt != NULL) { - ts->sculpt->flags &= ~SCULPT_FLAG_UNUSED_6; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 46)) { - /* Add wireframe color. */ - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "wire_color_type")) { - for (bScreen *screen = bmain->screens.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.wire_color_type = V3D_SHADING_SINGLE_COLOR; - } - } - } - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "View3DCursor", "short", "rotation_mode")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (is_zero_v3(scene->cursor.rotation_axis)) { - scene->cursor.rotation_mode = ROT_MODE_XYZ; - scene->cursor.rotation_quaternion[0] = 1.0f; - scene->cursor.rotation_axis[1] = 1.0f; - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 47)) { - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - ParticleEditSettings *pset = &scene->toolsettings->particle; - if (pset->brushtype < 0) { - pset->brushtype = PE_BRUSH_COMB; - } - } - - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - { - enum { PARCURVE = 1, PARKEY = 2, PAR_DEPRECATED = 16 }; - if (ELEM(ob->partype, PARCURVE, PARKEY, PAR_DEPRECATED)) { - ob->partype = PAROBJECT; - } - } - - { - enum { OB_WAVE = 21, OB_LIFE = 23, OB_SECTOR = 24 }; - if (ELEM(ob->type, OB_WAVE, OB_LIFE, OB_SECTOR)) { - ob->type = OB_EMPTY; - } - } - - ob->transflag &= ~(OB_TRANSFLAG_UNUSED_0 | OB_TRANSFLAG_UNUSED_1 | OB_TRANSFLAG_UNUSED_3 | - OB_TRANSFLAG_UNUSED_6 | OB_TRANSFLAG_UNUSED_12); - - ob->nlaflag &= ~(OB_ADS_UNUSED_1 | OB_ADS_UNUSED_2); - } - - LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) { - arm->flag &= ~(ARM_FLAG_UNUSED_1 | ARM_FLAG_UNUSED_5 | ARM_FLAG_UNUSED_6 | - ARM_FLAG_UNUSED_7 | ARM_FLAG_UNUSED_12); - } - - LISTBASE_FOREACH (Text *, text, &bmain->texts) { - text->flags &= ~(TXT_FLAG_UNUSED_8 | TXT_FLAG_UNUSED_9); - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 48)) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - /* Those are not currently used, but are accessible through RNA API and were not - * properly initialized previously. This is mere copy of BKE_init_scene() code. */ - if (scene->r.im_format.view_settings.look[0] == '\0') { - BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings); - BKE_color_managed_view_settings_init_render( - &scene->r.im_format.view_settings, &scene->r.im_format.display_settings, "Filmic"); - } - - if (scene->r.bake.im_format.view_settings.look[0] == '\0') { - BKE_color_managed_display_settings_init(&scene->r.bake.im_format.display_settings); - BKE_color_managed_view_settings_init_render(&scene->r.bake.im_format.view_settings, - &scene->r.bake.im_format.display_settings, - "Filmic"); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 49)) { - /* All tool names changed, reset to defaults. */ - for (WorkSpace *workspace = bmain->workspaces.first; workspace; - workspace = workspace->id.next) { - while (!BLI_listbase_is_empty(&workspace->tools)) { - BKE_workspace_tool_remove(workspace, workspace->tools.first); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 52)) { - LISTBASE_FOREACH (ParticleSettings *, part, &bmain->particles) { - /* Replace deprecated PART_DRAW_BB by PART_DRAW_NOT */ - if (part->ren_as == PART_DRAW_BB) { - part->ren_as = PART_DRAW_NOT; - } - if (part->draw_as == PART_DRAW_BB) { - part->draw_as = PART_DRAW_NOT; - } - } - - if (!DNA_struct_elem_find(fd->filesdna, "TriangulateModifierData", "int", "min_vertices")) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Triangulate) { - TriangulateModifierData *smd = (TriangulateModifierData *)md; - smd->min_vertices = 4; - } - } - } - } - - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ntree->type == NTREE_SHADER) { - for (bNode *node = ntree->nodes.first; node; node = node->next) { - /* Fix missing version patching from earlier changes. */ - if (STREQ(node->idname, "ShaderNodeOutputLamp")) { - STRNCPY(node->idname, "ShaderNodeOutputLight"); - } - if (node->type == SH_NODE_BSDF_PRINCIPLED && node->custom2 == 0) { - node->custom2 = SHD_SUBSURFACE_BURLEY; - } - } - } - } - FOREACH_NODETREE_END; - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 53)) { - for (Material *mat = bmain->materials.first; mat; mat = mat->id.next) { - /* Eevee: Keep material appearance consistent with previous behavior. */ - if (!mat->use_nodes || !mat->nodetree || mat->blend_method == MA_BM_SOLID) { - mat->blend_shadow = MA_BS_SOLID; - } - } - - /* grease pencil default animation channel color */ - { - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - if (gpd->flag & GP_DATA_ANNOTATIONS) { - continue; - } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* default channel color */ - ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f); - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 54)) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - bool is_first_subdiv = true; - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Subsurf) { - SubsurfModifierData *smd = (SubsurfModifierData *)md; - if (is_first_subdiv) { - smd->flags |= eSubsurfModifierFlag_UseCrease; - } - else { - smd->flags &= ~eSubsurfModifierFlag_UseCrease; - } - is_first_subdiv = false; - } - else if (md->type == eModifierType_Multires) { - MultiresModifierData *mmd = (MultiresModifierData *)md; - if (is_first_subdiv) { - mmd->flags |= eMultiresModifierFlag_UseCrease; - } - else { - mmd->flags &= ~eMultiresModifierFlag_UseCrease; - } - is_first_subdiv = false; - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 55)) { - for (bScreen *screen = bmain->screens.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_TEXT) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - - /* Remove multiple footers that were added by mistake. */ - do_versions_remove_regions_by_type(regionbase, RGN_TYPE_FOOTER); - - /* Add footer. */ - ARegion *ar = do_versions_add_region(RGN_TYPE_FOOTER, "footer for text"); - ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; - - ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); - BLI_insertlinkafter(regionbase, ar_header, ar); - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 56)) { - for (bScreen *screen = bmain->screens.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->gizmo_show_armature = V3D_GIZMO_SHOW_ARMATURE_BBONE | - V3D_GIZMO_SHOW_ARMATURE_ROLL; - v3d->gizmo_show_empty = V3D_GIZMO_SHOW_EMPTY_IMAGE | V3D_GIZMO_SHOW_EMPTY_FORCE_FIELD; - v3d->gizmo_show_light = V3D_GIZMO_SHOW_LIGHT_SIZE | V3D_GIZMO_SHOW_LIGHT_LOOK_AT; - v3d->gizmo_show_camera = V3D_GIZMO_SHOW_CAMERA_LENS | V3D_GIZMO_SHOW_CAMERA_DOF_DIST; - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 57)) { - /* Enable Show Interpolation in dopesheet by default. */ - for (bScreen *screen = bmain->screens.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_ACTION) { - SpaceAction *saction = (SpaceAction *)sl; - if ((saction->flag & SACTION_SHOW_EXTREMES) == 0) { - saction->flag |= SACTION_SHOW_INTERPOLATION; - } - } - } - } - } - - /* init grease pencil brush gradients */ - if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "gradient_f")) { - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->gpencil_settings != NULL) { - BrushGpencilSettings *gp = brush->gpencil_settings; - gp->gradient_f = 1.0f; - gp->gradient_s[0] = 1.0f; - gp->gradient_s[1] = 1.0f; - } - } - } - - /* init grease pencil stroke gradients */ - if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "gradient_f")) { - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - 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) { - gps->gradient_f = 1.0f; - gps->gradient_s[0] = 1.0f; - gps->gradient_s[1] = 1.0f; - } - } - } - } - } - - /* enable the axis aligned ortho grid by default */ - for (bScreen *screen = bmain->screens.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->gridflag |= V3D_SHOW_ORTHO_GRID; - } - } - } - } - } - - /* Keep un-versioned until we're finished adding space types. */ - { - for (bScreen *screen = bmain->screens.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) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - /* All spaces that use tools must be eventually added. */ - ARegion *ar = NULL; - if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ) && - ((ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)) == NULL)) { - /* Add tool header. */ - ar = do_versions_add_region(RGN_TYPE_TOOL_HEADER, "tool header"); - ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; - - ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); - BLI_insertlinkbefore(regionbase, ar_header, ar); - /* Hide by default, enable for painting workspaces (startup only). */ - ar->flag |= RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER; - } - if (ar != NULL) { - SET_FLAG_FROM_TEST(ar->flag, ar->flag & RGN_FLAG_HIDDEN_BY_USER, RGN_FLAG_HIDDEN); - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 60)) { - if (!DNA_struct_elem_find(fd->filesdna, "bSplineIKConstraint", "short", "yScaleMode")) { - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->pose) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (bConstraint *con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_SPLINEIK) { - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - if ((data->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) == 0) { - data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; - } - } - } - } - } - } - } - - if (!DNA_struct_elem_find( - fd->filesdna, "View3DOverlay", "float", "sculpt_mode_mask_opacity")) { - for (bScreen *screen = bmain->screens.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.sculpt_mode_mask_opacity = 0.75f; - } - } - } - } - } - if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "char", "render_aa")) { - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - scene->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; - scene->display.viewport_aa = SCE_DISPLAY_AA_FXAA; - } - } - - /* Split bbone_scalein/bbone_scaleout into x and y fields. */ - if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scale_out_y")) { - /* Update armature data and pose channels. */ - LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) { - do_version_bones_split_bbone_scale(&arm->bonebase); - } - - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->pose) { - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { - pchan->scale_in_y = pchan->scale_in_x; - pchan->scale_out_y = pchan->scale_out_x; - } - } - } - - /* Update action curves and drivers. */ - LISTBASE_FOREACH (bAction *, act, &bmain->actions) { - LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &act->curves) { - do_version_bbone_scale_fcurve_fix(&act->curves, fcu); - } - } - - BKE_animdata_main_cb(bmain, do_version_bbone_scale_animdata_cb, NULL); - } - - for (Scene *sce = bmain->scenes.first; sce != NULL; sce = sce->id.next) { - if (sce->ed != NULL) { - do_versions_seq_set_cache_defaults(sce->ed); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 61)) { - /* Added a power option to Copy Scale. */ - if (!DNA_struct_elem_find(fd->filesdna, "bSizeLikeConstraint", "float", "power")) { - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - do_version_constraints_copy_scale_power(&ob->constraints); - if (ob->pose) { - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { - do_version_constraints_copy_scale_power(&pchan->constraints); - } - } - } - } - - for (bScreen *screen = bmain->screens.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 (ELEM(sl->spacetype, SPACE_CLIP, SPACE_GRAPH, SPACE_SEQ)) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - - ARegion *ar = NULL; - if (sl->spacetype == SPACE_CLIP) { - if (((SpaceClip *)sl)->view == SC_VIEW_GRAPH) { - ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_PREVIEW); - } - } - else { - ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_WINDOW); - } - - if (ar != NULL) { - ar->v2d.scroll &= ~V2D_SCROLL_LEFT; - ar->v2d.scroll |= V2D_SCROLL_RIGHT; - } - } - } - } - } - - for (bScreen *screen = bmain->screens.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_OUTLINER) { - continue; - } - SpaceOutliner *so = (SpaceOutliner *)sl; - so->filter &= ~SO_FLAG_UNUSED_1; - so->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE; - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 69)) { - LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) { - arm->flag &= ~(ARM_FLAG_UNUSED_7 | ARM_FLAG_UNUSED_9); - } - - /* Initializes sun lights with the new angular diameter property */ - if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "sun_angle")) { - LISTBASE_FOREACH (Light *, light, &bmain->lights) { - light->sun_angle = 2.0f * atanf(light->area_size); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 70)) { - /* New image alpha modes. */ - LISTBASE_FOREACH (Image *, image, &bmain->images) { - const int IMA_IGNORE_ALPHA = (1 << 12); - if (image->flag & IMA_IGNORE_ALPHA) { - image->alpha_mode = IMA_ALPHA_IGNORE; - image->flag &= ~IMA_IGNORE_ALPHA; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 71)) { - /* This assumes the Blender builtin config. Depending on the OCIO - * environment variable for versioning is weak, and these deprecated view - * transforms and look names don't seem to exist in other commonly used - * OCIO configs so .blend files created for those would be unaffected. */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - ColorManagedViewSettings *view_settings; - view_settings = &scene->view_settings; - - if (STREQ(view_settings->view_transform, "Default")) { - STRNCPY(view_settings->view_transform, "Standard"); - } - else if (STREQ(view_settings->view_transform, "RRT") || - STREQ(view_settings->view_transform, "Film")) { - STRNCPY(view_settings->view_transform, "Filmic"); - } - else if (STREQ(view_settings->view_transform, "Log")) { - STRNCPY(view_settings->view_transform, "Filmic Log"); - } - - if (STREQ(view_settings->look, "Filmic - Base Contrast")) { - STRNCPY(view_settings->look, "None"); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 74)) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->ed != NULL) { - do_versions_seq_alloc_transform_and_crop(&scene->ed->seqbase); - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 280, 75)) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->master_collection != NULL) { - scene->master_collection->flag &= ~(COLLECTION_RESTRICT_VIEWPORT | - COLLECTION_RESTRICT_SELECT | - COLLECTION_RESTRICT_RENDER); - } - - UnitSettings *unit = &scene->unit; - if (unit->system == USER_UNIT_NONE) { - unit->length_unit = (char)USER_UNIT_ADAPTIVE; - unit->mass_unit = (char)USER_UNIT_ADAPTIVE; - } - - RenderData *render_data = &scene->r; - switch (render_data->ffcodecdata.ffmpeg_preset) { - case FFM_PRESET_ULTRAFAST: - case FFM_PRESET_SUPERFAST: - render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_REALTIME; - break; - case FFM_PRESET_VERYFAST: - case FFM_PRESET_FASTER: - case FFM_PRESET_FAST: - case FFM_PRESET_MEDIUM: - render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD; - break; - case FFM_PRESET_SLOW: - case FFM_PRESET_SLOWER: - case FFM_PRESET_VERYSLOW: - render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_BEST; - } - } - - LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) { - arm->flag &= ~(ARM_FLAG_UNUSED_6); - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 1)) { - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_DataTransfer) { - /* Now datatransfer's mix factor is multiplied with weights when any, - * instead of being ignored, - * we need to take care of that to keep 'old' files compatible. */ - DataTransferModifierData *dtmd = (DataTransferModifierData *)md; - if (dtmd->defgrp_name[0] != '\0') { - dtmd->mix_factor = 1.0f; - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) { - for (bScreen *screen = bmain->screens.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_TEXT) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - ARegion *ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_UI); - if (ar) { - ar->alignment = RGN_ALIGN_RIGHT; - } - } - /* Mark outliners as dirty for syncing and enable synced selection */ - if (sl->spacetype == SPACE_OUTLINER) { - SpaceOutliner *soutliner = (SpaceOutliner *)sl; - soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL; - soutliner->flag |= SO_SYNC_SELECT; - } - } - } - } - for (Mesh *mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) { - if (mesh->remesh_voxel_size == 0.0f) { - mesh->remesh_voxel_size = 0.1f; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 4)) { - ID *id; - FOREACH_MAIN_ID_BEGIN (bmain, id) { - bNodeTree *ntree = ntreeFromID(id); - if (ntree) { - ntree->id.flag |= LIB_PRIVATE_DATA; - } - } - FOREACH_MAIN_ID_END; - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 5)) { - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - if (br->ob_mode & OB_MODE_SCULPT && br->normal_radius_factor == 0.0f) { - br->normal_radius_factor = 0.5f; - } - } - - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - /* Older files do not have a master collection, which is then added through - * `BKE_collection_master_add()`, so everything is fine. */ - if (scene->master_collection != NULL) { - scene->master_collection->id.flag |= LIB_PRIVATE_DATA; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 6)) { - for (bScreen *screen = bmain->screens.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.flag |= V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER; - - /* files by default don't have studio lights selected unless interacted - * with the shading popover. When no studiolight could be read, we will - * select the default world one. */ - StudioLight *studio_light = BKE_studiolight_find(v3d->shading.lookdev_light, - STUDIOLIGHT_TYPE_WORLD); - if (studio_light != NULL) { - STRNCPY(v3d->shading.lookdev_light, studio_light->name); - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 9)) { - for (bScreen *screen = bmain->screens.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_FILE) { - SpaceFile *sfile = (SpaceFile *)sl; - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - ARegion *ar_ui = do_versions_find_region(regionbase, RGN_TYPE_UI); - ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); - ARegion *ar_toolprops = do_versions_find_region_or_null(regionbase, - RGN_TYPE_TOOL_PROPS); - - /* Reinsert UI region so that it spawns entire area width */ - BLI_remlink(regionbase, ar_ui); - BLI_insertlinkafter(regionbase, ar_header, ar_ui); - - ar_ui->flag |= RGN_FLAG_DYNAMIC_SIZE; - - if (ar_toolprops && (ar_toolprops->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) { - SpaceType *stype = BKE_spacetype_from_id(sl->spacetype); - - /* Remove empty region at old location. */ - BLI_assert(sfile->op == NULL); - BKE_area_region_free(stype, ar_toolprops); - BLI_freelinkN(regionbase, ar_toolprops); - } - - if (sfile->params) { - sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME; - } - } - } - } - } - - /* Convert the BONE_NO_SCALE flag to inherit_scale_mode enum. */ - if (!DNA_struct_elem_find(fd->filesdna, "Bone", "char", "inherit_scale_mode")) { - LISTBASE_FOREACH (bArmature *, arm, &bmain->armatures) { - do_version_bones_inherit_scale(&arm->bonebase); - } - } - - /* Convert the Offset flag to the mix mode enum. */ - if (!DNA_struct_elem_find(fd->filesdna, "bRotateLikeConstraint", "char", "mix_mode")) { - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - do_version_constraints_copy_rotation_mix_mode(&ob->constraints); - if (ob->pose) { - LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { - do_version_constraints_copy_rotation_mix_mode(&pchan->constraints); - } - } - } - } - - /* Added studiolight intensity */ - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "studiolight_intensity")) { - for (bScreen *screen = bmain->screens.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.studiolight_intensity = 1.0f; - } - } - } - } - } - - /* Elatic deform brush */ - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - if (br->ob_mode & OB_MODE_SCULPT && br->elastic_deform_volume_preservation == 0.0f) { - br->elastic_deform_volume_preservation = 0.5f; - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 281, 15)) { - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - if (scene->toolsettings->snap_node_mode == SCE_SNAP_MODE_NODE_X) { - scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; - } - } - - if (!DNA_struct_elem_find( - fd->filesdna, "LayerCollection", "short", "local_collections_bits")) { - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { - LISTBASE_FOREACH (LayerCollection *, layer_collection, &view_layer->layer_collections) { - do_versions_local_collection_bits_set(layer_collection); - } - } - } - } - - for (bScreen *screen = bmain->screens.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; - - for (ScrArea *sa_other = screen->areabase.first; sa_other; sa_other = sa_other->next) { - for (SpaceLink *sl_other = sa_other->spacedata.first; sl_other; - sl_other = sl_other->next) { - if (sl != sl_other && sl_other->spacetype == SPACE_VIEW3D) { - View3D *v3d_other = (View3D *)sl_other; - - if (v3d->shading.prop == v3d_other->shading.prop) { - v3d_other->shading.prop = NULL; - } - } - } - } - } - else if (sl->spacetype == SPACE_FILE) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - ARegion *ar_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS); - ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); - - if (ar_tools) { - ARegion *ar_next = ar_tools->next; - - /* We temporarily had two tools regions, get rid of the second one. */ - if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) { - do_versions_remove_region(regionbase, ar_next); - } - - BLI_remlink(regionbase, ar_tools); - BLI_insertlinkafter(regionbase, ar_header, ar_tools); - } - else { - ar_tools = do_versions_add_region(RGN_TYPE_TOOLS, "versioning file tools region"); - BLI_insertlinkafter(regionbase, ar_header, ar_tools); - ar_tools->alignment = RGN_ALIGN_LEFT; - } - } - } - } - } - - { - /* Initialize new grease pencil uv scale parameter. */ - if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "uv_scale")) { - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - 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) { - gps->uv_scale = 1.0f; - } - } - } - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 282, 2)) { - do_version_curvemapping_walker(bmain, do_version_curvemapping_flag_extend_extrapolate); - - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - sa->flag &= ~AREA_FLAG_UNUSED_6; - } - } - - /* Add custom curve profile to toolsettings for bevel tool */ - if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "CurveProfile", "custom_profile")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - ToolSettings *ts = scene->toolsettings; - if ((ts) && (ts->custom_bevel_profile_preset == NULL)) { - ts->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE); - } - } - } - - /* Add custom curve profile to bevel modifier */ - if (!DNA_struct_elem_find(fd->filesdna, "BevelModifier", "CurveProfile", "custom_profile")) { - for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { - for (ModifierData *md = object->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Bevel) { - BevelModifierData *bmd = (BevelModifierData *)md; - if (!bmd->custom_profile) { - bmd->custom_profile = BKE_curveprofile_add(PROF_PRESET_LINE); - } - } - } - } - } - - /* Dash Ratio and Dash Samples */ - if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "dash_ratio")) { - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - br->dash_ratio = 1.0f; - br->dash_samples = 20; - } - } - - /* Pose brush smooth iterations */ - if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "pose_smooth_iterations")) { - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - br->pose_smooth_iterations = 4; - } - } - - /* Cloth pressure */ - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData *)md; - - clmd->sim_parms->pressure_factor = 1; - } - } - } - } - - if (!MAIN_VERSION_ATLEAST(bmain, 282, 3)) { - /* Remove Unified pressure/size and pressure/alpha */ - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - ToolSettings *ts = scene->toolsettings; - UnifiedPaintSettings *ups = &ts->unified_paint_settings; - ups->flag &= ~(UNIFIED_PAINT_FLAG_UNUSED_0 | UNIFIED_PAINT_FLAG_UNUSED_1); - } - - /* Set the default render pass in the viewport to Combined. */ - if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "int", "render_pass")) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - scene->display.shading.render_pass = SCE_PASS_COMBINED; - } - - for (bScreen *screen = bmain->screens.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.render_pass = SCE_PASS_COMBINED; - } - } - } - } - } - - /* Make markers region visible by default. */ - for (bScreen *screen = bmain->screens.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) { - switch (sl->spacetype) { - case SPACE_SEQ: { - SpaceSeq *sseq = (SpaceSeq *)sl; - sseq->flag |= SEQ_SHOW_MARKERS; - break; - } - case SPACE_ACTION: { - SpaceAction *saction = (SpaceAction *)sl; - saction->flag |= SACTION_SHOW_MARKERS; - break; - } - case SPACE_GRAPH: { - SpaceGraph *sipo = (SpaceGraph *)sl; - sipo->flag |= SIPO_SHOW_MARKERS; - break; - } - case SPACE_NLA: { - SpaceNla *snla = (SpaceNla *)sl; - snla->flag |= SNLA_SHOW_MARKERS; - break; - } - } - } - } - } - - /* Init new Grease Pencil Paint tools. */ - { - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->gpencil_settings != NULL) { - brush->gpencil_vertex_tool = brush->gpencil_settings->brush_type; - } - } - - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->gpencil_settings != NULL) { - brush->gpencil_sculpt_tool = brush->gpencil_settings->brush_type; - } - } - - for (Brush *brush = bmain->brushes.first; brush; brush = brush->id.next) { - if (brush->gpencil_settings != NULL) { - brush->gpencil_weight_tool = brush->gpencil_settings->brush_type; - } - } - - BKE_paint_toolslots_init_from_main(bmain); - } - - /* Init default Grease Pencil Vertex paint mix factor for Viewport. */ - { - if (!DNA_struct_elem_find( - fd->filesdna, "View3DOverlay", "float", "gpencil_vertex_paint_opacity")) { - for (bScreen *screen = bmain->screens.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_vertex_paint_opacity = 1.0f; - } - } - } - } - } - } - - /* Init default Grease Pencil Vertex paint layer mix factor. */ - { - if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "float", "vertex_paint_opacity")) { - for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - gpl->vertex_paint_opacity = 1.0f; - } - } - } - } - } - - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ - - /* Sequencer Tool region */ - do_versions_area_ensure_tool_region(bmain, SPACE_SEQ, RGN_FLAG_HIDDEN); - - /* Cloth internal springs */ - for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData *)md; - - clmd->sim_parms->internal_tension = 15.0f; - clmd->sim_parms->max_internal_tension = 15.0f; - clmd->sim_parms->internal_compression = 15.0f; - clmd->sim_parms->max_internal_compression = 15.0f; - clmd->sim_parms->internal_spring_max_diversion = M_PI / 4.0f; - } - } - } - - /* Add primary tile to images. */ - if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "tiles")) { - for (Image *ima = bmain->images.first; ima; ima = ima->id.next) { - ImageTile *tile = MEM_callocN(sizeof(ImageTile), "Image Tile"); - tile->ok = 1; - tile->tile_number = 1001; - BLI_addtail(&ima->tiles, tile); - } - } - - /* UDIM Image Editor change. */ - if (!DNA_struct_elem_find(fd->filesdna, "SpaceImage", "int", "tile_grid_shape[2]")) { - for (bScreen *screen = bmain->screens.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_IMAGE) { - SpaceImage *sima = (SpaceImage *)sl; - sima->tile_grid_shape[0] = 1; - sima->tile_grid_shape[1] = 1; - } - } - } - } - } - - /* Brush cursor alpha */ - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - br->add_col[3] = 0.9f; - br->sub_col[3] = 0.9f; - } - - /* Pose brush IK segments. */ - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - if (br->pose_ik_segments == 0) { - br->pose_ik_segments = 1; - } - } - } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 34)) { + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea* area = screen->areabase.first; area; area = area->next) { + for (SpaceLink* slink = area->spacedata.first; slink; slink = slink->next) { + if (slink->spacetype == SPACE_USERPREF) { + ARegion* navigation_region = BKE_spacedata_find_region_type( + slink, area, RGN_TYPE_NAV_BAR); + + if (!navigation_region) { + ARegion* main_region = BKE_spacedata_find_region_type(slink, area, RGN_TYPE_WINDOW); + ListBase* regionbase = (slink == area->spacedata.first) ? &area->regionbase : + &slink->regionbase; + + navigation_region = MEM_callocN(sizeof(ARegion), + "userpref navigation-region do_versions"); + + /* Order matters, addhead not addtail! */ + BLI_insertlinkbefore(regionbase, main_region, navigation_region); + + navigation_region->regiontype = RGN_TYPE_NAV_BAR; + navigation_region->alignment = RGN_ALIGN_LEFT; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 36)) { + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "curvature_ridge_factor")) { + for (bScreen* screen = bmain->screens.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.curvature_ridge_factor = 1.0f; + v3d->shading.curvature_valley_factor = 1.0f; + } + } + } + } + } + + /* Rename OpenGL to Workbench. */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + if (STREQ(scene->r.engine, "BLENDER_OPENGL")) { + STRNCPY(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH); + } + } + + /* init Annotations onion skin */ + if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "int", "gstep")) { + for (bGPdata* gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + ARRAY_SET_ITEMS(gpl->gcolor_prev, 0.302f, 0.851f, 0.302f); + ARRAY_SET_ITEMS(gpl->gcolor_next, 0.250f, 0.1f, 1.0f); + } + } + } + + /* Move studio_light selection to lookdev_light. */ + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "lookdev_light[256]")) { + for (bScreen* screen = bmain->screens.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; + memcpy(v3d->shading.lookdev_light, v3d->shading.studio_light, sizeof(char) * 256); + } + } + } + } + } + + /* Change Solid mode shadow orientation. */ + if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "float", "shadow_focus")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + float* dir = scene->display.light_direction; + SWAP(float, dir[2], dir[1]); + dir[2] = -dir[2]; + dir[0] = -dir[0]; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 37)) { + for (Camera* ca = bmain->cameras.first; ca; ca = ca->id.next) { + ca->drawsize *= 2.0f; + } + + /* Grease pencil primitive curve */ + if (!DNA_struct_elem_find( + fd->filesdna, "GP_Sculpt_Settings", "CurveMapping", "cur_primitive")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + GP_Sculpt_Settings* gset = &scene->toolsettings->gp_sculpt; + if ((gset) && (gset->cur_primitive == NULL)) { + gset->cur_primitive = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + BKE_curvemapping_initialize(gset->cur_primitive); + BKE_curvemap_reset(gset->cur_primitive->cm, + &gset->cur_primitive->clipr, + CURVE_PRESET_BELL, + CURVEMAP_SLOPE_POSITIVE); + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 38)) { + if (DNA_struct_elem_find(fd->filesdna, "Object", "char", "empty_image_visibility_flag")) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + ob->empty_image_visibility_flag ^= (OB_EMPTY_IMAGE_HIDE_PERSPECTIVE | + OB_EMPTY_IMAGE_HIDE_ORTHOGRAPHIC | + OB_EMPTY_IMAGE_HIDE_BACK); + } + } + + for (bScreen* screen = bmain->screens.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) { + switch (sl->spacetype) { + case SPACE_IMAGE: { + SpaceImage* sima = (SpaceImage*)sl; + sima->flag &= ~(SI_FLAG_UNUSED_0 | SI_FLAG_UNUSED_1 | SI_FLAG_UNUSED_3 | + SI_FLAG_UNUSED_6 | SI_FLAG_UNUSED_7 | SI_FLAG_UNUSED_8 | + SI_FLAG_UNUSED_17 | SI_FLAG_UNUSED_18 | SI_FLAG_UNUSED_23 | + SI_FLAG_UNUSED_24); + break; + } + case SPACE_VIEW3D: { + View3D* v3d = (View3D*)sl; + v3d->flag &= ~(V3D_LOCAL_COLLECTIONS | V3D_FLAG_UNUSED_1 | V3D_FLAG_UNUSED_10 | + V3D_FLAG_UNUSED_12); + v3d->flag2 &= ~(V3D_FLAG2_UNUSED_3 | V3D_FLAG2_UNUSED_6 | V3D_FLAG2_UNUSED_12 | + V3D_FLAG2_UNUSED_13 | V3D_FLAG2_UNUSED_14 | V3D_FLAG2_UNUSED_15); + break; + } + case SPACE_OUTLINER: { + SpaceOutliner* so = (SpaceOutliner*)sl; + so->filter &= ~(SO_FILTER_UNUSED_1 | SO_FILTER_UNUSED_5 | SO_FILTER_UNUSED_12); + so->storeflag &= ~(SO_TREESTORE_UNUSED_1); + break; + } + case SPACE_FILE: { + SpaceFile* sfile = (SpaceFile*)sl; + if (sfile->params) { + sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_6 | + FILE_PARAMS_FLAG_UNUSED_9); + } + break; + } + case SPACE_NODE: { + SpaceNode* snode = (SpaceNode*)sl; + snode->flag &= ~(SNODE_FLAG_UNUSED_6 | SNODE_FLAG_UNUSED_10 | SNODE_FLAG_UNUSED_11); + break; + } + case SPACE_PROPERTIES: { + SpaceProperties* sbuts = (SpaceProperties*)sl; + sbuts->flag &= ~(SB_FLAG_UNUSED_2 | SB_FLAG_UNUSED_3); + break; + } + case SPACE_NLA: { + SpaceNla* snla = (SpaceNla*)sl; + snla->flag &= ~(SNLA_FLAG_UNUSED_0 | SNLA_FLAG_UNUSED_1 | SNLA_FLAG_UNUSED_3); + break; + } + } + } + } + } + + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->r.mode &= ~(R_MODE_UNUSED_1 | R_MODE_UNUSED_2 | R_MODE_UNUSED_3 | R_MODE_UNUSED_4 | + R_MODE_UNUSED_5 | R_MODE_UNUSED_6 | R_MODE_UNUSED_7 | R_MODE_UNUSED_8 | + R_MODE_UNUSED_10 | R_MODE_UNUSED_13 | R_MODE_UNUSED_16 | + R_MODE_UNUSED_17 | R_MODE_UNUSED_18 | R_MODE_UNUSED_19 | + R_MODE_UNUSED_20 | R_MODE_UNUSED_21 | R_MODE_UNUSED_27); + + scene->r.scemode &= ~(R_SCEMODE_UNUSED_8 | R_SCEMODE_UNUSED_11 | R_SCEMODE_UNUSED_13 | + R_SCEMODE_UNUSED_16 | R_SCEMODE_UNUSED_17 | R_SCEMODE_UNUSED_19); + + if (scene->toolsettings->sculpt) { + scene->toolsettings->sculpt->flags &= ~(SCULPT_FLAG_UNUSED_0 | SCULPT_FLAG_UNUSED_1 | + SCULPT_FLAG_UNUSED_2); + } + + if (scene->ed) { + Sequence* seq; + SEQ_BEGIN(scene->ed, seq) { + seq->flag &= ~(SEQ_FLAG_UNUSED_6 | SEQ_FLAG_UNUSED_18 | SEQ_FLAG_UNUSED_19 | + SEQ_FLAG_UNUSED_21); + if (seq->type == SEQ_TYPE_SPEED) { + SpeedControlVars* s = (SpeedControlVars*)seq->effectdata; + s->flags &= ~(SEQ_SPEED_UNUSED_1); + } + } + SEQ_END; + } + } + + for (World* world = bmain->worlds.first; world; world = world->id.next) { + world->flag &= ~(WO_MODE_UNUSED_1 | WO_MODE_UNUSED_2 | WO_MODE_UNUSED_3 | WO_MODE_UNUSED_4 | + WO_MODE_UNUSED_5 | WO_MODE_UNUSED_7); + } + + for (Image* image = bmain->images.first; image; image = image->id.next) { + image->flag &= ~(IMA_FLAG_UNUSED_0 | IMA_FLAG_UNUSED_1 | IMA_FLAG_UNUSED_4 | + IMA_FLAG_UNUSED_6 | IMA_FLAG_UNUSED_8 | IMA_FLAG_UNUSED_15 | + IMA_FLAG_UNUSED_16); + } + + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + ob->flag &= ~(OB_FLAG_UNUSED_11 | OB_FLAG_UNUSED_12); + ob->transflag &= ~(OB_TRANSFLAG_UNUSED_0 | OB_TRANSFLAG_UNUSED_1); + ob->shapeflag &= ~OB_SHAPE_FLAG_UNUSED_1; + } + + for (Mesh* me = bmain->meshes.first; me; me = me->id.next) { + me->flag &= ~(ME_FLAG_UNUSED_0 | ME_FLAG_UNUSED_1 | ME_FLAG_UNUSED_3 | ME_FLAG_UNUSED_4 | + ME_FLAG_UNUSED_6 | ME_FLAG_UNUSED_7 | ME_FLAG_UNUSED_8); + } + + for (Material* mat = bmain->materials.first; mat; mat = mat->id.next) { + mat->blend_flag &= ~(1 << 2); /* UNUSED */ + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 40)) { + if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "snap_transform_mode_flag")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->toolsettings->snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE; + } + } + + for (bScreen* screen = bmain->screens.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) { + switch (sl->spacetype) { + case SPACE_VIEW3D: { + enum { V3D_BACKFACE_CULLING = (1 << 10) }; + View3D* v3d = (View3D*)sl; + if (v3d->flag2 & V3D_BACKFACE_CULLING) { + v3d->flag2 &= ~V3D_BACKFACE_CULLING; + v3d->shading.flag |= V3D_SHADING_BACKFACE_CULLING; + } + break; + } + } + } + } + } + + if (!DNA_struct_find(fd->filesdna, "TransformOrientationSlot")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + for (int i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) { + scene->orientation_slots[i].index_custom = -1; + } + } + } + + /* Grease pencil cutter/select segment intersection threshold */ + if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "float", "isect_threshold")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + GP_Sculpt_Settings* gset = &scene->toolsettings->gp_sculpt; + if (gset) { + gset->isect_threshold = 0.1f; + } + } + } + + /* Fix anamorphic bokeh eevee rna limits.*/ + for (Camera* ca = bmain->cameras.first; ca; ca = ca->id.next) { + if (ca->gpu_dof.ratio < 0.01f) { + ca->gpu_dof.ratio = 0.01f; + } + } + + for (bScreen* screen = bmain->screens.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_USERPREF) { + ARegion* execute_region = BKE_spacedata_find_region_type(sl, area, RGN_TYPE_EXECUTE); + + if (!execute_region) { + ListBase* regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + ARegion* ar_navbar = BKE_spacedata_find_region_type(sl, area, RGN_TYPE_NAV_BAR); + + execute_region = MEM_callocN(sizeof(ARegion), "execute region for properties"); + + BLI_assert(ar_navbar); + + BLI_insertlinkafter(regionbase, ar_navbar, execute_region); + + execute_region->regiontype = RGN_TYPE_EXECUTE; + execute_region->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; + execute_region->flag |= RGN_FLAG_DYNAMIC_SIZE; + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 43)) { + ListBase* lb = which_libbase(bmain, ID_BR); + BKE_main_id_repair_duplicate_names_listbase(lb); + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 44)) { + if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "a")) { + for (Material* mat = bmain->materials.first; mat; mat = mat->id.next) { + mat->a = 1.0f; + } + } + + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + enum { + R_ALPHAKEY = 2, + }; + scene->r.seq_flag &= ~(R_SEQ_UNUSED_0 | R_SEQ_UNUSED_1 | R_SEQ_UNUSED_2); + scene->r.color_mgt_flag &= ~R_COLOR_MANAGEMENT_UNUSED_1; + if (scene->r.alphamode == R_ALPHAKEY) { + scene->r.alphamode = R_ADDSKY; + } + ToolSettings* ts = scene->toolsettings; + ts->particle.flag &= ~PE_UNUSED_6; + if (ts->sculpt != NULL) { + ts->sculpt->flags &= ~SCULPT_FLAG_UNUSED_6; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 46)) { + /* Add wireframe color. */ + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "char", "wire_color_type")) { + for (bScreen* screen = bmain->screens.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.wire_color_type = V3D_SHADING_SINGLE_COLOR; + } + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "View3DCursor", "short", "rotation_mode")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + if (is_zero_v3(scene->cursor.rotation_axis)) { + scene->cursor.rotation_mode = ROT_MODE_XYZ; + scene->cursor.rotation_quaternion[0] = 1.0f; + scene->cursor.rotation_axis[1] = 1.0f; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 47)) { + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + ParticleEditSettings* pset = &scene->toolsettings->particle; + if (pset->brushtype < 0) { + pset->brushtype = PE_BRUSH_COMB; + } + } + + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + { + enum { PARCURVE = 1, PARKEY = 2, PAR_DEPRECATED = 16 }; + if (ELEM(ob->partype, PARCURVE, PARKEY, PAR_DEPRECATED)) { + ob->partype = PAROBJECT; + } + } + + { + enum { OB_WAVE = 21, OB_LIFE = 23, OB_SECTOR = 24 }; + if (ELEM(ob->type, OB_WAVE, OB_LIFE, OB_SECTOR)) { + ob->type = OB_EMPTY; + } + } + + ob->transflag &= ~(OB_TRANSFLAG_UNUSED_0 | OB_TRANSFLAG_UNUSED_1 | OB_TRANSFLAG_UNUSED_3 | + OB_TRANSFLAG_UNUSED_6 | OB_TRANSFLAG_UNUSED_12); + + ob->nlaflag &= ~(OB_ADS_UNUSED_1 | OB_ADS_UNUSED_2); + } + + LISTBASE_FOREACH(bArmature*, arm, &bmain->armatures) { + arm->flag &= ~(ARM_FLAG_UNUSED_1 | ARM_FLAG_UNUSED_5 | ARM_FLAG_UNUSED_6 | + ARM_FLAG_UNUSED_7 | ARM_FLAG_UNUSED_12); + } + + LISTBASE_FOREACH(Text*, text, &bmain->texts) { + text->flags &= ~(TXT_FLAG_UNUSED_8 | TXT_FLAG_UNUSED_9); + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 48)) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + /* Those are not currently used, but are accessible through RNA API and were not + * properly initialized previously. This is mere copy of BKE_init_scene() code. */ + if (scene->r.im_format.view_settings.look[0] == '\0') { + BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings); + BKE_color_managed_view_settings_init_render( + &scene->r.im_format.view_settings, &scene->r.im_format.display_settings, "Filmic"); + } + + if (scene->r.bake.im_format.view_settings.look[0] == '\0') { + BKE_color_managed_display_settings_init(&scene->r.bake.im_format.display_settings); + BKE_color_managed_view_settings_init_render(&scene->r.bake.im_format.view_settings, + &scene->r.bake.im_format.display_settings, + "Filmic"); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 49)) { + /* All tool names changed, reset to defaults. */ + for (WorkSpace* workspace = bmain->workspaces.first; workspace; + workspace = workspace->id.next) { + while (!BLI_listbase_is_empty(&workspace->tools)) { + BKE_workspace_tool_remove(workspace, workspace->tools.first); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 52)) { + LISTBASE_FOREACH(ParticleSettings*, part, &bmain->particles) { + /* Replace deprecated PART_DRAW_BB by PART_DRAW_NOT */ + if (part->ren_as == PART_DRAW_BB) { + part->ren_as = PART_DRAW_NOT; + } + if (part->draw_as == PART_DRAW_BB) { + part->draw_as = PART_DRAW_NOT; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "TriangulateModifierData", "int", "min_vertices")) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Triangulate) { + TriangulateModifierData* smd = (TriangulateModifierData*)md; + smd->min_vertices = 4; + } + } + } + } + + FOREACH_NODETREE_BEGIN(bmain, ntree, id) { + if (ntree->type == NTREE_SHADER) { + for (bNode* node = ntree->nodes.first; node; node = node->next) { + /* Fix missing version patching from earlier changes. */ + if (STREQ(node->idname, "ShaderNodeOutputLamp")) { + STRNCPY(node->idname, "ShaderNodeOutputLight"); + } + if (node->type == SH_NODE_BSDF_PRINCIPLED && node->custom2 == 0) { + node->custom2 = SHD_SUBSURFACE_BURLEY; + } + } + } + } + FOREACH_NODETREE_END; + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 53)) { + for (Material* mat = bmain->materials.first; mat; mat = mat->id.next) { + /* Eevee: Keep material appearance consistent with previous behavior. */ + if (!mat->use_nodes || !mat->nodetree || mat->blend_method == MA_BM_SOLID) { + mat->blend_shadow = MA_BS_SOLID; + } + } + + /* grease pencil default animation channel color */ + { + for (bGPdata* gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + if (gpd->flag & GP_DATA_ANNOTATIONS) { + continue; + } + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + /* default channel color */ + ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f); + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 54)) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + bool is_first_subdiv = true; + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Subsurf) { + SubsurfModifierData* smd = (SubsurfModifierData*)md; + if (is_first_subdiv) { + smd->flags |= eSubsurfModifierFlag_UseCrease; + } + else { + smd->flags &= ~eSubsurfModifierFlag_UseCrease; + } + is_first_subdiv = false; + } + else if (md->type == eModifierType_Multires) { + MultiresModifierData* mmd = (MultiresModifierData*)md; + if (is_first_subdiv) { + mmd->flags |= eMultiresModifierFlag_UseCrease; + } + else { + mmd->flags &= ~eMultiresModifierFlag_UseCrease; + } + is_first_subdiv = false; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 55)) { + for (bScreen* screen = bmain->screens.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_TEXT) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + + /* Remove multiple footers that were added by mistake. */ + do_versions_remove_regions_by_type(regionbase, RGN_TYPE_FOOTER); + + /* Add footer. */ + ARegion* ar = do_versions_add_region(RGN_TYPE_FOOTER, "footer for text"); + ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; + + ARegion* ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); + BLI_insertlinkafter(regionbase, ar_header, ar); + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 56)) { + for (bScreen* screen = bmain->screens.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->gizmo_show_armature = V3D_GIZMO_SHOW_ARMATURE_BBONE | + V3D_GIZMO_SHOW_ARMATURE_ROLL; + v3d->gizmo_show_empty = V3D_GIZMO_SHOW_EMPTY_IMAGE | V3D_GIZMO_SHOW_EMPTY_FORCE_FIELD; + v3d->gizmo_show_light = V3D_GIZMO_SHOW_LIGHT_SIZE | V3D_GIZMO_SHOW_LIGHT_LOOK_AT; + v3d->gizmo_show_camera = V3D_GIZMO_SHOW_CAMERA_LENS | V3D_GIZMO_SHOW_CAMERA_DOF_DIST; + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 57)) { + /* Enable Show Interpolation in dopesheet by default. */ + for (bScreen* screen = bmain->screens.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_ACTION) { + SpaceAction* saction = (SpaceAction*)sl; + if ((saction->flag & SACTION_SHOW_EXTREMES) == 0) { + saction->flag |= SACTION_SHOW_INTERPOLATION; + } + } + } + } + } + + /* init grease pencil brush gradients */ + if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "gradient_f")) { + for (Brush* brush = bmain->brushes.first; brush; brush = brush->id.next) { + if (brush->gpencil_settings != NULL) { + BrushGpencilSettings* gp = brush->gpencil_settings; + gp->gradient_f = 1.0f; + gp->gradient_s[0] = 1.0f; + gp->gradient_s[1] = 1.0f; + } + } + } + + /* init grease pencil stroke gradients */ + if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "gradient_f")) { + for (bGPdata* gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + LISTBASE_FOREACH(bGPDframe*, gpf, &gpl->frames) { + LISTBASE_FOREACH(bGPDstroke*, gps, &gpf->strokes) { + gps->gradient_f = 1.0f; + gps->gradient_s[0] = 1.0f; + gps->gradient_s[1] = 1.0f; + } + } + } + } + } + + /* enable the axis aligned ortho grid by default */ + for (bScreen* screen = bmain->screens.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->gridflag |= V3D_SHOW_ORTHO_GRID; + } + } + } + } + } + + /* Keep un-versioned until we're finished adding space types. */ + { + for (bScreen* screen = bmain->screens.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) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + /* All spaces that use tools must be eventually added. */ + ARegion* ar = NULL; + if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ) && + ((ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER)) == NULL)) { + /* Add tool header. */ + ar = do_versions_add_region(RGN_TYPE_TOOL_HEADER, "tool header"); + ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + + ARegion* ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); + BLI_insertlinkbefore(regionbase, ar_header, ar); + /* Hide by default, enable for painting workspaces (startup only). */ + ar->flag |= RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER; + } + if (ar != NULL) { + SET_FLAG_FROM_TEST(ar->flag, ar->flag & RGN_FLAG_HIDDEN_BY_USER, RGN_FLAG_HIDDEN); + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 60)) { + if (!DNA_struct_elem_find(fd->filesdna, "bSplineIKConstraint", "short", "yScaleMode")) { + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + if (ob->pose) { + for (bPoseChannel* pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (bConstraint* con = pchan->constraints.first; con; con = con->next) { + if (con->type == CONSTRAINT_TYPE_SPLINEIK) { + bSplineIKConstraint* data = (bSplineIKConstraint*)con->data; + if ((data->flag & CONSTRAINT_SPLINEIK_SCALE_LIMITED) == 0) { + data->yScaleMode = CONSTRAINT_SPLINEIK_YS_FIT_CURVE; + } + } + } + } + } + } + } + + if (!DNA_struct_elem_find( + fd->filesdna, "View3DOverlay", "float", "sculpt_mode_mask_opacity")) { + for (bScreen* screen = bmain->screens.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.sculpt_mode_mask_opacity = 0.75f; + } + } + } + } + } + if (!DNA_struct_elem_find(fd->filesdna, "SceneDisplay", "char", "render_aa")) { + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + scene->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; + scene->display.viewport_aa = SCE_DISPLAY_AA_FXAA; + } + } + + /* Split bbone_scalein/bbone_scaleout into x and y fields. */ + if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "scale_out_y")) { + /* Update armature data and pose channels. */ + LISTBASE_FOREACH(bArmature*, arm, &bmain->armatures) { + do_version_bones_split_bbone_scale(&arm->bonebase); + } + + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + if (ob->pose) { + LISTBASE_FOREACH(bPoseChannel*, pchan, &ob->pose->chanbase) { + pchan->scale_in_y = pchan->scale_in_x; + pchan->scale_out_y = pchan->scale_out_x; + } + } + } + + /* Update action curves and drivers. */ + LISTBASE_FOREACH(bAction*, act, &bmain->actions) { + LISTBASE_FOREACH_MUTABLE(FCurve*, fcu, &act->curves) { + do_version_bbone_scale_fcurve_fix(&act->curves, fcu); + } + } + + BKE_animdata_main_cb(bmain, do_version_bbone_scale_animdata_cb, NULL); + } + + for (Scene* sce = bmain->scenes.first; sce != NULL; sce = sce->id.next) { + if (sce->ed != NULL) { + do_versions_seq_set_cache_defaults(sce->ed); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 61)) { + /* Added a power option to Copy Scale. */ + if (!DNA_struct_elem_find(fd->filesdna, "bSizeLikeConstraint", "float", "power")) { + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + do_version_constraints_copy_scale_power(&ob->constraints); + if (ob->pose) { + LISTBASE_FOREACH(bPoseChannel*, pchan, &ob->pose->chanbase) { + do_version_constraints_copy_scale_power(&pchan->constraints); + } + } + } + } + + for (bScreen* screen = bmain->screens.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 (ELEM(sl->spacetype, SPACE_CLIP, SPACE_GRAPH, SPACE_SEQ)) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + + ARegion* ar = NULL; + if (sl->spacetype == SPACE_CLIP) { + if (((SpaceClip*)sl)->view == SC_VIEW_GRAPH) { + ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_PREVIEW); + } + } + else { + ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_WINDOW); + } + + if (ar != NULL) { + ar->v2d.scroll &= ~V2D_SCROLL_LEFT; + ar->v2d.scroll |= V2D_SCROLL_RIGHT; + } + } + } + } + } + + for (bScreen* screen = bmain->screens.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_OUTLINER) { + continue; + } + SpaceOutliner* so = (SpaceOutliner*)sl; + so->filter &= ~SO_FLAG_UNUSED_1; + so->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 69)) { + LISTBASE_FOREACH(bArmature*, arm, &bmain->armatures) { + arm->flag &= ~(ARM_FLAG_UNUSED_7 | ARM_FLAG_UNUSED_9); + } + + /* Initializes sun lights with the new angular diameter property */ + if (!DNA_struct_elem_find(fd->filesdna, "Light", "float", "sun_angle")) { + LISTBASE_FOREACH(Light*, light, &bmain->lights) { + light->sun_angle = 2.0f * atanf(light->area_size); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 70)) { + /* New image alpha modes. */ + LISTBASE_FOREACH(Image*, image, &bmain->images) { + const int IMA_IGNORE_ALPHA = (1 << 12); + if (image->flag & IMA_IGNORE_ALPHA) { + image->alpha_mode = IMA_ALPHA_IGNORE; + image->flag &= ~IMA_IGNORE_ALPHA; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 71)) { + /* This assumes the Blender builtin config. Depending on the OCIO + * environment variable for versioning is weak, and these deprecated view + * transforms and look names don't seem to exist in other commonly used + * OCIO configs so .blend files created for those would be unaffected. */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + ColorManagedViewSettings* view_settings; + view_settings = &scene->view_settings; + + if (STREQ(view_settings->view_transform, "Default")) { + STRNCPY(view_settings->view_transform, "Standard"); + } + else if (STREQ(view_settings->view_transform, "RRT") || + STREQ(view_settings->view_transform, "Film")) { + STRNCPY(view_settings->view_transform, "Filmic"); + } + else if (STREQ(view_settings->view_transform, "Log")) { + STRNCPY(view_settings->view_transform, "Filmic Log"); + } + + if (STREQ(view_settings->look, "Filmic - Base Contrast")) { + STRNCPY(view_settings->look, "None"); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 74)) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + if (scene->ed != NULL) { + do_versions_seq_alloc_transform_and_crop(&scene->ed->seqbase); + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 280, 75)) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + if (scene->master_collection != NULL) { + scene->master_collection->flag &= ~(COLLECTION_RESTRICT_VIEWPORT | + COLLECTION_RESTRICT_SELECT | + COLLECTION_RESTRICT_RENDER); + } + + UnitSettings* unit = &scene->unit; + if (unit->system == USER_UNIT_NONE) { + unit->length_unit = (char)USER_UNIT_ADAPTIVE; + unit->mass_unit = (char)USER_UNIT_ADAPTIVE; + } + + RenderData* render_data = &scene->r; + switch (render_data->ffcodecdata.ffmpeg_preset) { + case FFM_PRESET_ULTRAFAST: + case FFM_PRESET_SUPERFAST: + render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_REALTIME; + break; + case FFM_PRESET_VERYFAST: + case FFM_PRESET_FASTER: + case FFM_PRESET_FAST: + case FFM_PRESET_MEDIUM: + render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_GOOD; + break; + case FFM_PRESET_SLOW: + case FFM_PRESET_SLOWER: + case FFM_PRESET_VERYSLOW: + render_data->ffcodecdata.ffmpeg_preset = FFM_PRESET_BEST; + } + } + + LISTBASE_FOREACH(bArmature*, arm, &bmain->armatures) { + arm->flag &= ~(ARM_FLAG_UNUSED_6); + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 1)) { + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_DataTransfer) { + /* Now datatransfer's mix factor is multiplied with weights when any, + * instead of being ignored, + * we need to take care of that to keep 'old' files compatible. */ + DataTransferModifierData* dtmd = (DataTransferModifierData*)md; + if (dtmd->defgrp_name[0] != '\0') { + dtmd->mix_factor = 1.0f; + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) { + for (bScreen* screen = bmain->screens.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_TEXT) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion* ar = do_versions_find_region_or_null(regionbase, RGN_TYPE_UI); + if (ar) { + ar->alignment = RGN_ALIGN_RIGHT; + } + } + /* Mark outliners as dirty for syncing and enable synced selection */ + if (sl->spacetype == SPACE_OUTLINER) { + SpaceOutliner* soutliner = (SpaceOutliner*)sl; + soutliner->sync_select_dirty |= WM_OUTLINER_SYNC_SELECT_FROM_ALL; + soutliner->flag |= SO_SYNC_SELECT; + } + } + } + } + for (Mesh* mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) { + if (mesh->remesh_voxel_size == 0.0f) { + mesh->remesh_voxel_size = 0.1f; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 4)) { + ID* id; + FOREACH_MAIN_ID_BEGIN(bmain, id) { + bNodeTree* ntree = ntreeFromID(id); + if (ntree) { + ntree->id.flag |= LIB_PRIVATE_DATA; + } + } + FOREACH_MAIN_ID_END; + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 5)) { + for (Brush* br = bmain->brushes.first; br; br = br->id.next) { + if (br->ob_mode & OB_MODE_SCULPT && br->normal_radius_factor == 0.0f) { + br->normal_radius_factor = 0.5f; + } + } + + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + /* Older files do not have a master collection, which is then added through + * `BKE_collection_master_add()`, so everything is fine. */ + if (scene->master_collection != NULL) { + scene->master_collection->id.flag |= LIB_PRIVATE_DATA; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 6)) { + for (bScreen* screen = bmain->screens.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.flag |= V3D_SHADING_SCENE_LIGHTS_RENDER | V3D_SHADING_SCENE_WORLD_RENDER; + + /* files by default don't have studio lights selected unless interacted + * with the shading popover. When no studiolight could be read, we will + * select the default world one. */ + StudioLight* studio_light = BKE_studiolight_find(v3d->shading.lookdev_light, + STUDIOLIGHT_TYPE_WORLD); + if (studio_light != NULL) { + STRNCPY(v3d->shading.lookdev_light, studio_light->name); + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 9)) { + for (bScreen* screen = bmain->screens.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_FILE) { + SpaceFile* sfile = (SpaceFile*)sl; + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion* ar_ui = do_versions_find_region(regionbase, RGN_TYPE_UI); + ARegion* ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); + ARegion* ar_toolprops = do_versions_find_region_or_null(regionbase, + RGN_TYPE_TOOL_PROPS); + + /* Reinsert UI region so that it spawns entire area width */ + BLI_remlink(regionbase, ar_ui); + BLI_insertlinkafter(regionbase, ar_header, ar_ui); + + ar_ui->flag |= RGN_FLAG_DYNAMIC_SIZE; + + if (ar_toolprops && (ar_toolprops->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) { + SpaceType* stype = BKE_spacetype_from_id(sl->spacetype); + + /* Remove empty region at old location. */ + BLI_assert(sfile->op == NULL); + BKE_area_region_free(stype, ar_toolprops); + BLI_freelinkN(regionbase, ar_toolprops); + } + + if (sfile->params) { + sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME; + } + } + } + } + } + + /* Convert the BONE_NO_SCALE flag to inherit_scale_mode enum. */ + if (!DNA_struct_elem_find(fd->filesdna, "Bone", "char", "inherit_scale_mode")) { + LISTBASE_FOREACH(bArmature*, arm, &bmain->armatures) { + do_version_bones_inherit_scale(&arm->bonebase); + } + } + + /* Convert the Offset flag to the mix mode enum. */ + if (!DNA_struct_elem_find(fd->filesdna, "bRotateLikeConstraint", "char", "mix_mode")) { + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + do_version_constraints_copy_rotation_mix_mode(&ob->constraints); + if (ob->pose) { + LISTBASE_FOREACH(bPoseChannel*, pchan, &ob->pose->chanbase) { + do_version_constraints_copy_rotation_mix_mode(&pchan->constraints); + } + } + } + } + + /* Added studiolight intensity */ + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "float", "studiolight_intensity")) { + for (bScreen* screen = bmain->screens.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.studiolight_intensity = 1.0f; + } + } + } + } + } + + /* Elatic deform brush */ + for (Brush* br = bmain->brushes.first; br; br = br->id.next) { + if (br->ob_mode & OB_MODE_SCULPT && br->elastic_deform_volume_preservation == 0.0f) { + br->elastic_deform_volume_preservation = 0.5f; + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 281, 15)) { + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + if (scene->toolsettings->snap_node_mode == SCE_SNAP_MODE_NODE_X) { + scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; + } + } + + if (!DNA_struct_elem_find( + fd->filesdna, "LayerCollection", "short", "local_collections_bits")) { + LISTBASE_FOREACH(Scene*, scene, &bmain->scenes) { + LISTBASE_FOREACH(ViewLayer*, view_layer, &scene->view_layers) { + LISTBASE_FOREACH(LayerCollection*, layer_collection, &view_layer->layer_collections) { + do_versions_local_collection_bits_set(layer_collection); + } + } + } + } + + for (bScreen* screen = bmain->screens.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; + + for (ScrArea* sa_other = screen->areabase.first; sa_other; sa_other = sa_other->next) { + for (SpaceLink* sl_other = sa_other->spacedata.first; sl_other; + sl_other = sl_other->next) { + if (sl != sl_other && sl_other->spacetype == SPACE_VIEW3D) { + View3D* v3d_other = (View3D*)sl_other; + + if (v3d->shading.prop == v3d_other->shading.prop) { + v3d_other->shading.prop = NULL; + } + } + } + } + } + else if (sl->spacetype == SPACE_FILE) { + ListBase* regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion* ar_tools = do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOLS); + ARegion* ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); + + if (ar_tools) { + ARegion* ar_next = ar_tools->next; + + /* We temporarily had two tools regions, get rid of the second one. */ + if (ar_next && ar_next->regiontype == RGN_TYPE_TOOLS) { + do_versions_remove_region(regionbase, ar_next); + } + + BLI_remlink(regionbase, ar_tools); + BLI_insertlinkafter(regionbase, ar_header, ar_tools); + } + else { + ar_tools = do_versions_add_region(RGN_TYPE_TOOLS, "versioning file tools region"); + BLI_insertlinkafter(regionbase, ar_header, ar_tools); + ar_tools->alignment = RGN_ALIGN_LEFT; + } + } + } + } + } + + { + /* Initialize new grease pencil uv scale parameter. */ + if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "uv_scale")) { + for (bGPdata* gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + LISTBASE_FOREACH(bGPDframe*, gpf, &gpl->frames) { + LISTBASE_FOREACH(bGPDstroke*, gps, &gpf->strokes) { + gps->uv_scale = 1.0f; + } + } + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 282, 2)) { + do_version_curvemapping_walker(bmain, do_version_curvemapping_flag_extend_extrapolate); + + for (bScreen* screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea* sa = screen->areabase.first; sa; sa = sa->next) { + sa->flag &= ~AREA_FLAG_UNUSED_6; + } + } + + /* Add custom curve profile to toolsettings for bevel tool */ + if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "CurveProfile", "custom_profile")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + ToolSettings* ts = scene->toolsettings; + if ((ts) && (ts->custom_bevel_profile_preset == NULL)) { + ts->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE); + } + } + } + + /* Add custom curve profile to bevel modifier */ + if (!DNA_struct_elem_find(fd->filesdna, "BevelModifier", "CurveProfile", "custom_profile")) { + for (Object* object = bmain->objects.first; object != NULL; object = object->id.next) { + for (ModifierData* md = object->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Bevel) { + BevelModifierData* bmd = (BevelModifierData*)md; + if (!bmd->custom_profile) { + bmd->custom_profile = BKE_curveprofile_add(PROF_PRESET_LINE); + } + } + } + } + } + + /* Dash Ratio and Dash Samples */ + if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "dash_ratio")) { + for (Brush* br = bmain->brushes.first; br; br = br->id.next) { + br->dash_ratio = 1.0f; + br->dash_samples = 20; + } + } + + /* Pose brush smooth iterations */ + if (!DNA_struct_elem_find(fd->filesdna, "Brush", "float", "pose_smooth_iterations")) { + for (Brush* br = bmain->brushes.first; br; br = br->id.next) { + br->pose_smooth_iterations = 4; + } + } + + /* Cloth pressure */ + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Cloth) { + ClothModifierData* clmd = (ClothModifierData*)md; + + clmd->sim_parms->pressure_factor = 1; + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 282, 3)) { + /* Remove Unified pressure/size and pressure/alpha */ + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + ToolSettings* ts = scene->toolsettings; + UnifiedPaintSettings* ups = &ts->unified_paint_settings; + ups->flag &= ~(UNIFIED_PAINT_FLAG_UNUSED_0 | UNIFIED_PAINT_FLAG_UNUSED_1); + } + + /* Set the default render pass in the viewport to Combined. */ + if (!DNA_struct_elem_find(fd->filesdna, "View3DShading", "int", "render_pass")) { + for (Scene* scene = bmain->scenes.first; scene; scene = scene->id.next) { + scene->display.shading.render_pass = SCE_PASS_COMBINED; + } + + for (bScreen* screen = bmain->screens.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.render_pass = SCE_PASS_COMBINED; + } + } + } + } + } + + /* Make markers region visible by default. */ + for (bScreen* screen = bmain->screens.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) { + switch (sl->spacetype) { + case SPACE_SEQ: { + SpaceSeq* sseq = (SpaceSeq*)sl; + sseq->flag |= SEQ_SHOW_MARKERS; + break; + } + case SPACE_ACTION: { + SpaceAction* saction = (SpaceAction*)sl; + saction->flag |= SACTION_SHOW_MARKERS; + break; + } + case SPACE_GRAPH: { + SpaceGraph* sipo = (SpaceGraph*)sl; + sipo->flag |= SIPO_SHOW_MARKERS; + break; + } + case SPACE_NLA: { + SpaceNla* snla = (SpaceNla*)sl; + snla->flag |= SNLA_SHOW_MARKERS; + break; + } + } + } + } + } + + /* Init new Grease Pencil Paint tools. */ + { + for (Brush* brush = bmain->brushes.first; brush; brush = brush->id.next) { + if (brush->gpencil_settings != NULL) { + brush->gpencil_vertex_tool = brush->gpencil_settings->brush_type; + brush->gpencil_sculpt_tool = brush->gpencil_settings->brush_type; + brush->gpencil_weight_tool = brush->gpencil_settings->brush_type; + } + } + + BKE_paint_toolslots_init_from_main(bmain); + } + + /* Init default Grease Pencil Vertex paint mix factor for Viewport. */ + { + if (!DNA_struct_elem_find( + fd->filesdna, "View3DOverlay", "float", "gpencil_vertex_paint_opacity")) { + for (bScreen* screen = bmain->screens.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_vertex_paint_opacity = 1.0f; + } + } + } + } + } + } + + /* Init default Grease Pencil Vertex paint layer mix factor. */ + { + if (!DNA_struct_elem_find(fd->filesdna, "bGPDlayer", "float", "vertex_paint_opacity")) { + for (bGPdata* gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + gpl->vertex_paint_opacity = 1.0f; + } + } + } + } + } + + if (!MAIN_VERSION_ATLEAST(bmain, 283, 0)) { + + /* Update Grease Pencil after drawing engine refactor. */ + { + LISTBASE_FOREACH(Material*, mat, &bmain->materials) { + MaterialGPencilStyle* gp_style = mat->gp_style; + if (gp_style == NULL) { + continue; + } + /* Fix Grease Pencil Material colors to Linear. */ + srgb_to_linearrgb_v4(gp_style->stroke_rgba, gp_style->stroke_rgba); + srgb_to_linearrgb_v4(gp_style->fill_rgba, gp_style->fill_rgba); + + /* Move old gradient variables to texture. */ + if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) { + gp_style->texture_angle = gp_style->gradient_angle; + copy_v2_v2(gp_style->texture_scale, gp_style->gradient_scale); + copy_v2_v2(gp_style->texture_offset, gp_style->gradient_shift); + } + /* Set Checker material as Solid. This fill mode has been removed and replaced + * by textures. */ + if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_CHECKER) { + gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; + } + /* Update Alpha channel for texture opacity. */ + if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) { + gp_style->fill_rgba[3] *= gp_style->texture_opacity; + } + /* Stroke stencil mask to mix = 1. */ + if (gp_style->flag & GP_MATERIAL_STROKE_PATTERN) { + gp_style->mix_stroke_factor = 1.0f; + gp_style->flag &= ~GP_MATERIAL_STROKE_PATTERN; + } + /* Mix disabled, set mix factor to 0. */ + else if ((gp_style->flag & GP_MATERIAL_STROKE_TEX_MIX) == 0) { + gp_style->mix_stroke_factor = 0.0f; + } + } + + /* Fix Grease Pencil VFX and modifiers. */ + LISTBASE_FOREACH(Object*, ob, &bmain->objects) { + if (ob->type != OB_GPENCIL) { + continue; + } + + /* VFX. */ + LISTBASE_FOREACH(ShaderFxData*, fx, &ob->shader_fx) { + switch (fx->type) { + case eShaderFxType_Colorize: { + ColorizeShaderFxData* vfx = (ColorizeShaderFxData*)fx; + if (ELEM(vfx->mode, eShaderFxColorizeMode_GrayScale, eShaderFxColorizeMode_Sepia)) { + vfx->factor = 1.0f; + } + srgb_to_linearrgb_v4(vfx->low_color, vfx->low_color); + srgb_to_linearrgb_v4(vfx->high_color, vfx->high_color); + break; + } + case eShaderFxType_Pixel: { + PixelShaderFxData* vfx = (PixelShaderFxData*)fx; + srgb_to_linearrgb_v4(vfx->rgba, vfx->rgba); + break; + } + case eShaderFxType_Rim: { + RimShaderFxData* vfx = (RimShaderFxData*)fx; + srgb_to_linearrgb_v3_v3(vfx->rim_rgb, vfx->rim_rgb); + srgb_to_linearrgb_v3_v3(vfx->mask_rgb, vfx->mask_rgb); + break; + } + case eShaderFxType_Shadow: { + ShadowShaderFxData* vfx = (ShadowShaderFxData*)fx; + srgb_to_linearrgb_v4(vfx->shadow_rgba, vfx->shadow_rgba); + break; + } + case eShaderFxType_Glow: { + GlowShaderFxData* vfx = (GlowShaderFxData*)fx; + srgb_to_linearrgb_v3_v3(vfx->glow_color, vfx->glow_color); + srgb_to_linearrgb_v3_v3(vfx->select_color, vfx->select_color); + break; + } + default: + break; + } + } + + /* Modifiers. */ + LISTBASE_FOREACH(GpencilModifierData*, md, &ob->greasepencil_modifiers) { + const GpencilModifierTypeInfo* mti = BKE_gpencil_modifierType_getInfo(md->type); + switch (mti->type) { + case eGpencilModifierTypeType_Gpencil: { + TintGpencilModifierData* mmd = (TintGpencilModifierData*)md; + srgb_to_linearrgb_v3_v3(mmd->rgb, mmd->rgb); + break; + } + default: + break; + } + } + } + + /* Fix Layers Colors and Vertex Colors to Linear. + * Also set lights to on for layers. */ + LISTBASE_FOREACH(bGPdata*, gpd, &bmain->gpencils) { + if (gpd->flag & GP_DATA_ANNOTATIONS) { + continue; + } + /* Onion colors. */ + srgb_to_linearrgb_v3_v3(gpd->gcolor_prev, gpd->gcolor_prev); + srgb_to_linearrgb_v3_v3(gpd->gcolor_next, gpd->gcolor_next); + + LISTBASE_FOREACH(bGPDlayer*, gpl, &gpd->layers) { + gpl->flag |= GP_LAYER_USE_LIGHTS; + srgb_to_linearrgb_v4(gpl->tintcolor, gpl->tintcolor); + + LISTBASE_FOREACH(bGPDframe*, gpf, &gpl->frames) { + LISTBASE_FOREACH(bGPDstroke*, gps, &gpf->strokes) { + /* Set initial opacity for fill color. */ + gps->fill_opacity_fac = 1.0f; + + /* Calc geometry data because in old versions this data was not saved. */ + BKE_gpencil_stroke_geometry_update(gps); + + srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill); + int i; + bGPDspoint* pt; + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color); + } + } + } + } + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #BLO_version_defaults_userpref_blend + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ + + /* Sequencer Tool region */ + do_versions_area_ensure_tool_region(bmain, SPACE_SEQ, RGN_FLAG_HIDDEN); + + /* Cloth internal springs */ + for (Object* ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ModifierData* md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Cloth) { + ClothModifierData* clmd = (ClothModifierData*)md; + + clmd->sim_parms->internal_tension = 15.0f; + clmd->sim_parms->max_internal_tension = 15.0f; + clmd->sim_parms->internal_compression = 15.0f; + clmd->sim_parms->max_internal_compression = 15.0f; + clmd->sim_parms->internal_spring_max_diversion = M_PI / 4.0f; + } + } + } + + /* Add primary tile to images. */ + if (!DNA_struct_elem_find(fd->filesdna, "Image", "ListBase", "tiles")) { + for (Image* ima = bmain->images.first; ima; ima = ima->id.next) { + ImageTile* tile = MEM_callocN(sizeof(ImageTile), "Image Tile"); + tile->ok = 1; + tile->tile_number = 1001; + BLI_addtail(&ima->tiles, tile); + } + } + + /* UDIM Image Editor change. */ + if (!DNA_struct_elem_find(fd->filesdna, "SpaceImage", "int", "tile_grid_shape[2]")) { + for (bScreen* screen = bmain->screens.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_IMAGE) { + SpaceImage* sima = (SpaceImage*)sl; + sima->tile_grid_shape[0] = 1; + sima->tile_grid_shape[1] = 1; + } + } + } + } + } + + /* Brush cursor alpha */ + for (Brush* br = bmain->brushes.first; br; br = br->id.next) { + br->add_col[3] = 0.9f; + br->sub_col[3] = 0.9f; + } + + /* Pose brush IK segments. */ + for (Brush* br = bmain->brushes.first; br; br = br->id.next) { + if (br->pose_ik_segments == 0) { + br->pose_ik_segments = 1; + } + } + } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 8dc71dd314e..1c0ea8d20ed 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -241,6 +241,8 @@ static void blo_update_defaults_screen(bScreen *screen, View3D *v3d = sa->spacedata.first; /* Set Vertex Color by default. */ v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR; + /* Enable Annotations. */ + v3d->flag2 |= V3D_SHOW_ANNOTATION; } } } @@ -614,14 +616,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) if (ma == NULL) { ma = BKE_gpencil_material_add(bmain, "Dots Stroke"); } - ma->gp_style->mode = GP_STYLE_MODE_DOTS; + ma->gp_style->mode = GP_MATERIAL_MODE_DOT; /* Boxes Stroke. */ ma = BLI_findstring(&bmain->materials, "Boxes Stroke", offsetof(ID, name) + 2); if (ma == NULL) { ma = BKE_gpencil_material_add(bmain, "Boxes Stroke"); } - ma->gp_style->mode = GP_STYLE_MODE_BOX; + ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE; /* Reset all grease pencil brushes. */ Scene *scene = bmain->scenes.first; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 055bc96f5d9..dd8a5a6795a 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2726,14 +2726,15 @@ static void write_gpencil(WriteData *wd, bGPdata *gpd) /* write grease-pencil layers to file */ writelist(wd, DATA, bGPDlayer, &gpd->layers); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* write this layer's frames to file */ writelist(wd, DATA, bGPDframe, &gpl->frames); - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* write strokes */ writelist(wd, DATA, bGPDstroke, &gpf->strokes); - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points); + writestruct(wd, DATA, bGPDtriangle, gps->tot_triangles, gps->triangles); write_dverts(wd, gps->totpoints, gps->dvert); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 98864b11c4a..6a936b560b2 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -2149,6 +2149,15 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) add_relation(material_key, geometry_key, "Material -> GP Data"); } } + + /* Layer parenting need react to the parent object transformation. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + if (gpl->parent != NULL) { + ComponentKey transform_key(&gpl->parent->id, NodeType::TRANSFORM); + ComponentKey gpd_geom_key(&gpd->id, NodeType::GEOMETRY); + add_relation(transform_key, gpd_geom_key, "GPencil Parent Layer"); + } + } break; } default: 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 b74e5715e14..5873a5cd65f 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 @@ -43,6 +43,7 @@ #include "BKE_curve.h" #include "BKE_global.h" #include "BKE_idprop.h" +#include "BKE_gpencil.h" #include "BKE_layer.h" #include "BKE_library.h" #include "BKE_scene.h" @@ -790,6 +791,9 @@ void update_id_after_copy(const Depsgraph *depsgraph, } BKE_pose_pchan_index_rebuild(object_cow->pose); } + if (object_cow->type == OB_GPENCIL) { + BKE_gpencil_update_orig_pointers(object_orig, object_cow); + } update_particles_after_copy(depsgraph, object_orig, object_cow); update_modifiers_orig_pointers(object_orig, object_cow); update_proxy_pointers_after_copy(depsgraph, object_orig, object_cow); diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index a74a255045a..5d11578fe19 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -52,6 +52,7 @@ set(SRC intern/draw_cache_extract_mesh.c intern/draw_cache_impl_curve.c intern/draw_cache_impl_displist.c + intern/draw_cache_impl_gpencil.c intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.c intern/draw_cache_impl_metaball.c @@ -110,12 +111,13 @@ set(SRC engines/workbench/workbench_studiolight.c engines/workbench/workbench_volume.c engines/external/external_engine.c + engines/gpencil/gpencil_antialiasing.c engines/gpencil/gpencil_cache_utils.c - engines/gpencil/gpencil_draw_cache_impl.c - engines/gpencil/gpencil_draw_utils.c + engines/gpencil/gpencil_draw_data.c engines/gpencil/gpencil_engine.c engines/gpencil/gpencil_engine.h engines/gpencil/gpencil_render.c + engines/gpencil/gpencil_shader.c engines/gpencil/gpencil_shader_fx.c engines/select/select_draw_utils.c engines/select/select_engine.c @@ -127,6 +129,7 @@ set(SRC engines/overlay/overlay_engine.c engines/overlay/overlay_extra.c engines/overlay/overlay_facing.c + engines/overlay/overlay_gpencil.c engines/overlay/overlay_grid.c engines/overlay/overlay_image.c engines/overlay/overlay_lattice.c @@ -273,36 +276,17 @@ data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC) data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC) data_to_c_simple(intern/shaders/common_fullscreen_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_blend_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_glow_prepare_frag.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_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_shadow_prepare_frag.glsl SRC) -data_to_c_simple(engines/gpencil/shaders/fx/gpencil_fx_shadow_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) +data_to_c_simple(engines/gpencil/shaders/gpencil_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_antialiasing_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_common_lib.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_composite_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_layer_blend_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_layer_mask_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_frag.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_depth_merge_vert.glsl SRC) +data_to_c_simple(engines/gpencil/shaders/gpencil_vfx_frag.glsl SRC) data_to_c_simple(engines/select/shaders/selection_id_3D_vert.glsl SRC) data_to_c_simple(engines/select/shaders/selection_id_frag.glsl SRC) @@ -334,6 +318,9 @@ data_to_c_simple(engines/overlay/shaders/edit_curve_handle_geom.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_curve_handle_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_curve_point_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_curve_wire_vert.glsl SRC) +data_to_c_simple(engines/overlay/shaders/edit_gpencil_canvas_vert.glsl SRC) +data_to_c_simple(engines/overlay/shaders/edit_gpencil_guide_vert.glsl SRC) +data_to_c_simple(engines/overlay/shaders/edit_gpencil_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_lattice_point_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_lattice_wire_vert.glsl SRC) data_to_c_simple(engines/overlay/shaders/edit_mesh_common_lib.glsl SRC) diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c new file mode 100644 index 00000000000..f53746b922b --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c @@ -0,0 +1,155 @@ +/* + * 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. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup draw + */ + +#include "DRW_render.h" + +#include "gpencil_engine.h" + +#include "smaa_textures.h" + +void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata) +{ + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_FramebufferList *fbl = vedata->fbl; + GPENCIL_TextureList *txl = vedata->txl; + GPENCIL_PassList *psl = vedata->psl; + DRWShadingGroup *grp; + + /* We need a temporary buffer to output result. */ + BLI_assert(pd->color_layer_tx && pd->reveal_layer_tx); + + if (txl->smaa_search_tx == NULL) { + txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH, + SEARCHTEX_HEIGHT, + 0, + 2, + searchTexBytes, + GPU_R8, + GPU_DATA_UNSIGNED_BYTE, + 0, + false, + NULL); + + txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH, + AREATEX_HEIGHT, + 0, + 2, + areaTexBytes, + GPU_RG8, + GPU_DATA_UNSIGNED_BYTE, + 0, + false, + NULL); + + GPU_texture_bind(txl->smaa_search_tx, 0); + GPU_texture_filter_mode(txl->smaa_search_tx, true); + GPU_texture_unbind(txl->smaa_search_tx); + + GPU_texture_bind(txl->smaa_area_tx, 0); + GPU_texture_filter_mode(txl->smaa_area_tx, true); + GPU_texture_unbind(txl->smaa_area_tx); + } + + const float *size = DRW_viewport_size_get(); + float metrics[4] = {1.0f / size[0], 1.0f / size[1], size[0], size[1]}; + + { + pd->smaa_edge_tx = DRW_texture_pool_query_2d( + size[0], size[1], GPU_RG8, &draw_engine_gpencil_type); + pd->smaa_weight_tx = DRW_texture_pool_query_2d( + size[0], size[1], GPU_RGBA8, &draw_engine_gpencil_type); + + GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(pd->smaa_edge_tx), + }); + + GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(pd->smaa_weight_tx), + }); + } + + { + /* Stage 1: Edge detection. */ + DRW_PASS_CREATE(psl->smaa_edge_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = GPENCIL_shader_antialiasing(0); + grp = DRW_shgroup_create(sh, psl->smaa_edge_ps); + DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx); + DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + + DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + /* Stage 2: Blend Weight/Coord. */ + DRW_PASS_CREATE(psl->smaa_weight_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = GPENCIL_shader_antialiasing(1); + grp = DRW_shgroup_create(sh, psl->smaa_weight_ps); + DRW_shgroup_uniform_texture(grp, "edgesTex", pd->smaa_edge_tx); + DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx); + DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + + DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + /* Stage 3: Resolve. */ + /* TODO merge it with the main composite pass. */ + DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = GPENCIL_shader_antialiasing(2); + grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps); + DRW_shgroup_uniform_texture(grp, "blendTex", pd->smaa_weight_tx); + DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx); + DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} + +void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata) +{ + GPENCIL_FramebufferList *fbl = vedata->fbl; + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_PassList *psl = vedata->psl; + + GPU_framebuffer_bind(fbl->smaa_edge_fb); + DRW_draw_pass(psl->smaa_edge_ps); + + GPU_framebuffer_bind(fbl->smaa_weight_fb); + DRW_draw_pass(psl->smaa_weight_ps); + + GPU_framebuffer_bind(fbl->layer_fb); + DRW_draw_pass(psl->smaa_resolve_ps); + + /* Swap buffers */ + SWAP(GPUTexture *, pd->color_tx, pd->color_layer_tx); + SWAP(GPUTexture *, pd->reveal_tx, pd->reveal_layer_tx); +} diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index f21d96a304c..ae8ac611570 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -33,324 +33,218 @@ #include "BKE_gpencil.h" #include "BKE_object.h" +#include "BLI_memblock.h" +#include "BLI_link_utils.h" + #include "gpencil_engine.h" #include "draw_cache_impl.h" #include "DEG_depsgraph.h" -/* verify if exist a non instanced version of the object */ -static bool gpencil_has_noninstanced_object(Object *ob_instance) +GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const ViewLayer *view_layer = draw_ctx->view_layer; - Object *ob = NULL; - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - ob = base->object; - if (ob->type != OB_GPENCIL) { - continue; - } - /* is not duplicated and the name is equals */ - if ((ob->base_flag & BASE_FROM_DUPLI) == 0) { - if (STREQ(ob->id.name, ob_instance->id.name)) { - return true; - } - } + bGPdata *gpd = (bGPdata *)ob->data; + GPENCIL_tObject *tgp_ob = BLI_memblock_alloc(pd->gp_object_pool); + + tgp_ob->layers.first = tgp_ob->layers.last = NULL; + tgp_ob->vfx.first = tgp_ob->vfx.last = NULL; + tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->obmat[3]); + tgp_ob->is_drawmode3d = (gpd->draw_mode == GP_DRAWMODE_3D); + + /* Find the normal most likely to represent the gpObject. */ + /* TODO: This does not work quite well if you use + * strokes not aligned with the object axes. Maybe we could try to + * compute the minimum axis of all strokes. But this would be more + * computationaly heavy and should go into the GPData evaluation. */ + BoundBox *bbox = BKE_object_boundbox_get(ob); + /* Convert bbox to matrix */ + float mat[4][4], size[3], center[3]; + BKE_boundbox_calc_size_aabb(bbox, size); + BKE_boundbox_calc_center_aabb(bbox, center); + unit_m4(mat); + copy_v3_v3(mat[3], center); + /* Avoid division by 0.0 later. */ + add_v3_fl(size, 1e-8f); + rescale_m4(mat, size); + /* BBox space to World. */ + mul_m4_m4m4(mat, ob->obmat, mat); + if (DRW_view_is_persp_get(NULL)) { + /* BBox center to camera vector. */ + sub_v3_v3v3(tgp_ob->plane_normal, pd->camera_pos, mat[3]); + } + else { + copy_v3_v3(tgp_ob->plane_normal, pd->camera_z_axis); + } + /* World to BBox space. */ + invert_m4(mat); + /* Normalize the vector in BBox space. */ + mul_mat3_m4_v3(mat, tgp_ob->plane_normal); + normalize_v3(tgp_ob->plane_normal); + + transpose_m4(mat); + /* mat is now a "normal" matrix which will transform + * BBox space normal to world space. */ + mul_mat3_m4_v3(mat, tgp_ob->plane_normal); + normalize_v3(tgp_ob->plane_normal); + + /* Define a matrix that will be used to render a triangle to merge the depth of the rendered + * gpencil object with the rest of the scene. */ + unit_m4(tgp_ob->plane_mat); + copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal); + orthogonalize_m4(tgp_ob->plane_mat, 2); + mul_mat3_m4_v3(ob->obmat, size); + float radius = len_v3(size); + mul_m4_v3(ob->obmat, center); + rescale_m4(tgp_ob->plane_mat, (float[3]){radius, radius, radius}); + copy_v3_v3(tgp_ob->plane_mat[3], center); + + /* Add to corresponding list if is in front. */ + if (ob->dtx & OB_DRAWXRAY) { + BLI_LINKS_APPEND(&pd->tobjects_infront, tgp_ob); + } + else { + BLI_LINKS_APPEND(&pd->tobjects, tgp_ob); } - return false; + return tgp_ob; } -/* add a gpencil object to cache to defer drawing */ -tGPencilObjectCache *gpencil_object_cache_add(tGPencilObjectCache *cache_array, - Object *ob, - int *gp_cache_size, - int *gp_cache_used) +GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, Object *ob, bGPDlayer *gpl) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - tGPencilObjectCache *cache_elem = NULL; - RegionView3D *rv3d = draw_ctx->rv3d; - View3D *v3d = draw_ctx->v3d; - 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; + const bool is_obact = ((pd->obact) && (pd->obact == ob)); + const bool is_fade = ((pd->fade_layer_opacity > -1.0f) && (is_obact) && + ((gpl->flag & GP_LAYER_ACTIVE) == 0)); + + /* Defines layer opacity. For active object depends of layer opacity factor, and + * for no active object, depends if the fade grease pencil objects option is enabled. */ + float fade_layer_opacity = gpl->opacity; + if (!pd->is_render) { + if ((is_obact) && (is_fade)) { + fade_layer_opacity = pd->fade_layer_opacity; } - else { - *gp_cache_size += GP_CACHE_BLOCK_SIZE; - p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size); + else if ((!is_obact) && (pd->fade_gp_object_opacity > -1.0f)) { + fade_layer_opacity = pd->fade_gp_object_opacity; } - cache_array = p; - } - /* zero out all pointers */ - cache_elem = &cache_array[*gp_cache_used]; - memset(cache_elem, 0, sizeof(*cache_elem)); - - cache_elem->ob = ob; - cache_elem->gpd = (bGPdata *)ob->data; - cache_elem->name = BKE_id_to_unique_string_key(&ob->id); - - copy_v3_v3(cache_elem->loc, ob->obmat[3]); - copy_m4_m4(cache_elem->obmat, ob->obmat); - cache_elem->idx = *gp_cache_used; - - /* object is duplicated (particle) */ - if (ob->base_flag & BASE_FROM_DUPLI) { - /* Check if the original object is not in the viewlayer - * and cannot be managed as dupli. This is slower, but required to keep - * the particle drawing FPS and display instanced objects in scene - * without the original object */ - bool has_original = gpencil_has_noninstanced_object(ob); - cache_elem->is_dup_ob = (has_original) ? ob->base_flag & BASE_FROM_DUPLI : false; } - else { - cache_elem->is_dup_ob = false; - } - - cache_elem->scale = mat4_to_scale(ob->obmat); - - /* save FXs */ - cache_elem->pixfactor = cache_elem->gpd->pixfactor; - cache_elem->shader_fx = ob->shader_fx; - - /* save wire mode (object mode is always primary option) */ - if (ob->dt == OB_WIRE) { - cache_elem->shading_type[0] = (int)OB_WIRE; - } - else { - if (v3d) { - cache_elem->shading_type[0] = (int)v3d->shading.type; + bGPdata *gpd = (bGPdata *)ob->data; + GPENCIL_tLayer *tgp_layer = BLI_memblock_alloc(pd->gp_layer_pool); + + const bool is_mask = (gpl->flag & GP_LAYER_USE_MASK) != 0; + tgp_layer->is_mask = is_mask; + tgp_layer->do_masked_clear = false; + + if (!is_mask) { + tgp_layer->is_masked = false; + for (bGPDlayer *gpl_m = gpl->next; gpl_m; gpl_m = gpl_m->next) { + if (gpl_m->flag & GP_LAYER_USE_MASK) { + if (gpl_m->flag & GP_LAYER_HIDE) { + /* We don't mask but we dont try to mask with further layers. */ + } + else { + tgp_layer->is_masked = true; + } + break; + } } } - /* shgrp array */ - cache_elem->tot_layers = 0; - int totgpl = BLI_listbase_count(&cache_elem->gpd->layers); - if (totgpl > 0) { - cache_elem->shgrp_array = MEM_callocN(sizeof(tGPencilObjectCache_shgrp) * totgpl, __func__); - } - - /* calculate zdepth from point of view */ - float zdepth = 0.0; - if (rv3d) { - if (rv3d->is_persp) { - zdepth = ED_view3d_calc_zfac(rv3d, ob->obmat[3], NULL); + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; + if (GPENCIL_3D_DRAWMODE(ob, gpd) || pd->draw_depth_only) { + /* TODO better 3D mode. */ + state |= DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; } else { - zdepth = -dot_v3v3(rv3d->viewinv[2], ob->obmat[3]); - } - } - 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->obmat[3], plane_cam); + /* We render all strokes with uniform depth (increasing with stroke id). */ + state |= DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_GREATER; } - } - cache_elem->zdepth = zdepth; - /* increase slots used in cache */ - (*gp_cache_used)++; - return cache_array; -} - -/* add a shading group to the cache to create later */ -GpencilBatchGroup *gpencil_group_cache_add(GpencilBatchGroup *cache_array, - bGPDlayer *gpl, - bGPDframe *gpf, - bGPDstroke *gps, - const short type, - const bool onion, - const int vertex_idx, - int *grp_size, - int *grp_used) -{ - GpencilBatchGroup *cache_elem = NULL; - GpencilBatchGroup *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 (*grp_used + 1 > *grp_size) { - if ((*grp_size == 0) || (cache_array == NULL)) { - p = MEM_callocN(sizeof(struct GpencilBatchGroup) * GPENCIL_GROUPS_BLOCK_SIZE, - "GpencilBatchGroup"); - *grp_size = GPENCIL_GROUPS_BLOCK_SIZE; + if (gpl->flag & GP_LAYER_USE_MASK) { + state |= DRW_STATE_STENCIL_EQUAL; } else { - *grp_size += GPENCIL_GROUPS_BLOCK_SIZE; - p = MEM_recallocN(cache_array, sizeof(struct GpencilBatchGroup) * *grp_size); + state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; } - cache_array = p; - } - /* zero out all data */ - cache_elem = &cache_array[*grp_used]; - memset(cache_elem, 0, sizeof(*cache_elem)); - - cache_elem->gpl = gpl; - cache_elem->gpf = gpf; - cache_elem->gps = gps; - cache_elem->type = type; - cache_elem->onion = onion; - cache_elem->vertex_idx = vertex_idx; - - /* increase slots used in cache */ - (*grp_used)++; - return cache_array; -} - -/* get current cache data */ -static GpencilBatchCache *gpencil_batch_get_element(Object *ob) -{ - return ob->runtime.gpencil_cache; -} - -/* verify if cache is valid */ -static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra) -{ - bool valid = true; - if (cache == NULL) { - return false; - } - - cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); - if (cfra != cache->cache_frame) { - valid = false; - } - else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) { - valid = false; - } - else if (gpd->flag & GP_DATA_PYTHON_UPDATED) { - gpd->flag &= ~GP_DATA_PYTHON_UPDATED; - valid = false; - } - else if (cache->is_editmode) { - valid = false; - } - else if (cache->is_dirty) { - valid = false; - } - - return valid; -} - -/* cache init */ -static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) -{ - bGPdata *gpd = (bGPdata *)ob->data; - - GpencilBatchCache *cache = gpencil_batch_get_element(ob); - - if (!cache) { - cache = MEM_callocN(sizeof(*cache), __func__); - ob->runtime.gpencil_cache = cache; - } - else { - memset(cache, 0, sizeof(*cache)); - } - - cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); - - cache->is_dirty = true; - - cache->cache_frame = cfra; - - return cache; -} - -/* clear cache */ -static void gpencil_batch_cache_clear(GpencilBatchCache *cache) -{ - if (!cache) { - return; - } - - GPU_BATCH_DISCARD_SAFE(cache->b_stroke.batch); - GPU_BATCH_DISCARD_SAFE(cache->b_point.batch); - GPU_BATCH_DISCARD_SAFE(cache->b_fill.batch); - GPU_BATCH_DISCARD_SAFE(cache->b_edit.batch); - GPU_BATCH_DISCARD_SAFE(cache->b_edlin.batch); - - MEM_SAFE_FREE(cache->b_stroke.batch); - MEM_SAFE_FREE(cache->b_point.batch); - MEM_SAFE_FREE(cache->b_fill.batch); - MEM_SAFE_FREE(cache->b_edit.batch); - MEM_SAFE_FREE(cache->b_edlin.batch); - - /* internal format data */ - MEM_SAFE_FREE(cache->b_stroke.format); - MEM_SAFE_FREE(cache->b_point.format); - MEM_SAFE_FREE(cache->b_fill.format); - MEM_SAFE_FREE(cache->b_edit.format); - MEM_SAFE_FREE(cache->b_edlin.format); - - MEM_SAFE_FREE(cache->grp_cache); - cache->grp_size = 0; - cache->grp_used = 0; -} - -/* get cache */ -GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra) -{ - bGPdata *gpd = (bGPdata *)ob->data; - - GpencilBatchCache *cache = gpencil_batch_get_element(ob); - if (!gpencil_batch_cache_valid(cache, gpd, cfra)) { - if (cache) { - gpencil_batch_cache_clear(cache); + tgp_layer->geom_ps = DRW_pass_create("GPencil Layer", state); + } + + if (is_mask) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL | DRW_STATE_BLEND_MUL; + tgp_layer->blend_ps = DRW_pass_create("GPencil Mask Layer", state); + + GPUShader *sh = GPENCIL_shader_layer_mask_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tgp_layer->blend_ps); + DRW_shgroup_uniform_int_copy(grp, "isFirstPass", true); + DRW_shgroup_uniform_float_copy(grp, "maskOpacity", fade_layer_opacity); + DRW_shgroup_uniform_bool_copy(grp, "maskInvert", gpl->flag & GP_LAYER_MASK_INVERT); + DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_masked_tx); + DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_masked_tx); + DRW_shgroup_uniform_texture_ref(grp, "maskBuf", &pd->reveal_layer_tx); + DRW_shgroup_stencil_mask(grp, 0xFF); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + /* We cannot do custom blending on MultiTarget framebuffers. + * Workaround by doing 2 passes. */ + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL); + DRW_shgroup_uniform_int_copy(grp, "isFirstPass", false); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + pd->use_mask_fb = true; + } + else if ((gpl->blend_mode != eGplBlendMode_Regular) || (fade_layer_opacity < 1.0f)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL; + switch (gpl->blend_mode) { + case eGplBlendMode_Regular: + state |= DRW_STATE_BLEND_ALPHA_PREMUL; + break; + case eGplBlendMode_Add: + state |= DRW_STATE_BLEND_ADD_FULL; + break; + case eGplBlendMode_Subtract: + state |= DRW_STATE_BLEND_SUB; + break; + case eGplBlendMode_Multiply: + case eGplBlendMode_Divide: + case eGplBlendMode_Overlay: + state |= DRW_STATE_BLEND_MUL; + break; } - return gpencil_batch_cache_init(ob, cfra); - } - else { - return cache; - } -} -/* set cache as dirty */ -void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd) -{ - gpd->flag |= GP_DATA_CACHE_IS_DIRTY; -} - -/* free batch cache */ -void DRW_gpencil_batch_cache_free(bGPdata *UNUSED(gpd)) -{ - return; -} + if (ELEM(gpl->blend_mode, eGplBlendMode_Subtract, eGplBlendMode_Overlay)) { + /* For these effect to propagate, we need a signed floating point buffer. */ + pd->use_signed_fb = true; + } -/* wrapper to clear cache */ -void DRW_gpencil_freecache(struct Object *ob) -{ - if ((ob) && (ob->type == OB_GPENCIL)) { - gpencil_batch_cache_clear(ob->runtime.gpencil_cache); - MEM_SAFE_FREE(ob->runtime.gpencil_cache); - bGPdata *gpd = (bGPdata *)ob->data; - if (gpd) { - gpd->flag |= GP_DATA_CACHE_IS_DIRTY; + tgp_layer->blend_ps = DRW_pass_create("GPencil Blend Layer", state); + + GPUShader *sh = GPENCIL_shader_layer_blend_get(); + DRWShadingGroup *grp = DRW_shgroup_create(sh, tgp_layer->blend_ps); + DRW_shgroup_uniform_int_copy(grp, "blendMode", gpl->blend_mode); + DRW_shgroup_uniform_float_copy(grp, "blendOpacity", fade_layer_opacity); + DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_layer_tx); + DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_layer_tx); + DRW_shgroup_stencil_mask(grp, 0xFF); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + if (gpl->blend_mode == eGplBlendMode_Overlay) { + /* We cannot do custom blending on MultiTarget framebuffers. + * Workaround by doing 2 passes. */ + grp = DRW_shgroup_create(sh, tgp_layer->blend_ps); + DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL); + DRW_shgroup_uniform_int_copy(grp, "blendMode", 999); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } - } - /* clear all frames evaluated data */ - for (int i = 0; i < ob->runtime.gpencil_tot_layers; i++) { - bGPDframe *gpf_eval = &ob->runtime.gpencil_evaluated_frames[i]; - BKE_gpencil_free_frame_runtime_data(gpf_eval); + pd->use_layer_fb = true; + } + else { + tgp_layer->blend_ps = NULL; } - ob->runtime.gpencil_tot_layers = 0; - MEM_SAFE_FREE(ob->runtime.gpencil_evaluated_frames); + return tgp_layer; } diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c deleted file mode 100644 index 30fc1896bbb..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c +++ /dev/null @@ -1,1144 +0,0 @@ -/* - * 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 - */ - -/** \file - * \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_deform.h" -#include "BKE_gpencil.h" - -#include "DRW_render.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, - const bGPDspoint *pt, - int idx, - uint pos_id, - uint color_id, - uint thickness_id, - uint uvdata_id, - short thickness, - const bool attenuate, - const float ink[4]) -{ - float alpha = ink[3] * pt->strength; - - /* If using vertex paint mask, attenuate not selected. */ - if ((attenuate) && ((pt->flag & GP_SPOINT_SELECT) == 0)) { - alpha *= GP_VERTEX_MASK_ATTENUATE; - } - - 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 */ - 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 buffer_stroke point to vbo */ -static void gpencil_set_buffer_stroke_point(GPUVertBuf *vbo, - const bGPDspoint *pt, - int idx, - uint pos_id, - uint color_id, - uint thickness_id, - uint uvdata_id, - uint prev_pos_id, - const float ref_pt[3], - short thickness, - const float ink[4]) -{ - - 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 */ - 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); - /* reference point to follow drawing path */ - GPU_vertbuf_attr_set(vbo, prev_pos_id, idx, ref_pt); -} - -/* 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], - const 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); -} - -static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex) -{ - if (be->vbo->vertex_alloc <= be->vbo_len + totvertex) { - uint newsize = be->vbo->vertex_alloc + - (((totvertex / GPENCIL_VBO_BLOCK_SIZE) + 1) * GPENCIL_VBO_BLOCK_SIZE); - GPU_vertbuf_data_resize(be->vbo, newsize); - } -} - -static void gpencil_elem_format_ensure(GpencilBatchCacheElem *be) -{ - if (be->format == NULL) { - be->format = MEM_callocN(sizeof(GPUVertFormat), __func__); - } -} - -/* create batch geometry data for points stroke shader */ -void gpencil_get_point_geom(GpencilBatchCacheElem *be, - bGPDlayer *gpl, - bGPDstroke *gps, - short thickness, - const float ink[4], - const float tintcolor[4], - const int alignment_mode, - const bool onion) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - ToolSettings *ts = draw_ctx->scene->toolsettings; - Object *ob = draw_ctx->obact; - bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; - int totvertex = gps->totpoints; - float mix_color[4]; - - const float vpaint_mix = gpencil_get_vertex_paint_factor(v3d); - const bool attenuate = (GPENCIL_VERTEX_MODE(gpd) && - GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); - - if (be->vbo == NULL) { - gpencil_elem_format_ensure(be); - be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - be->thickness_id = GPU_vertformat_attr_add( - be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - be->uvdata_id = GPU_vertformat_attr_add( - be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - be->prev_pos_id = GPU_vertformat_attr_add( - be->format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - be->vbo = GPU_vertbuf_create_with_format(be->format); - GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex); - be->vbo_len = 0; - } - gpencil_vbo_ensure_size(be, totvertex); - - /* draw stroke curve */ - const bGPDspoint *pt = gps->points; - 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); - /* Apply the mix color. */ - if (!onion) { - float mixtint[3]; - interp_v3_v3v3(mixtint, pt->mix_color, tintcolor, tintcolor[3]); - interp_v3_v3v3( - mix_color, ink, mixtint, pt->mix_color[3] * vpaint_mix * gpl->vertex_paint_opacity); - } - /* If using vertex paint mask, attenuate not selected. */ - if ((attenuate) && ((pt->flag & GP_SPOINT_SELECT) == 0)) { - alpha *= GP_VERTEX_MASK_ATTENUATE; - } - - ARRAY_SET_ITEMS(col, mix_color[0], mix_color[1], mix_color[2], alpha); - - float thick = max_ff(pt->pressure * thickness, 1.0f); - - GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col); - GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick); - - /* transfer both values using the same shader variable */ - float uvdata[2] = {pt->uv_fac, pt->uv_rot}; - GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata); - - GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x); - - /* use previous point to determine stroke direction */ - bGPDspoint *pt2 = NULL; - float fpt[3]; - if (alignment_mode != GP_STYLE_FOLLOW_PATH) { - /* add small offset to get a vector */ - copy_v3_v3(fpt, &pt->x); - fpt[0] += 0.00001f; - fpt[1] += 0.00001f; - GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); - } - else { - if (i == 0) { - if (gps->totpoints > 1) { - /* extrapolate a point before first point */ - pt2 = &gps->points[1]; - interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f); - GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); - } - else { - /* add small offset to get a vector */ - copy_v3_v3(fpt, &pt->x); - fpt[0] += 0.00001f; - fpt[1] += 0.00001f; - GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt); - } - } - else { - pt2 = &gps->points[i - 1]; - GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x); - } - } - be->vbo_len++; - } -} - -/* create batch geometry data for stroke shader */ -void gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, - bGPDlayer *gpl, - bGPDstroke *gps, - short thickness, - const float ink[4], - const float tintcolor[4], - const bool onion) -{ - bGPDspoint *points = gps->points; - int totpoints = gps->totpoints; - /* if cyclic needs more vertex */ - int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0; - int totvertex = totpoints + cyclic_add + 2; - float mix_color[4]; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - ToolSettings *ts = draw_ctx->scene->toolsettings; - Object *ob = draw_ctx->obact; - bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; - - const float vpaint_mix = gpencil_get_vertex_paint_factor(v3d); - const bool attenuate = (GPENCIL_VERTEX_MODE(gpd) && - GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); - - if (be->vbo == NULL) { - gpencil_elem_format_ensure(be); - be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - be->thickness_id = GPU_vertformat_attr_add( - be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - be->uvdata_id = GPU_vertformat_attr_add( - be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - be->vbo = GPU_vertbuf_create_with_format(be->format); - GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex); - be->vbo_len = 0; - } - gpencil_vbo_ensure_size(be, totvertex); - - /* draw stroke curve */ - const bGPDspoint *pt = points; - for (int i = 0; i < totpoints; i++, pt++) { - /* Apply the mix color. */ - copy_v4_v4(mix_color, ink); - if (!onion) { - float mixtint[3]; - interp_v3_v3v3(mixtint, pt->mix_color, tintcolor, tintcolor[3]); - interp_v3_v3v3( - mix_color, ink, mixtint, pt->mix_color[3] * vpaint_mix * gpl->vertex_paint_opacity); - } - - /* first point for adjacency (not drawn) */ - if (i == 0) { - if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { - gpencil_set_stroke_point(be->vbo, - &points[totpoints - 1], - be->vbo_len, - be->pos_id, - be->color_id, - be->thickness_id, - be->uvdata_id, - thickness, - attenuate, - mix_color); - be->vbo_len++; - } - else { - gpencil_set_stroke_point(be->vbo, - &points[1], - be->vbo_len, - be->pos_id, - be->color_id, - be->thickness_id, - be->uvdata_id, - thickness, - attenuate, - mix_color); - be->vbo_len++; - } - } - /* set point */ - gpencil_set_stroke_point(be->vbo, - pt, - be->vbo_len, - be->pos_id, - be->color_id, - be->thickness_id, - be->uvdata_id, - thickness, - attenuate, - mix_color); - be->vbo_len++; - } - - if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) { - /* draw line to first point to complete the cycle */ - gpencil_set_stroke_point(be->vbo, - &points[0], - be->vbo_len, - be->pos_id, - be->color_id, - be->thickness_id, - be->uvdata_id, - thickness, - attenuate, - mix_color); - be->vbo_len++; - /* now add adjacency point (not drawn) */ - gpencil_set_stroke_point(be->vbo, - &points[1], - be->vbo_len, - be->pos_id, - be->color_id, - be->thickness_id, - be->uvdata_id, - thickness, - attenuate, - mix_color); - be->vbo_len++; - } - /* last adjacency point (not drawn) */ - else { - gpencil_set_stroke_point(be->vbo, - &points[totpoints - 2], - be->vbo_len, - be->pos_id, - be->color_id, - be->thickness_id, - be->uvdata_id, - thickness, - attenuate, - mix_color); - be->vbo_len++; - } -} - -/* create batch geometry data for stroke shader */ -void gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, - 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_GEOMETRY) || (gps->tot_triangles == 0) || - (gps->triangles == NULL)) { - BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps); - } - - BLI_assert(gps->tot_triangles >= 1); - int totvertex = gps->tot_triangles * 3; - - if (be->vbo == NULL) { - gpencil_elem_format_ensure(be); - be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - be->uvdata_id = GPU_vertformat_attr_add( - be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - be->vbo = GPU_vertbuf_create_with_format(be->format); - GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex); - be->vbo_len = 0; - } - gpencil_vbo_ensure_size(be, totvertex); - - /* Draw all triangles for filling the polygon (cache must be calculated before) */ - bGPDtriangle *stroke_triangle = gps->triangles; - for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { - for (int j = 0; j < 3; j++) { - gpencil_set_fill_point(be->vbo, - be->vbo_len, - &gps->points[stroke_triangle->verts[j]], - color, - stroke_triangle->uv[j], - be->pos_id, - be->color_id, - be->uvdata_id); - be->vbo_len++; - } - } -} - -/* create batch geometry data for current buffer stroke shader */ -GPUBatch *gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - 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_used; - /* if cyclic needs more vertex */ - int cyclic_add = (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC) ? 1 : 0; - int totvertex = totpoints + cyclic_add + 2; - - 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, totvertex); - - /* draw stroke curve */ - const tGPspoint *tpt = points; - bGPDspoint pt, pt2, pt3; - int idx = 0; - - /* get origin to reproject point */ - float origin[3]; - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); - ED_gp_get_drawing_reference(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(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); - - /* first point for adjacency (not drawn) */ - if (i == 0) { - if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) { - ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 1], &pt2); - gpencil_set_stroke_point(vbo, - &pt2, - idx, - pos_id, - color_id, - thickness_id, - uvdata_id, - thickness, - false, - gpd->runtime.scolor); - idx++; - } - else { - ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt2); - gpencil_set_stroke_point(vbo, - &pt2, - idx, - pos_id, - color_id, - thickness_id, - uvdata_id, - thickness, - false, - gpd->runtime.scolor); - idx++; - } - } - - /* set point */ - gpencil_set_stroke_point(vbo, - &pt, - idx, - pos_id, - color_id, - thickness_id, - uvdata_id, - thickness, - false, - gpd->runtime.scolor); - idx++; - } - - /* last adjacency point (not drawn) */ - if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) { - /* draw line to first point to complete the cycle */ - ED_gpencil_tpoint_to_point(ar, origin, &points[0], &pt2); - gpencil_set_stroke_point(vbo, - &pt2, - idx, - pos_id, - color_id, - thickness_id, - uvdata_id, - thickness, - false, - gpd->runtime.scolor); - idx++; - /* now add adjacency point (not drawn) */ - ED_gpencil_tpoint_to_point(ar, origin, &points[1], &pt3); - gpencil_set_stroke_point(vbo, - &pt3, - idx, - pos_id, - color_id, - thickness_id, - uvdata_id, - thickness, - false, - gpd->runtime.scolor); - idx++; - } - /* last adjacency point (not drawn) */ - else { - ED_gpencil_tpoint_to_point(ar, origin, &points[totpoints - 2], &pt2); - gpencil_set_stroke_point(vbo, - &pt2, - idx, - pos_id, - color_id, - thickness_id, - uvdata_id, - thickness, - false, - gpd->runtime.scolor); - idx++; - } - - 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 *gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - 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_used; - - static GPUVertFormat format = {0}; - static uint pos_id, color_id, thickness_id, uvdata_id, prev_pos_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); - prev_pos_id = GPU_vertformat_attr_add(&format, "prev_pos", GPU_COMP_F32, 3, 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(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(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); - - /* use previous point to determine stroke direction (drawing path) */ - bGPDspoint pt2; - float ref_pt[3]; - - if (i == 0) { - if (totpoints > 1) { - /* extrapolate a point before first point */ - tGPspoint *tpt2 = &points[1]; - ED_gpencil_tpoint_to_point(ar, origin, tpt2, &pt2); - ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2); - - interp_v3_v3v3(ref_pt, &pt2.x, &pt.x, 1.5f); - } - else { - copy_v3_v3(ref_pt, &pt.x); - } - } - else { - tGPspoint *tpt2 = &points[i - 1]; - ED_gpencil_tpoint_to_point(ar, origin, tpt2, &pt2); - ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2); - - copy_v3_v3(ref_pt, &pt2.x); - } - - /* set point */ - gpencil_set_buffer_stroke_point(vbo, - &pt, - idx, - pos_id, - color_id, - thickness_id, - uvdata_id, - prev_pos_id, - ref_pt, - 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 control point shader */ -GPUBatch *gpencil_get_buffer_ctrlpoint_geom(bGPdata *gpd) -{ - bGPDcontrolpoint *cps = gpd->runtime.cp_points; - int totpoints = gpd->runtime.tot_cp_points; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - ToolSettings *ts = scene->toolsettings; - - if (ts->gp_sculpt.guide.use_guide) { - totpoints++; - } - - 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); - size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, 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, totpoints); - - int idx = 0; - for (int i = 0; i < gpd->runtime.tot_cp_points; i++) { - bGPDcontrolpoint *cp = &cps[i]; - - GPU_vertbuf_attr_set(vbo, color_id, idx, cp->color); - - /* scale size */ - float size = cp->size * 0.8f; - GPU_vertbuf_attr_set(vbo, size_id, idx, &size); - - GPU_vertbuf_attr_set(vbo, pos_id, idx, &cp->x); - idx++; - } - - if (ts->gp_sculpt.guide.use_guide) { - float size = 10 * 0.8f; - float color[4]; - float position[3]; - if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) { - UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); - copy_v3_v3(position, ts->gp_sculpt.guide.location); - } - else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT && - ts->gp_sculpt.guide.reference_object != NULL) { - UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color); - copy_v3_v3(position, ts->gp_sculpt.guide.reference_object->loc); - } - else { - UI_GetThemeColor4fv(TH_REDALERT, color); - copy_v3_v3(position, scene->cursor.location); - } - GPU_vertbuf_attr_set(vbo, pos_id, idx, position); - GPU_vertbuf_attr_set(vbo, size_id, idx, &size); - GPU_vertbuf_attr_set(vbo, color_id, idx, color); - } - - return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); -} - -/* create batch geometry data for current buffer fill shader */ -GPUBatch *gpencil_get_buffer_fill_geom(bGPdata *gpd) -{ - if (gpd == NULL) { - return NULL; - } - - const tGPspoint *points = gpd->runtime.sbuffer; - int totpoints = gpd->runtime.sbuffer_used; - if (totpoints < 3) { - return NULL; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - 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(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); -} - -/* Draw selected verts for strokes being edited */ -void gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, - bGPDstroke *gps, - float alpha, - short dflag) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - Object *ob = draw_ctx->obact; - bGPdata *gpd = ob->data; - const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); - const bool is_vertex_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_VERTEXMODE); - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - - 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]; - float unselectColor[4]; - if (!is_vertex_paint) { - UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); - UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor); - } - else { - UI_GetThemeColor3fv(TH_ACTIVE_VERT, selectColor); - UI_GetThemeColor3fv(TH_VERTEX, unselectColor); - /* Make smaller */ - vsize *= 0.8f; - bsize *= 0.8f; - } - selectColor[3] = alpha; - unselectColor[3] = alpha; - - float linecolor[4]; - copy_v4_v4(linecolor, gpd->line_color); - - if (be->vbo == NULL) { - gpencil_elem_format_ensure(be); - be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - be->thickness_id = GPU_vertformat_attr_add( - be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - - be->vbo = GPU_vertbuf_create_with_format(be->format); - GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex); - be->vbo_len = 0; - } - gpencil_vbo_ensure_size(be, 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; - - float fcolor[4]; - float fsize = 0; - for (int i = 0; i < gps->totpoints; i++, pt++) { - /* weight paint */ - if (is_weight_paint) { - float weight = (dvert && dvert->dw && (vgindex > -1)) ? defvert_find_weight(dvert, vgindex) : - 0.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; - } - /* weight paint */ - else if (is_vertex_paint) { - if (pt->flag & GP_SPOINT_SELECT) { - copy_v4_v4(fcolor, selectColor); - fsize = vsize; - } - else { - copy_v4_v4(fcolor, unselectColor); - fsize = bsize; - } - } - 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 ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { - ARRAY_SET_ITEMS(fcolor, linecolor[0], linecolor[1], linecolor[2], selectColor[3]); - mul_v4_fl(fcolor, 0.9f); - copy_v4_v4(fcolor, fcolor); - fsize = vsize * 0.8f; - } - else if (pt->flag & GP_SPOINT_SELECT) { - copy_v4_v4(fcolor, selectColor); - fsize = vsize; - } - else { - copy_v4_v4(fcolor, unselectColor); - fsize = bsize; - } - } - - GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor); - GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize); - GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x); - be->vbo_len++; - if (gps->dvert != NULL) { - dvert++; - } - } -} - -/* Draw lines for strokes being edited */ -void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, - bGPDstroke *gps, - float alpha, - const bool hide_select) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - Object *ob = draw_ctx->obact; - bGPdata *gpd = ob->data; - const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); - const int fake_point = (gps->totpoints == 1) ? 1 : 0; - - 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); - - if (be->vbo == NULL) { - gpencil_elem_format_ensure(be); - be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - - be->vbo = GPU_vertbuf_create_with_format(be->format); - GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex); - be->vbo_len = 0; - } - gpencil_vbo_ensure_size(be, gps->totpoints + fake_point); - - /* Draw all the stroke lines (selected or not) */ - bGPDspoint *pt = gps->points; - MDeformVert *dvert = gps->dvert; - - float fcolor[4]; - for (int i = 0; i < gps->totpoints; i++, pt++) { - /* weight paint */ - if (is_weight_paint) { - float weight = (dvert && dvert->dw && (vgindex > -1)) ? defvert_find_weight(dvert, vgindex) : - 0.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) && (!hide_select)) { - copy_v4_v4(fcolor, selectColor); - } - else { - copy_v4_v4(fcolor, linecolor); - } - } - - GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor); - GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x); - be->vbo_len++; - - if (gps->dvert != NULL) { - dvert++; - } - } - /* If only 1 point in the stroke, add a point moved slightly. */ - if (fake_point > 0) { - float fpt[3]; - pt = &gps->points[0]; - mul_v3_v3fl(fpt, &pt->x, 1.001f); - GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor); - GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, fpt); - be->vbo_len++; - } -} - -static void set_grid_point(GPUVertBuf *vbo, - int idx, - const float col_grid[4], - uint pos_id, - uint color_id, - float v1, - float v2, - const int axis) -{ - GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid); - - float pos[3]; - /* Set the grid in the selected axis */ - switch (axis) { - case GP_LOCKAXIS_X: { - ARRAY_SET_ITEMS(pos, 0.0f, v1, v2); - break; - } - case GP_LOCKAXIS_Y: { - ARRAY_SET_ITEMS(pos, v1, 0.0f, v2); - break; - } - case GP_LOCKAXIS_Z: - default: /* view aligned */ - { - ARRAY_SET_ITEMS(pos, v1, v2, 0.0f); - break; - } - } - - GPU_vertbuf_attr_set(vbo, pos_id, idx, pos); -} - -/* Draw grid lines */ -GPUBatch *gpencil_get_grid(Object *ob) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - ToolSettings *ts = scene->toolsettings; - View3D *v3d = draw_ctx->v3d; - bGPdata *gpd = (bGPdata *)ob->data; - const bool do_center = (gpd->grid.lines <= 0) ? false : true; - - float col_grid[4]; - - /* verify we have something to draw and valid values */ - if (gpd->grid.scale[0] == 0.0f) { - gpd->grid.scale[0] = 1.0f; - } - if (gpd->grid.scale[1] == 0.0f) { - gpd->grid.scale[1] = 1.0f; - } - - if (v3d->overlay.gpencil_grid_opacity < 0.1f) { - v3d->overlay.gpencil_grid_opacity = 0.1f; - } - - /* set color */ - copy_v3_v3(col_grid, gpd->grid.color); - col_grid[3] = v3d->overlay.gpencil_grid_opacity; - - const int axis = ts->gp_sculpt.lock_axis; - - const char *grid_unit = NULL; - const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines; - const float grid_w = gpd->grid.scale[0] * ED_scene_grid_scale(scene, &grid_unit); - const float grid_h = gpd->grid.scale[1] * ED_scene_grid_scale(scene, &grid_unit); - const float space_w = (grid_w / gridlines); - const float space_h = (grid_h / gridlines); - const float offset[2] = {gpd->grid.offset[0], gpd->grid.offset[1]}; - - 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_w = a * space_w; - const float line_h = a * space_h; - - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], -line_h + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], -line_h + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], +line_h + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], +line_h + offset[1], axis); - idx++; - - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], -grid_h + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], +grid_h + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], -grid_h + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], +grid_h + offset[1], axis); - idx++; - } - /* center lines */ - if (do_center) { - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], 0.0f + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], 0.0f + offset[1], axis); - idx++; - - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], -grid_h + offset[1], axis); - idx++; - set_grid_point( - vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], +grid_h + offset[1], 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_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c new file mode 100644 index 00000000000..97e5a44f0ab --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -0,0 +1,506 @@ +/* + * 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. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "DNA_light_types.h" + +#include "BKE_image.h" + +#include "BLI_hash.h" +#include "BLI_math_color.h" +#include "BLI_memblock.h" + +#include "GPU_uniformbuffer.h" + +#include "IMB_imbuf_types.h" + +#include "gpencil_engine.h" + +GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd) +{ + GPENCIL_LightPool *lightpool = BLI_memblock_alloc(pd->gp_light_pool); + lightpool->light_used = 0; + /* Tag light list end. */ + lightpool->light_data[0].color[0] = -1.0; + if (lightpool->ubo == NULL) { + lightpool->ubo = GPU_uniformbuffer_create(sizeof(lightpool->light_data), NULL, NULL); + } + pd->last_light_pool = lightpool; + return lightpool; +} + +static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_PrivateData *pd) +{ + GPENCIL_MaterialPool *matpool = BLI_memblock_alloc(pd->gp_material_pool); + matpool->next = NULL; + matpool->used_count = 0; + if (matpool->ubo == NULL) { + matpool->ubo = GPU_uniformbuffer_create(sizeof(matpool->mat_data), NULL, NULL); + } + pd->last_material_pool = matpool; + return matpool; +} + +static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_premult) +{ + ImBuf *ibuf; + ImageUser iuser = {NULL}; + struct GPUTexture *gpu_tex = NULL; + void *lock; + + iuser.ok = true; + ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock); + + if (ibuf != NULL && ibuf->rect != NULL) { + gpu_tex = GPU_texture_from_blender(image, &iuser, ibuf, GL_TEXTURE_2D); + *r_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL); + } + BKE_image_release_ibuf(image, ibuf, lock); + + return gpu_tex; +} + +#if 0 /* Old implementation. Reference for doing versioning code. TODO remove. */ +static void gpencil_uv_transform_get(const float ofs[2], + const float scale[2], + const float rotation, + float r_uvmat[3][2]) +{ + /* OPTI this could use 3x2 matrices and reduce the number of operations drastically. */ + float mat[4][4]; + float scale_v3[3] = {scale[0], scale[1], 0.0}; + /* Scale */ + size_to_mat4(mat, scale_v3); + /* Offset to center. */ + translate_m4(mat, 0.5f + ofs[0], 0.5f + ofs[1], 0.0f); + /* Rotation; */ + rotate_m4(mat, 'Z', -rotation); + /* Translate. */ + translate_m4(mat, -0.5f, -0.5f, 0.0f); + /* Convert to 3x2 */ + copy_v2_v2(r_uvmat[0], mat[0]); + copy_v2_v2(r_uvmat[1], mat[1]); + copy_v2_v2(r_uvmat[2], mat[3]); +} +#endif + +static void gpencil_uv_transform_get(const float ofs[2], + const float scale[2], + const float rotation, + float r_uvmat[3][2]) +{ + /* OPTI this could use 3x2 matrices and reduce the number of operations drastically. */ + float mat[4][4]; + unit_m4(mat); + /* Offset to center. */ + translate_m4(mat, 0.5f, 0.5f, 0.0f); + /* Reversed order. */ + rescale_m4(mat, (float[3]){1.0f / scale[0], 1.0f / scale[1], 0.0}); + rotate_m4(mat, 'Z', -rotation); + translate_m4(mat, ofs[0], ofs[1], 0.0f); + /* Convert to 3x2 */ + copy_v2_v2(r_uvmat[0], mat[0]); + copy_v2_v2(r_uvmat[1], mat[1]); + copy_v2_v2(r_uvmat[2], mat[3]); +} + +#define HSV_SATURATION 0.5 +#define HSV_VALUE 0.8 + +static void gpencil_object_random_color_get(const Object *ob, float r_color[3]) +{ + /* Duplicated from workbench_material.c */ + uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); + if (ob->id.lib) { + hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name); + } + float hue = BLI_hash_int_01(hash); + float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; + hsv_to_rgb_v(hsv, r_color); +} + +static void gpencil_shade_color(float color[3]) +{ + /* This is scene refered color, not gamma corrected and not per perceptual. + * So we lower the threshold a bit. (1.0 / 3.0) */ + if (color[0] + color[1] + color[2] > 1.1) { + add_v3_fl(color, -0.25f); + } + else { + add_v3_fl(color, 0.15f); + } + CLAMP3(color, 0.0f, 1.0f); +} + +/* Apply all overrides from the solid viewport mode to the GPencil material. */ +static MaterialGPencilStyle *gpencil_viewport_material_overrides(GPENCIL_PrivateData *pd, + Object *ob, + int color_type, + MaterialGPencilStyle *gp_style) +{ + static MaterialGPencilStyle gp_style_tmp; + + switch (color_type) { + case V3D_SHADING_MATERIAL_COLOR: + copy_v4_v4(gp_style_tmp.stroke_rgba, gp_style->stroke_rgba); + copy_v4_v4(gp_style_tmp.fill_rgba, gp_style->fill_rgba); + gp_style = &gp_style_tmp; + gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; + gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; + break; + case V3D_SHADING_TEXTURE_COLOR: + memcpy(&gp_style_tmp, gp_style, sizeof(*gp_style)); + gp_style = &gp_style_tmp; + if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) { + copy_v4_fl(gp_style->stroke_rgba, 1.0f); + gp_style->mix_stroke_factor = 0.0f; + } + + if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) { + copy_v4_fl(gp_style->fill_rgba, 1.0f); + gp_style->mix_factor = 0.0f; + } + else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) { + /* gp_style->fill_rgba is needed for correct gradient. */ + gp_style->mix_factor = 0.0f; + } + break; + case V3D_SHADING_RANDOM_COLOR: + gp_style = &gp_style_tmp; + gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; + gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; + gpencil_object_random_color_get(ob, gp_style->fill_rgba); + gp_style->fill_rgba[3] = 1.0f; + copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba); + gpencil_shade_color(gp_style->stroke_rgba); + break; + case V3D_SHADING_SINGLE_COLOR: + gp_style = &gp_style_tmp; + gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; + gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; + copy_v3_v3(gp_style->fill_rgba, pd->v3d_single_color); + gp_style->fill_rgba[3] = 1.0f; + copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba); + gpencil_shade_color(gp_style->stroke_rgba); + break; + case V3D_SHADING_OBJECT_COLOR: + gp_style = &gp_style_tmp; + gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; + gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; + copy_v4_v4(gp_style->fill_rgba, ob->color); + copy_v4_v4(gp_style->stroke_rgba, ob->color); + gpencil_shade_color(gp_style->stroke_rgba); + break; + case V3D_SHADING_VERTEX_COLOR: + gp_style = &gp_style_tmp; + gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID; + gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID; + copy_v4_fl(gp_style->fill_rgba, 1.0f); + copy_v4_fl(gp_style->stroke_rgba, 1.0f); + break; + default: + break; + } + return gp_style; +} + +/** + * Creates a linked list of material pool containing all materials assigned for a given object. + * We merge the material pools together if object does not contain a huge amount of materials. + * Also return an offset to the first material of the object in the ubo. + **/ +GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs) +{ + GPENCIL_MaterialPool *matpool = pd->last_material_pool; + + int mat_len = max_ii(1, ob->totcol); + + bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GP_MATERIAL_BUFFER_LEN); + + if (reuse_matpool) { + /* Share the matpool with other objects. Return offset to first material. */ + *ofs = matpool->used_count; + } + else { + matpool = gpencil_material_pool_add(pd); + *ofs = 0; + } + + /* Force vertex color in solid mode with vertex paint mode. Same behavior as meshes. */ + bGPdata *gpd = (bGPdata *)ob->data; + int color_type = (pd->v3d_color_type != -1 && GPENCIL_VERTEX_MODE(gpd)) ? + V3D_SHADING_VERTEX_COLOR : + pd->v3d_color_type; + + GPENCIL_MaterialPool *pool = matpool; + for (int i = 0; i < mat_len; i++) { + if ((i > 0) && (pool->used_count == GP_MATERIAL_BUFFER_LEN)) { + pool->next = gpencil_material_pool_add(pd); + pool = pool->next; + } + int mat_id = pool->used_count++; + + gpMaterial *mat_data = &pool->mat_data[mat_id]; + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, i + 1); + + if (gp_style->mode == GP_MATERIAL_MODE_LINE) { + mat_data->flag = 0; + } + else { + switch (gp_style->alignment_mode) { + case GP_MATERIAL_FOLLOW_PATH: + mat_data->flag = GP_STROKE_ALIGNMENT_STROKE; + break; + case GP_MATERIAL_FOLLOW_OBJ: + mat_data->flag = GP_STROKE_ALIGNMENT_OBJECT; + break; + case GP_MATERIAL_FOLLOW_FIXED: + default: + mat_data->flag = GP_STROKE_ALIGNMENT_FIXED; + break; + } + + if (gp_style->mode == GP_MATERIAL_MODE_DOT) { + mat_data->flag |= GP_STROKE_DOTS; + } + } + + if ((gp_style->mode != GP_MATERIAL_MODE_LINE) || + (gp_style->flag & GP_MATERIAL_DISABLE_STENCIL)) { + mat_data->flag |= GP_STROKE_OVERLAP; + } + + gp_style = gpencil_viewport_material_overrides(pd, ob, color_type, gp_style); + + /* Stroke Style */ + if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) { + bool premul; + pool->tex_stroke[mat_id] = gpencil_image_texture_get(gp_style->sima, &premul); + mat_data->flag |= pool->tex_stroke[mat_id] ? GP_STROKE_TEXTURE_USE : 0; + mat_data->flag |= premul ? GP_STROKE_TEXTURE_PREMUL : 0; + copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba); + mat_data->stroke_texture_mix = 1.0f - gp_style->mix_stroke_factor; + mat_data->stroke_u_scale = 500.0f / gp_style->texture_pixsize; + } + else /* if (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_SOLID) */ { + pool->tex_stroke[mat_id] = NULL; + mat_data->flag &= ~GP_STROKE_TEXTURE_USE; + copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba); + mat_data->stroke_texture_mix = 0.0f; + } + + /* Fill Style */ + if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) { + bool use_clip = (gp_style->flag & GP_MATERIAL_TEX_CLAMP) != 0; + bool premul; + pool->tex_fill[mat_id] = gpencil_image_texture_get(gp_style->ima, &premul); + mat_data->flag |= pool->tex_fill[mat_id] ? GP_FILL_TEXTURE_USE : 0; + mat_data->flag |= premul ? GP_FILL_TEXTURE_PREMUL : 0; + mat_data->flag |= use_clip ? GP_FILL_TEXTURE_CLIP : 0; + gpencil_uv_transform_get(gp_style->texture_offset, + gp_style->texture_scale, + gp_style->texture_angle, + mat_data->fill_uv_transform); + copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba); + mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor; + } + else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) { + bool use_radial = (gp_style->gradient_type == GP_MATERIAL_GRADIENT_RADIAL); + pool->tex_fill[mat_id] = NULL; + mat_data->flag |= GP_FILL_GRADIENT_USE; + mat_data->flag |= use_radial ? GP_FILL_GRADIENT_RADIAL : 0; + gpencil_uv_transform_get(gp_style->texture_offset, + gp_style->texture_scale, + gp_style->texture_angle, + mat_data->fill_uv_transform); + copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba); + copy_v4_v4(mat_data->fill_mix_color, gp_style->mix_rgba); + mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor; + if (gp_style->flag & GP_MATERIAL_FLIP_FILL) { + swap_v4_v4(mat_data->fill_color, mat_data->fill_mix_color); + } + } + else /* if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) */ { + pool->tex_fill[mat_id] = NULL; + copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba); + mat_data->fill_texture_mix = 0.0f; + } + } + + return matpool; +} + +void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool, + int mat_id, + GPUTexture **r_tex_stroke, + GPUTexture **r_tex_fill, + GPUUniformBuffer **r_ubo_mat) +{ + GPENCIL_MaterialPool *matpool = first_pool; + int pool_id = mat_id / GP_MATERIAL_BUFFER_LEN; + for (int i = 0; i < pool_id; i++) { + matpool = matpool->next; + } + mat_id = mat_id % GP_MATERIAL_BUFFER_LEN; + *r_ubo_mat = matpool->ubo; + if (r_tex_fill) { + *r_tex_fill = matpool->tex_fill[mat_id]; + } + if (r_tex_stroke) { + *r_tex_stroke = matpool->tex_stroke[mat_id]; + } +} + +void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]) +{ + if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) { + return; + } + + gpLight *gp_light = &lightpool->light_data[lightpool->light_used]; + gp_light->type = GP_LIGHT_TYPE_AMBIENT; + copy_v3_v3(gp_light->color, color); + lightpool->light_used++; + + if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) { + /* Tag light list end. */ + gp_light[1].color[0] = -1.0f; + } +} + +static float light_power_get(const Light *la) +{ + if (la->type == LA_AREA) { + return 1.0f / (4.0f * M_PI); + } + else if (la->type == LA_SPOT || la->type == LA_LOCAL) { + return 1.0f / (4.0f * M_PI * M_PI); + } + else { + return 1.0f / M_PI; + } +} + +void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob) +{ + Light *la = (Light *)ob->data; + + if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) { + return; + } + + gpLight *gp_light = &lightpool->light_data[lightpool->light_used]; + float(*mat)[4] = (float(*)[4])gp_light->right; + + if (la->type == LA_SPOT) { + copy_m4_m4(mat, ob->imat); + gp_light->type = GP_LIGHT_TYPE_SPOT; + gp_light->spotsize = cosf(la->spotsize * 0.5f); + gp_light->spotblend = (1.0f - gp_light->spotsize) * la->spotblend; + } + else if (la->type == LA_AREA) { + /* Simulate area lights using a spot light. */ + normalize_m4_m4(mat, ob->obmat); + invert_m4(mat); + gp_light->type = GP_LIGHT_TYPE_SPOT; + gp_light->spotsize = cosf(M_PI * 0.5f); + gp_light->spotblend = (1.0f - gp_light->spotsize) * 1.0f; + } + else if (la->type == LA_SUN) { + normalize_v3_v3(gp_light->forward, ob->obmat[2]); + gp_light->type = GP_LIGHT_TYPE_SUN; + } + else { + gp_light->type = GP_LIGHT_TYPE_POINT; + } + copy_v4_v4(gp_light->position, ob->obmat[3]); + copy_v3_v3(gp_light->color, &la->r); + mul_v3_fl(gp_light->color, la->energy * light_power_get(la)); + + lightpool->light_used++; + + if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) { + /* Tag light list end. */ + gp_light[1].color[0] = -1.0f; + } +} + +/** + * Creates a single pool containing all lights assigned (light linked) for a given object. + **/ +GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *UNUSED(ob)) +{ + GPENCIL_LightPool *lightpool = pd->last_light_pool; + + if (lightpool == NULL) { + lightpool = gpencil_light_pool_add(pd); + } + /* TODO */ + // gpencil_light_pool_populate(lightpool, ob); + + return lightpool; +} + +void gpencil_material_pool_free(void *storage) +{ + GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage; + DRW_UBO_FREE_SAFE(matpool->ubo); +} + +void gpencil_light_pool_free(void *storage) +{ + GPENCIL_LightPool *lightpool = (GPENCIL_LightPool *)storage; + DRW_UBO_FREE_SAFE(lightpool->ubo); +} + +static void gpencil_view_layer_data_free(void *storage) +{ + GPENCIL_ViewLayerData *vldata = (GPENCIL_ViewLayerData *)storage; + + BLI_memblock_destroy(vldata->gp_light_pool, gpencil_light_pool_free); + BLI_memblock_destroy(vldata->gp_material_pool, gpencil_material_pool_free); + BLI_memblock_destroy(vldata->gp_object_pool, NULL); + BLI_memblock_destroy(vldata->gp_layer_pool, NULL); + BLI_memblock_destroy(vldata->gp_vfx_pool, NULL); +} + +GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void) +{ + GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure( + &draw_engine_gpencil_type, gpencil_view_layer_data_free); + + /* NOTE(fclem) Putting this stuff in viewlayer means it is shared by all viewports. + * For now it is ok, but in the future, it could become a problem if we implement + * the caching system. */ + if (*vldata == NULL) { + *vldata = MEM_callocN(sizeof(**vldata), "GPENCIL_ViewLayerData"); + + (*vldata)->gp_light_pool = BLI_memblock_create(sizeof(GPENCIL_LightPool)); + (*vldata)->gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool)); + (*vldata)->gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject)); + (*vldata)->gp_layer_pool = BLI_memblock_create(sizeof(GPENCIL_tLayer)); + (*vldata)->gp_vfx_pool = BLI_memblock_create(sizeof(GPENCIL_tVfx)); + } + + return *vldata; +} diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c deleted file mode 100644 index f2fc77dccf6..00000000000 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ /dev/null @@ -1,2128 +0,0 @@ -/* - * 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. - * - * Copyright 2017, Blender Foundation. - */ - -/** \file - * \ingroup draw - */ - -#include "DRW_render.h" - -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" -#include "BKE_image.h" -#include "BKE_material.h" -#include "BKE_paint.h" - -#include "BLI_hash.h" - -#include "ED_gpencil.h" - -#include "DNA_gpencil_types.h" -#include "DNA_material_types.h" -#include "DNA_view3d_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" - -#include "UI_resources.h" - -/* fill type to communicate to shader */ -#define SOLID 0 -#define GRADIENT 1 -#define RADIAL 2 -#define CHECKER 3 -#define TEXTURE 4 -#define PATTERN 5 - -/* Verify if must fade object or not. */ -static bool gpencil_fade_object_check(GPENCIL_StorageList *stl, Object *ob) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - const bool is_overlay = (bool)((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && - (v3d->gp_flag & V3D_GP_SHOW_PAPER)); - - if ((!is_overlay) || (ob == draw_ctx->obact) || - ((v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL) == 0) || - (v3d->overlay.gpencil_paper_opacity == 1.0f)) { - return false; - } - - const bool playing = stl->storage->is_playing; - const bool is_render = (bool)stl->storage->is_render; - const bool is_mat_preview = (bool)stl->storage->is_mat_preview; - const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth()); - - return (bool)((!is_render) && (!playing) && (!is_mat_preview) && (!is_select)); -} - -/* Define Fade layer uniforms. */ -static void gpencil_set_fade_layer_uniforms( - GPENCIL_StorageList *stl, DRWShadingGroup *grp, Object *ob, bGPDlayer *gpl, const bool skip) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true; - const bool is_fade = (v3d) && (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) && - (draw_ctx->obact) && (draw_ctx->obact == ob) && - ((gpl->flag & GP_LAYER_ACTIVE) == 0); - - const bool playing = stl->storage->is_playing; - const bool is_render = (bool)stl->storage->is_render; - const bool is_mat_preview = (bool)stl->storage->is_mat_preview; - const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth()); - - /* If drawing or not fading layer, skip. */ - if ((!overlay) || (skip) || (!is_fade) || (is_render) || (playing) || (is_mat_preview) || - (is_select)) { - DRW_shgroup_uniform_int_copy(grp, "fade_layer", 0); - return; - } - - /* If layer is above active, use alpha (2) if below use mix with background (1). */ - if (stl->storage->is_ontop) { - DRW_shgroup_uniform_int_copy(grp, "fade_layer", 2); - } - else { - DRW_shgroup_uniform_int_copy(grp, "fade_layer", 1); - } - if (v3d) { - DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1); - DRW_shgroup_uniform_float(grp, "fade_layer_factor", &v3d->overlay.gpencil_fade_layer, 1); - } -} - -/* Define Fade object uniforms. */ -static void gpencil_set_fade_ob_uniforms(View3D *v3d, DRWShadingGroup *grp, bool status) -{ - DRW_shgroup_uniform_bool_copy(grp, "fade_ob", status); - if (v3d) { - DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1); - DRW_shgroup_uniform_float(grp, "fade_ob_factor", &v3d->overlay.gpencil_paper_opacity, 1); - } -} - -/* Get number of vertex for using in GPU VBOs */ -static void gpencil_calc_vertex(GPENCIL_StorageList *stl, - tGPencilObjectCache *cache_ob, - GpencilBatchCache *cache, - bGPdata *gpd) -{ - if ((!cache->is_dirty) || (gpd == NULL)) { - return; - } - - Object *ob = cache_ob->ob; - const bool main_onion = stl->storage->is_main_onion; - const bool playing = stl->storage->is_playing; - const bool overlay = stl->storage->is_main_overlay; - const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && - main_onion && !playing && gpencil_onion_active(gpd); - - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - - /* Onion skinning. */ - const int step = gpd->gstep; - const int mode = gpd->onion_mode; - const short onion_keytype = gpd->onion_keytype; - - cache_ob->tot_vertex = 0; - cache_ob->tot_triangles = 0; - int idx_eval = 0; - - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - bGPDframe *init_gpf = NULL; - const bool is_onion = ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN)); - if (gpl->flag & GP_LAYER_HIDE) { - idx_eval++; - continue; - } - - /* Relative onion mode needs to find the frame range before. */ - int frame_from = -9999; - int frame_to = 9999; - if ((is_onion) && (mode == GP_ONION_MODE_RELATIVE)) { - /* 1) Found first Frame. */ - int idx = 0; - if (gpl->actframe) { - for (bGPDframe *gf = gpl->actframe->prev; gf; gf = gf->prev) { - idx++; - frame_from = gf->framenum; - if (idx >= step) { - break; - } - } - /* 2) Found last Frame. */ - idx = 0; - for (bGPDframe *gf = gpl->actframe->next; gf; gf = gf->next) { - idx++; - frame_to = gf->framenum; - if (idx >= gpd->gstep_next) { - break; - } - } - } - } - - /* If multiedit or onion skin need to count all frames of the layer. */ - if ((is_multiedit) || (is_onion)) { - init_gpf = gpl->frames.first; - } - else { - init_gpf = &ob->runtime.gpencil_evaluated_frames[idx_eval]; - } - - if (init_gpf == NULL) { - continue; - } - - for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - if (!is_onion) { - if ((!is_multiedit) || - ((is_multiedit) && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) { - cache_ob->tot_vertex += gps->totpoints + 3; - cache_ob->tot_triangles += gps->totpoints - 1; - } - } - else { - bool select = ((is_multiedit) && - ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT))); - - if (!select) { - /* Only selected frames. */ - if ((mode == GP_ONION_MODE_SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) { - continue; - } - /* Verify keyframe type. */ - if ((onion_keytype > -1) && (gpf->key_type != onion_keytype)) { - continue; - } - /* Absolute range. */ - if (mode == GP_ONION_MODE_ABSOLUTE) { - if ((gpl->actframe) && (abs(gpl->actframe->framenum - gpf->framenum) > step)) { - continue; - } - } - /* Relative range. */ - if (mode == GP_ONION_MODE_RELATIVE) { - if ((gpf->framenum < frame_from) || (gpf->framenum > frame_to)) { - continue; - } - } - } - - cache_ob->tot_vertex += gps->totpoints + 3; - cache_ob->tot_triangles += gps->totpoints - 1; - } - } - - /* If not multiframe nor Onion skin, don't need follow counting. */ - if ((!is_multiedit) && (!is_onion)) { - break; - } - } - idx_eval++; - } - - cache->b_fill.tot_vertex = cache_ob->tot_triangles * 3; - cache->b_stroke.tot_vertex = cache_ob->tot_vertex; - cache->b_point.tot_vertex = cache_ob->tot_vertex; - cache->b_edit.tot_vertex = cache_ob->tot_vertex; - cache->b_edlin.tot_vertex = cache_ob->tot_vertex; -} - -/* 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; -} - -/* recalc the internal geometry caches for fill and uvs */ -static void gpencil_recalc_geometry_caches(Object *ob, - bGPDlayer *gpl, - MaterialGPencilStyle *gp_style, - bGPDstroke *gps) -{ - if (gps->flag & GP_STROKE_RECALC_GEOMETRY) { - /* 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->flag & GP_STYLE_FILL_SHOW) && - ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0) || - (gpl->blend_mode != eGplBlendMode_Regular))) { - BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps); - } - } - - /* calc uv data along the stroke */ - ED_gpencil_calc_stroke_uv(ob, gps); - - /* clear flag */ - gps->flag &= ~GP_STROKE_RECALC_GEOMETRY; - } -} - -static void set_wireframe_color(Object *ob, - bGPDlayer *gpl, - View3D *v3d, - GPENCIL_StorageList *stl, - MaterialGPencilStyle *gp_style, - int id, - const bool is_fill) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - World *world = draw_ctx->scene->world; - - float color[4]; - if (((gp_style->stroke_rgba[3] < GPENCIL_ALPHA_OPACITY_THRESH) || - (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0))) && - (gp_style->fill_rgba[3] >= GPENCIL_ALPHA_OPACITY_THRESH)) { - copy_v4_v4(color, gp_style->fill_rgba); - } - else { - copy_v4_v4(color, gp_style->stroke_rgba); - } - - /* wire color */ - if ((v3d) && (id > -1)) { - const char type = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ? - v3d->shading.wire_color_type : - v3d->shading.color_type); - /* if fill and wire, use background color */ - if ((is_fill) && (stl->shgroups[id].shading_type[0] == OB_WIRE)) { - if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_THEME) { - UI_GetThemeColor4fv(TH_BACK, stl->shgroups[id].wire_color); - stl->shgroups[id].wire_color[3] = 1.0f; - } - else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) { - color[0] = world->horr; - color[1] = world->horg; - color[2] = world->horb; - color[3] = 1.0f; - linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color); - } - else { - copy_v3_v3(color, v3d->shading.background_color); - color[3] = 1.0f; - linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color); - } - return; - } - - /* strokes */ - switch (type) { - case V3D_SHADING_SINGLE_COLOR: { - if (stl->shgroups[id].shading_type[0] == OB_WIRE) { - UI_GetThemeColor4fv(TH_WIRE, color); - } - else { - copy_v3_v3(color, v3d->shading.single_color); - } - color[3] = 1.0f; - linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color); - break; - } - case V3D_SHADING_OBJECT_COLOR: { - copy_v4_v4(color, ob->color); - color[3] = 1.0f; - linearrgb_to_srgb_v4(stl->shgroups[id].wire_color, color); - break; - } - case V3D_SHADING_RANDOM_COLOR: { - uint gpl_hash = 1; - uint ob_hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); - if (gpl) { - gpl_hash = BLI_ghashutil_strhash_p_murmur(gpl->info); - } - - float hue = BLI_hash_int_01(ob_hash * gpl_hash); - float hsv[3] = {hue, 0.40f, 0.8f}; - float wire_col[3]; - hsv_to_rgb_v(hsv, &wire_col[0]); - - copy_v3_v3(stl->shgroups[id].wire_color, wire_col); - stl->shgroups[id].wire_color[3] = 1.0f; - break; - } - default: { - copy_v4_v4(stl->shgroups[id].wire_color, color); - break; - } - } - } - else { - copy_v4_v4(stl->shgroups[id].wire_color, color); - } - - /* if solid, the alpha must be set to alpha */ - if (stl->shgroups[id].shading_type[0] == OB_SOLID) { - stl->shgroups[id].wire_color[3] = 1.0f; - } -} - -/* create shading group for filling */ -static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - DRWPass *pass, - GPUShader *shader, - Object *ob, - float (*obmat)[4], - bGPdata *gpd, - bGPDlayer *gpl, - MaterialGPencilStyle *gp_style, - int id, - const int shading_type[2]) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - - /* e_data.gpencil_fill_sh */ - DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); - - DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat); - - 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_CHECKER: - stl->shgroups[id].fill_style = CHECKER; - 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); - DRW_shgroup_uniform_float(grp, "layer_opacity", &gpl->opacity, 1); - - stl->shgroups[id].texture_mix = gp_style->flag & GP_STYLE_FILL_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); - - stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE; - DRW_shgroup_uniform_int(grp, "xraymode", &stl->shgroups[id].xray_mode, 1); - DRW_shgroup_uniform_int(grp, "drawmode", (const int *)&gpd->draw_mode, 1); - - /* viewport x-ray */ - stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray; - DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1); - - /* shading type */ - stl->shgroups[id].shading_type[0] = GPENCIL_USE_SOLID(stl) ? (int)OB_RENDER : shading_type[0]; - if (v3d) { - stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ? - v3d->shading.wire_color_type : - v3d->shading.color_type); - } - - DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2); - - /* Fade layer uniforms. */ - gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false); - - /* Fade object uniforms. */ - gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob)); - - /* wire color */ - set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, true); - DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1); - - /* image texture */ - if ((gp_style->flag & GP_STYLE_FILL_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, ibuf, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "myTexture", texture); - DRW_shgroup_uniform_bool_copy( - grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL)); - - 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; -} - -/* check if some onion is enabled */ -bool gpencil_onion_active(bGPdata *gpd) -{ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->onion_flag & GP_LAYER_ONIONSKIN) { - return true; - } - } - return false; -} - -/* create shading group for strokes */ -DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - DRWPass *pass, - GPUShader *shader, - Object *ob, - float (*obmat)[4], - bGPdata *gpd, - bGPDlayer *gpl, - bGPDstroke *gps, - MaterialGPencilStyle *gp_style, - int id, - bool onion, - const float scale, - const int shading_type[2]) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - const float *viewport_size = DRW_viewport_size_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - - /* 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_mat4(grp, "gpModelMatrix", obmat); - - /* avoid wrong values */ - if ((gpd) && (gpd->pixfactor == 0.0f)) { - gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; - } - - /* object scale and depth */ - if ((ob) && (id > -1)) { - stl->shgroups[id].obj_scale = scale; - 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); - - stl->shgroups[id].caps_mode[0] = gps->caps[0]; - stl->shgroups[id].caps_mode[1] = gps->caps[1]; - DRW_shgroup_uniform_int(grp, "caps_mode", &stl->shgroups[id].caps_mode[0], 2); - - stl->shgroups[id].gradient_f = gps->gradient_f; - copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s); - DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1); - - /* viewport x-ray */ - stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray; - DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1); - - stl->shgroups[id].shading_type[0] = (GPENCIL_USE_SOLID(stl) || onion) ? (int)OB_RENDER : - shading_type[0]; - if (v3d) { - stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ? - v3d->shading.wire_color_type : - v3d->shading.color_type); - } - DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2); - - /* Fade layer uniforms. */ - gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false); - - /* Fade object uniforms. */ - gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob)); - - /* wire color */ - set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false); - DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1); - - /* mix stroke factor */ - stl->shgroups[id].mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ? - gp_style->mix_stroke_factor : - 0.0f; - DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->shgroups[id].mix_stroke_factor, 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); - } - const int zero[2] = {0, 0}; - DRW_shgroup_uniform_int(grp, "caps_mode", &zero[0], 2); - - DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1); - - /* viewport x-ray */ - DRW_shgroup_uniform_int(grp, "viewport_xray", &stl->storage->is_xray, 1); - DRW_shgroup_uniform_int(grp, "shading_type", (const int *)&stl->storage->shade_render, 2); - - /* mix stroke factor */ - stl->storage->mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ? - gp_style->mix_stroke_factor : - 0.0f; - DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->storage->mix_stroke_factor, 1); - } - - DRW_shgroup_uniform_vec4(grp, "colormix", gp_style->stroke_rgba, 1); - - if ((gpd) && (id > -1)) { - stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE; - DRW_shgroup_uniform_int(grp, "xraymode", &stl->shgroups[id].xray_mode, 1); - } - else { - /* for drawing always on predefined z-depth */ - DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1); - } - - /* Fade layer uniforms. */ - gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true); - - /* Fade object uniforms. */ - gpencil_set_fade_ob_uniforms(v3d, grp, false); - - /* 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, ibuf, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "myTexture", texture); - DRW_shgroup_uniform_bool_copy( - grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL)); - - 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 points */ -static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - DRWPass *pass, - GPUShader *shader, - Object *ob, - float (*obmat)[4], - bGPdata *gpd, - bGPDlayer *gpl, - bGPDstroke *gps, - MaterialGPencilStyle *gp_style, - int id, - bool onion, - const float scale, - const int shading_type[2]) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - const float *viewport_size = DRW_viewport_size_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - - /* 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_mat4(grp, "gpModelMatrix", obmat); - - /* avoid wrong values */ - if ((gpd) && (gpd->pixfactor == 0.0f)) { - gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; - } - - /* object scale and depth */ - if ((ob) && (id > -1)) { - stl->shgroups[id].obj_scale = scale; - 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); - - stl->shgroups[id].gradient_f = gps->gradient_f; - copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s); - DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1); - DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->shgroups[id].gradient_s, 1); - - /* viewport x-ray */ - stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray; - DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1); - - stl->shgroups[id].shading_type[0] = (GPENCIL_USE_SOLID(stl) || onion) ? (int)OB_RENDER : - shading_type[0]; - if (v3d) { - stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ? - v3d->shading.wire_color_type : - v3d->shading.color_type); - } - DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2); - - /* Fade layer uniforms. */ - gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false); - - /* Fade object uniforms. */ - gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob)); - - /* wire color */ - set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false); - DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1); - - /* mix stroke factor */ - stl->shgroups[id].mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ? - gp_style->mix_stroke_factor : - 0.0f; - DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->shgroups[id].mix_stroke_factor, 1); - - /* lock rotation of dots and boxes */ - stl->shgroups[id].alignment_mode = gp_style->alignment_mode; - DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->shgroups[id].alignment_mode, 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); - } - - DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1); - DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->storage->gradient_s, 1); - - /* viewport x-ray */ - DRW_shgroup_uniform_int(grp, "viewport_xray", &stl->storage->is_xray, 1); - DRW_shgroup_uniform_int(grp, "shading_type", (const int *)&stl->storage->shade_render, 2); - - /* mix stroke factor */ - stl->storage->mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ? - gp_style->mix_stroke_factor : - 0.0f; - DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->storage->mix_stroke_factor, 1); - - /* lock rotation of dots and boxes */ - DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->storage->alignment_mode, 1); - } - - DRW_shgroup_uniform_vec4(grp, "colormix", gp_style->stroke_rgba, 1); - - if ((gpd) && (id > -1)) { - stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE; - DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&stl->shgroups[id].xray_mode, 1); - } - else { - /* for drawing always on predefined z-depth */ - DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1); - } - - /* Fade layer uniforms. */ - gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true); - - /* Fade object uniforms. */ - gpencil_set_fade_ob_uniforms(v3d, grp, false); - - /* 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, ibuf, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "myTexture", texture); - DRW_shgroup_uniform_bool_copy( - grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL)); - - 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; -} - -/* Get vertex Paint factor */ -float gpencil_get_vertex_paint_factor(View3D *v3d) -{ - if (v3d) { - float vpaint_mix = ((v3d->shading.type < OB_MATERIAL) && - (v3d->shading.color_type == V3D_SHADING_MATERIAL_COLOR)) ? - 0.0f : - v3d->overlay.gpencil_vertex_paint_opacity; - return vpaint_mix; - } - - return 1.0f; -} - -/* add fill vertex info */ -static void gpencil_add_fill_vertexdata(GpencilBatchCache *cache, - Object *ob, - bGPDlayer *gpl, - bGPDframe *gpf, - bGPDstroke *gps, - float opacity, - const float tintcolor[4], - const bool onion, - const bool custonion) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - ToolSettings *ts = draw_ctx->scene->toolsettings; - View3D *v3d = draw_ctx->v3d; - bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; - - const float vpaint_mix = gpencil_get_vertex_paint_factor(v3d); - const bool attenuate = (GPENCIL_VERTEX_MODE(gpd) && - GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); - - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(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] * opacity; - if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0) || - (gpl->blend_mode != eGplBlendMode_Regular)) { - if (cache->is_dirty) { - const float *color; - if (!onion) { - /* Apply the mix color of the fill and layer tint. */ - float mixtint[3]; - interp_v3_v3v3(mixtint, gps->mix_color_fill, tintcolor, tintcolor[3]); - interp_v3_v3v3(tfill, - tfill, - mixtint, - gps->mix_color_fill[3] * vpaint_mix * gpl->vertex_paint_opacity); - /* If using vertex paint mask, attenuate not selected. */ - if ((attenuate) && ((gps->flag & GP_STROKE_SELECT) == 0)) { - tfill[3] *= GP_VERTEX_MASK_ATTENUATE; - } - color = tfill; - } - else { - if (custonion) { - color = tintcolor; - } - else { - ARRAY_SET_ITEMS(tfill, UNPACK3(gps->runtime.tmp_fill_rgba), tintcolor[3]); - color = tfill; - } - } - /* create vertex data */ - const int old_len = cache->b_fill.vbo_len; - gpencil_get_fill_geom(&cache->b_fill, ob, gps, color); - - /* add to list of groups */ - if (old_len < cache->b_fill.vbo_len) { - cache->grp_cache = gpencil_group_cache_add(cache->grp_cache, - gpl, - gpf, - gps, - eGpencilBatchGroupType_Fill, - onion, - cache->b_fill.vbo_len, - &cache->grp_size, - &cache->grp_used); - } - } - } - } -} - -/* add stroke vertex info */ -static void gpencil_add_stroke_vertexdata(GpencilBatchCache *cache, - 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_gpencil_material_settings(ob, gps->mat_nr + 1); - const int alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH; - - /* set color using base color, tint color and opacity */ - if (cache->is_dirty) { - 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 ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) { - /* create vertex data */ - const int old_len = cache->b_stroke.vbo_len; - gpencil_get_stroke_geom(&cache->b_stroke, gpl, gps, sthickness, ink, tintcolor, onion); - - /* add to list of groups */ - if (old_len < cache->b_stroke.vbo_len) { - cache->grp_cache = gpencil_group_cache_add(cache->grp_cache, - gpl, - gpf, - gps, - eGpencilBatchGroupType_Stroke, - onion, - cache->b_stroke.vbo_len, - &cache->grp_size, - &cache->grp_used); - } - } - else { - /* create vertex data */ - const int old_len = cache->b_point.vbo_len; - gpencil_get_point_geom( - &cache->b_point, gpl, gps, sthickness, ink, tintcolor, alignment_mode, onion); - - /* add to list of groups */ - if (old_len < cache->b_point.vbo_len) { - cache->grp_cache = gpencil_group_cache_add(cache->grp_cache, - gpl, - gpf, - gps, - eGpencilBatchGroupType_Point, - onion, - cache->b_point.vbo_len, - &cache->grp_size, - &cache->grp_used); - } - } - } -} - -/* add edit points vertex info */ -static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache, - Object *ob, - bGPdata *gpd, - bGPDlayer *gpl, - bGPDframe *gpf, - bGPDstroke *gps) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - ToolSettings *ts = draw_ctx->scene->toolsettings; - const bool is_overlay = ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0); - const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) && - GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt)); - - const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) && - (ts->gpencil_selectmode_sculpt & - (GP_SCULPT_MASK_SELECTMODE_POINT | - GP_SCULPT_MASK_SELECTMODE_SEGMENT))); - - const bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) && - GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); - - const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) && - (ts->gpencil_selectmode_vertex & - (GP_VERTEX_MASK_SELECTMODE_POINT | - GP_VERTEX_MASK_SELECTMODE_SEGMENT))); - - const bool hide_vertex_lines = (GPENCIL_VERTEX_MODE(gpd) && (use_vertex_mask) && - ((v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) == 0)); - - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(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) || GPENCIL_VERTEX_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); - const bool is_vertex_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_VERTEXMODE); - - /* If Sculpt/Vertex mode and the mask is disabled, the select must be hidden. */ - const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) || - (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask)); - - /* Show Edit points if: - * Edit mode: Not in Stroke selection mode - * Sculpt mode: Not in Stroke mask mode and any other mask mode enabled - * Weight mode: Always - * Vertex mode: Always - */ - const bool show_points = (show_sculpt_points) || (show_vertex_points) || (is_weight_paint) || - (is_vertex_paint) || - (GPENCIL_EDIT_MODE(gpd) && - ((ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE) || - (gps->totpoints == 1))); - - if (GPENCIL_VERTEX_MODE(gpd) && (!use_vertex_mask) && - ((v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) == 0)) { - return; - } - - if (cache->is_dirty) { - if ((obact == ob) && (is_overlay) && (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) && - (!hide_vertex_lines)) { - /* line of the original stroke */ - gpencil_get_edlin_geom(&cache->b_edlin, gps, edit_alpha, hide_select); - - /* add to list of groups */ - cache->grp_cache = gpencil_group_cache_add(cache->grp_cache, - gpl, - gpf, - gps, - eGpencilBatchGroupType_Edlin, - false, - cache->b_edlin.vbo_len, - &cache->grp_size, - &cache->grp_used); - } - - /* If the points are hidden return. */ - if ((!show_points) || (hide_select) || ((is_vertex_paint) && (!is_overlay))) { - return; - } - - /* edit points */ - if (((gps->flag & GP_STROKE_SELECT) && (is_overlay)) || (is_weight_paint) || - (is_vertex_paint)) { - if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) || - ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) { - if (obact == ob) { - gpencil_get_edit_geom(&cache->b_edit, gps, edit_alpha, gpd->flag); - - /* add to list of groups */ - cache->grp_cache = gpencil_group_cache_add(cache->grp_cache, - gpl, - gpf, - gps, - eGpencilBatchGroupType_Edit, - false, - cache->b_edit.vbo_len, - &cache->grp_size, - &cache->grp_used); - } - } - } - } - } -} - -/* main function to draw strokes */ -static void gpencil_draw_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, - tGPencilObjectCache *cache_ob) -{ - 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; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const bool playing = stl->storage->is_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->gp_flag & 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 */ - if ((cache_ob != NULL) && (cache_ob->is_dup_ob)) { - copy_m4_m4(gpf->runtime.parent_obmat, cache_ob->obmat); - } - else { - ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, gpf->runtime.parent_obmat); - } - - for (gps = gpf->strokes.first; gps; gps = gps->next) { - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(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; - } - - /* Copy color to temp fields. */ - if ((is_multiedit) && (gp_style)) { - copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); - copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); - } - - /* be sure recalc all cache in source stroke to avoid recalculation when frame change - * and improve fps */ - gpencil_recalc_geometry_caches( - ob, gpl, gp_style, (gps->runtime.gps_orig) ? gps->runtime.gps_orig : 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) || - (gpl->blend_mode != eGplBlendMode_Regular)) { - - continue; - } - } - - if ((gpl->actframe && (gpl->actframe->framenum == gpf->framenum)) || (!is_multiedit) || - (overlay_multiedit)) { - /* hide any blend layer */ - if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Regular)) { - /* fill */ - if ((gp_style->flag & GP_STYLE_FILL_SHOW) && (!stl->storage->simplify_fill) && - ((gps->flag & GP_STROKE_NOFILL) == 0)) { - gpencil_add_fill_vertexdata( - cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion); - } - /* stroke - * No fill strokes, must show stroke always or if the total points is lower than 3, - * because the stroke cannot be filled and it would be invisible. */ - if (((gp_style->flag & GP_STYLE_STROKE_SHOW) || (gps->flag & GP_STROKE_NOFILL) || - (gps->totpoints < 3)) && - ((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || - (gpl->blend_mode == eGplBlendMode_Regular))) { - /* recalc strokes uv (geometry can be changed by modifiers) */ - if (gps->flag & GP_STROKE_RECALC_GEOMETRY) { - ED_gpencil_calc_stroke_uv(ob, gps); - } - - gpencil_add_stroke_vertexdata( - cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion); - } - } - } - - /* edit points (only in edit mode or mask and not play animation not render) */ - if ((draw_ctx->obact == ob) && (!playing) && (!is_render) && (!cache_ob->is_dup_ob)) { - if ((gpl->flag & GP_LAYER_LOCKED) == 0) { - if (!stl->g_data->shgrps_edit_line) { - stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh, - psl->edit_pass); - DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_line, "gpModelMatrix", ob->obmat); - } - 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); - DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_point, "gpModelMatrix", ob->obmat); - } - - gpencil_add_editpoints_vertexdata(cache, ob, gpd, gpl, gpf, gps); - } - } - } -} - -/* 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); -} - -/* function to draw strokes for onion only */ -static void gpencil_draw_onion_strokes(GpencilBatchCache *cache, - void *vedata, - Object *ob, - bGPdata *gpd, - bGPDlayer *gpl, - bGPDframe *gpf, - const float opacity, - const float tintcolor[4], - const bool custonion) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - Depsgraph *depsgraph = DRW_context_state_get()->depsgraph; - - /* get parent matrix and save as static data */ - ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, gpf->runtime.parent_obmat); - - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - if (gp_style == NULL) { - 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); - - 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; - } - - /* stroke */ - gpencil_add_stroke_vertexdata(cache, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion); - - stl->storage->shgroup_id++; - } -} - -/* draw onion-skinning for a layer */ -static void gpencil_draw_onionskins(GpencilBatchCache *cache, - 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; - bool colflag = false; - const int mode = gpd->onion_mode; - bGPDframe *gpf_loop = ((gpd->onion_flag & GP_ONION_LOOP) && (mode != GP_ONION_MODE_SELECTED)) ? - gpl->frames.first : - NULL; - int last = gpf->framenum; - - colflag = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0; - const short onion_keytype = gpd->onion_keytype; - /* ------------------------------- - * 1) Draw Previous Frames First - * ------------------------------- */ - step = gpd->gstep; - - 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; - } - /* verify keyframe type */ - if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) { - 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_SELECTED) && (gpd->onion_flag & GP_ONION_LOOP)) { - gpf_loop = gf; - } - - gpencil_get_onion_alpha(color, gpd); - gpencil_draw_onion_strokes(cache, vedata, ob, gpd, gpl, gf, color[3], color, colflag); - } - /* ------------------------------- - * 2) Now draw next frames - * ------------------------------- */ - step = gpd->gstep_next; - - 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; - } - /* verify keyframe type */ - if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) { - 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, 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, vedata, ob, gpd, gpl, gpf_loop, color[3], color, colflag); - } - } -} - -/* Check if stencil is required */ -static bool gpencil_is_stencil_required(MaterialGPencilStyle *gp_style) -{ - return (bool)((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_SOLID) && - ((gp_style->flag & GP_STYLE_DISABLE_STENCIL) == 0)); -} - -/* draw stroke in drawing buffer */ -void 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; - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true; - Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); - const bool is_paint_tool = (bool)((brush) && (brush->gpencil_tool == GPAINT_TOOL_DRAW)); - bGPdata *gpd_eval = ob->data; - /* need the original to avoid cow overhead while drawing */ - bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id); - - MaterialGPencilStyle *gp_style = NULL; - float obscale = mat4_to_scale(ob->obmat); - - /* use the brush material */ - Material *ma = BKE_gpencil_object_material_get_from_brush(ob, 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_gpencil_material_settings(ob, ob->actcol); - } - - static float unit_mat[4][4] = { - {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}}; - - /* 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 (gpd->runtime.sbuffer_used > 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; - - /* save gradient info */ - stl->storage->gradient_f = brush->gpencil_settings->gradient_f; - copy_v2_v2(stl->storage->gradient_s, brush->gpencil_settings->gradient_s); - stl->storage->alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH; - - /* if only one point, don't need to draw buffer because the user has no time to see it */ - if (gpd->runtime.sbuffer_used > 1) { - if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) { - stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_stroke_create( - e_data, - vedata, - psl->drawing_pass, - e_data->gpencil_stroke_sh, - NULL, - unit_mat, - gpd, - NULL, - NULL, - gp_style, - -1, - false, - 1.0f, - (const int *)stl->storage->shade_render); - - if (gpencil_is_stencil_required(gp_style)) { - DRW_shgroup_stencil_mask(stl->g_data->shgrps_drawing_stroke, 0x01); - } - else { - /* Disable stencil for this type */ - DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_stroke, - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - } - } - else { - stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_point_create( - e_data, - vedata, - psl->drawing_pass, - e_data->gpencil_point_sh, - NULL, - unit_mat, - gpd, - NULL, - NULL, - gp_style, - -1, - false, - 1.0f, - (const int *)stl->storage->shade_render); - /* Disable stencil for this type */ - DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_stroke, - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - } - - /* 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 = gpencil_get_buffer_stroke_geom(gpd, lthick); - } - else { - stl->g_data->batch_buffer_stroke = gpencil_get_buffer_point_geom(gpd, lthick); - } - - /* buffer strokes, must show stroke always */ - DRW_shgroup_call( - stl->g_data->shgrps_drawing_stroke, stl->g_data->batch_buffer_stroke, NULL); - - if ((gpd->runtime.sbuffer_used >= 3) && - (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) && - ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0) && - ((brush->gpencil_settings->flag & GP_BRUSH_DISSABLE_LASSO) == 0) && - (gp_style->flag & GP_STYLE_FILL_SHOW)) { - /* 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); - /* Disable stencil for this type */ - DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_fill, - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - - stl->g_data->batch_buffer_fill = gpencil_get_buffer_fill_geom(gpd); - DRW_shgroup_call(stl->g_data->shgrps_drawing_fill, stl->g_data->batch_buffer_fill, NULL); - } - } - } - } - - /* control points for primitives and speed guide */ - const bool is_cppoint = (gpd->runtime.tot_cp_points > 0); - const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide && - (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL)); - const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) && - ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0)); - - if ((overlay) && (is_paint_tool) && (is_cppoint || is_speed_guide) && (is_show_gizmo) && - ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0)) { - DRWShadingGroup *shgrp = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->drawing_pass); - const float *viewport_size = DRW_viewport_size_get(); - DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1); - DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", unit_mat); - - /* Disable stencil for this type */ - DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - stl->g_data->batch_buffer_ctrlpoint = gpencil_get_buffer_ctrlpoint_geom(gpd); - - DRW_shgroup_call(shgrp, stl->g_data->batch_buffer_ctrlpoint, NULL); - } -} - -/* create all missing batches */ -static void gpencil_batches_ensure(GpencilBatchCache *cache) -{ - if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) { - cache->b_point.batch = GPU_batch_create_ex( - GPU_PRIM_POINTS, cache->b_point.vbo, NULL, GPU_BATCH_OWNS_VBO); - } - if ((cache->b_stroke.vbo) && (cache->b_stroke.batch == NULL)) { - cache->b_stroke.batch = GPU_batch_create_ex( - GPU_PRIM_LINE_STRIP_ADJ, cache->b_stroke.vbo, NULL, GPU_BATCH_OWNS_VBO); - } - if ((cache->b_fill.vbo) && (cache->b_fill.batch == NULL)) { - cache->b_fill.batch = GPU_batch_create_ex( - GPU_PRIM_TRIS, cache->b_fill.vbo, NULL, GPU_BATCH_OWNS_VBO); - } - if ((cache->b_edit.vbo) && (cache->b_edit.batch == NULL)) { - cache->b_edit.batch = GPU_batch_create_ex( - GPU_PRIM_POINTS, cache->b_edit.vbo, NULL, GPU_BATCH_OWNS_VBO); - } - if ((cache->b_edlin.vbo) && (cache->b_edlin.batch == NULL)) { - cache->b_edlin.batch = GPU_batch_create_ex( - GPU_PRIM_LINE_STRIP, cache->b_edlin.vbo, NULL, GPU_BATCH_OWNS_VBO); - } -} - -/* create all shading groups */ -static void gpencil_shgroups_create(GPENCIL_e_data *e_data, - void *vedata, - Object *ob, - GpencilBatchCache *cache, - tGPencilObjectCache *cache_ob) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - bGPdata *gpd = (bGPdata *)ob->data; - DRWPass *stroke_pass = GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d; - - GpencilBatchGroup *elm = NULL; - DRWShadingGroup *shgrp = NULL; - tGPencilObjectCache_shgrp *array_elm = NULL; - - bGPDlayer *gpl = NULL; - bGPDlayer *gpl_prev = NULL; - int idx = 0; - bool tag_first = false; - bool strokes = false; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const View3D *v3d = draw_ctx->v3d; - - const bool overlay = draw_ctx->v3d != NULL ? - (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : - true; - const bool screen_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; - const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && screen_onion && - overlay && gpencil_onion_active(gpd); - - int start_stroke = 0; - int start_point = 0; - int start_fill = 0; - int start_edit = 0; - int start_edlin = 0; - - uint stencil_id = 1; - /* Flag to determine if the layer is above active layer. */ - stl->storage->is_ontop = false; - for (int i = 0; i < cache->grp_used; i++) { - elm = &cache->grp_cache[i]; - array_elm = &cache_ob->shgrp_array[idx]; - - /* Limit stencil id */ - if (stencil_id > 255) { - stencil_id = 1; - } - - /* save last group when change */ - if (gpl_prev == NULL) { - gpl_prev = elm->gpl; - tag_first = true; - } - else { - if (elm->gpl != gpl_prev) { - /* first layer is always blend Normal */ - array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode; - array_elm->end_shgrp = shgrp; - gpl_prev = elm->gpl; - tag_first = true; - idx++; - } - } - - gpl = elm->gpl; - if ((!stl->storage->is_ontop) && (gpl->flag & GP_LAYER_ACTIVE)) { - stl->storage->is_ontop = true; - } - - bGPDframe *gpf = elm->gpf; - bGPDstroke *gps = elm->gps; - MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - /* if the user switch used material from data to object, - * the material could not be available */ - if (gp_style == NULL) { - break; - } - - /* limit the number of shading groups */ - if (i >= GPENCIL_MAX_SHGROUPS) { - break; - } - - const float scale = (!cache_ob->is_dup_ob) ? mat4_to_scale(gpf->runtime.parent_obmat) : - cache_ob->scale; - float(*obmat)[4] = (!cache_ob->is_dup_ob) ? gpf->runtime.parent_obmat : cache_ob->obmat; - switch (elm->type) { - case eGpencilBatchGroupType_Stroke: { - const int len = elm->vertex_idx - start_stroke; - strokes = true; - - shgrp = gpencil_shgroup_stroke_create(e_data, - vedata, - stroke_pass, - e_data->gpencil_stroke_sh, - ob, - obmat, - gpd, - gpl, - gps, - gp_style, - stl->storage->shgroup_id, - elm->onion, - scale, - cache_ob->shading_type); - - /* set stencil mask id */ - if (gpencil_is_stencil_required(gp_style)) { - if (stencil_id == 1) { - /* Clear previous stencils. */ - DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0); - } - DRW_shgroup_stencil_mask(shgrp, stencil_id); - stencil_id++; - } - else { - /* Disable stencil for this type */ - DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - } - - if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len); - } - stl->storage->shgroup_id++; - start_stroke = elm->vertex_idx; - break; - } - case eGpencilBatchGroupType_Point: { - const int len = elm->vertex_idx - start_point; - strokes = true; - - shgrp = gpencil_shgroup_point_create(e_data, - vedata, - stroke_pass, - e_data->gpencil_point_sh, - ob, - obmat, - gpd, - gpl, - gps, - gp_style, - stl->storage->shgroup_id, - elm->onion, - scale, - cache_ob->shading_type); - - /* Disable stencil for this type */ - DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - - if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len); - } - stl->storage->shgroup_id++; - start_point = elm->vertex_idx; - break; - } - case eGpencilBatchGroupType_Fill: { - const int len = elm->vertex_idx - start_fill; - strokes = true; - - shgrp = gpencil_shgroup_fill_create(e_data, - vedata, - stroke_pass, - e_data->gpencil_fill_sh, - ob, - obmat, - gpd, - gpl, - gp_style, - stl->storage->shgroup_id, - cache_ob->shading_type); - - /* Disable stencil for this type */ - DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - - if ((do_onion) || (elm->onion == false)) { - DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len); - } - stl->storage->shgroup_id++; - start_fill = elm->vertex_idx; - break; - } - case eGpencilBatchGroupType_Edit: { - if (stl->g_data->shgrps_edit_point) { - const int len = elm->vertex_idx - start_edit; - - shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point); - DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat); - /* use always the same group */ - DRW_shgroup_call_range( - stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len); - - start_edit = elm->vertex_idx; - } - break; - } - case eGpencilBatchGroupType_Edlin: { - if (stl->g_data->shgrps_edit_line) { - const int len = elm->vertex_idx - start_edlin; - - shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line); - DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat); - /* use always the same group */ - DRW_shgroup_call_range( - stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len); - - start_edlin = elm->vertex_idx; - } - break; - } - default: { - break; - } - } - /* save first group */ - if ((shgrp != NULL) && (tag_first) && (strokes)) { - array_elm = &cache_ob->shgrp_array[idx]; - array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode; - array_elm->mask_layer = gpl->flag & GP_LAYER_USE_MASK; - array_elm->blend_opacity = gpl->opacity; - array_elm->init_shgrp = shgrp; - cache_ob->tot_layers++; - tag_first = false; - } - } - - /* save last group */ - if (shgrp != NULL) { - array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode; - array_elm->end_shgrp = shgrp; - } -} -/* populate a datablock for multiedit (no onions, no modifiers) */ -void gpencil_populate_multiedit(GPENCIL_e_data *e_data, - void *vedata, - Object *ob, - tGPencilObjectCache *cache_ob) -{ - bGPdata *gpd = (bGPdata *)ob->data; - bGPDframe *gpf = NULL; - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph); - GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval); - - /* check if playing animation */ - const bool playing = stl->storage->is_playing; - - /* calc max size of VBOs */ - gpencil_calc_vertex(stl, cache_ob, cache, gpd); - - /* 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; - } - const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3]; - const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha}; - - /* 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, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob); - } - } - } - else { - gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV); - if (gpf) { - gpencil_draw_strokes( - cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob); - } - } - } - - /* create batchs and shading groups */ - gpencil_batches_ensure(cache); - gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); - - cache->is_dirty = false; -} - -/* helper for populate a complete grease pencil datablock */ -void gpencil_populate_datablock(GPENCIL_e_data *e_data, - void *vedata, - Object *ob, - tGPencilObjectCache *cache_ob) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph); - Scene *scene = draw_ctx->scene; - - /* TODO: Review why is needed this recalc when render cycles + GP object in background. - * We need these lines to keep running the background render, but asap we get an alternative - * solution, we must remove it and keep all logic inside gpencil_modifier module. (antoniov) - */ - if (ob->runtime.gpencil_tot_layers == 0) { - BKE_gpencil_modifiers_calc(draw_ctx->depsgraph, draw_ctx->scene, ob); - } - - bGPdata *gpd = (bGPdata *)ob->data; - - /* If render mode, instead to use view switches, test if the datablock has - * the onion activated for render. */ - const bool render_onion = (gpd && gpd->onion_flag & GP_ONION_GHOST_ALWAYS); - const bool main_onion = (stl->storage->is_render) ? render_onion : stl->storage->is_main_onion; - const bool overlay = (stl->storage->is_render) ? render_onion : stl->storage->is_main_overlay; - const bool playing = stl->storage->is_playing; - const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay && - main_onion && !playing && gpencil_onion_active(gpd); - - View3D *v3d = draw_ctx->v3d; - int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph); - - bGPDframe *gpf_eval = NULL; - const bool time_remap = BKE_gpencil_has_time_modifiers(ob); - - float opacity; - bGPDframe *gpf = NULL; - - GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval); - - /* if object is duplicate, only create shading groups */ - if (cache_ob->is_dup_ob) { - gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); - return; - } - - /* calc max size of VBOs */ - gpencil_calc_vertex(stl, cache_ob, cache, gpd); - - /* 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; - } - - const bool is_solomode = GPENCIL_PAINT_MODE(gpd) && (!playing) && (!stl->storage->is_render) && - (gpl->flag & GP_LAYER_SOLO_MODE); - - /* filter view layer to gp layers in the same view layer (for compo) */ - if ((stl->storage->is_render) && (gpl->viewlayername[0] != '\0')) { - if (!STREQ(view_layer->name, gpl->viewlayername)) { - continue; - } - } - - /* remap time */ - int remap_cfra = cfra_eval; - if ((time_remap) && (!stl->storage->simplify_modif)) { - remap_cfra = BKE_gpencil_time_modifier( - draw_ctx->depsgraph, scene, ob, gpl, cfra_eval, stl->storage->is_render); - } - - gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV); - if (gpf == NULL) { - continue; - } - - /* if solo mode, display only frames with keyframe in the current frame */ - if ((is_solomode) && (gpf->framenum != remap_cfra)) { - continue; - } - - opacity = gpl->opacity; - /* if pose mode, maybe the overlay to fade geometry is enabled */ - if ((draw_ctx->obact) && (draw_ctx->object_mode == OB_MODE_POSE) && - (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT)) { - opacity = opacity * v3d->overlay.xray_alpha_bone; - } - - /* Get evaluated frames array data */ - int idx_eval = BLI_findindex(&gpd->layers, gpl); - gpf_eval = &ob->runtime.gpencil_evaluated_frames[idx_eval]; - - /* draw onion skins */ - if (!ID_IS_LINKED(&gpd->id)) { - if ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) && - ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) && (!cache_ob->is_dup_ob) && - (gpd->id.us <= 1)) { - if ((!stl->storage->is_render) || - ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) { - gpencil_draw_onionskins(cache, vedata, ob, gpd, gpl, gpf); - } - } - } - /* draw normal strokes */ - const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3]; - const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha}; - gpencil_draw_strokes( - cache, e_data, vedata, ob, gpd, gpl, gpf_eval, opacity, tintcolor, false, cache_ob); - } - - /* create batchs and shading groups */ - gpencil_batches_ensure(cache); - gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); - - cache->is_dirty = false; -} - -void gpencil_populate_particles(GPENCIL_e_data *e_data, GHash *gh_objects, void *vedata) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - - /* add particles */ - for (int i = 0; i < stl->g_data->gp_cache_used; i++) { - tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i]; - if (cache_ob->is_dup_ob) { - /* Reassign duplicate objects because memory for particles is not available - * and need to use the original data-block and run-time data. */ - Object *ob = (Object *)BLI_ghash_lookup(gh_objects, cache_ob->name); - if (ob) { - cache_ob->ob = ob; - cache_ob->gpd = (bGPdata *)ob->data; - GpencilBatchCache *cache = ob->runtime.gpencil_cache; - if (cache != NULL) { - gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob); - } - } - } - } -} diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index f44551356c4..8736857c45c 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -29,11 +29,19 @@ #include "BKE_paint.h" #include "BKE_shader_fx.h" +#include "BKE_camera.h" +#include "BKE_global.h" /* for G.debug */ + +#include "BLI_link_utils.h" +#include "BLI_memblock.h" + +#include "DNA_camera_types.h" #include "DNA_gpencil_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" #include "GPU_texture.h" +#include "GPU_uniformbuffer.h" #include "gpencil_engine.h" @@ -44,1129 +52,947 @@ #include "UI_resources.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[]; -extern char datatoc_gpencil_blend_frag_glsl[]; - -extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; - -extern char datatoc_common_colormanagement_lib_glsl[]; -extern char datatoc_common_view_lib_glsl[]; - -/* *********** STATIC *********** */ -static GPENCIL_e_data e_data = {NULL}; /* Engine data */ - /* *********** FUNCTIONS *********** */ -/* create a multisample buffer if not present */ -void gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h) +void GPENCIL_engine_init(void *ved) { + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_StorageList *stl = vedata->stl; + GPENCIL_TextureList *txl = vedata->txl; 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)}); - } - } + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + const DRWContextState *ctx = DRW_context_state_get(); + const View3D *v3d = ctx->v3d; + + if (!stl->pd) { + stl->pd = MEM_callocN(sizeof(GPENCIL_PrivateData), "GPENCIL_PrivateData"); + } + + if (txl->dummy_texture == NULL) { + float pixels[1][4] = {{1.0f, 0.0f, 1.0f, 1.0f}}; + txl->dummy_texture = DRW_texture_create_2d(1, 1, GPU_RGBA8, DRW_TEX_WRAP, (float *)pixels); + } + + GPENCIL_ViewLayerData *vldata = GPENCIL_view_layer_data_ensure(); + + /* Resize and reset memblocks. */ + BLI_memblock_clear(vldata->gp_light_pool, gpencil_light_pool_free); + BLI_memblock_clear(vldata->gp_material_pool, gpencil_material_pool_free); + BLI_memblock_clear(vldata->gp_object_pool, NULL); + BLI_memblock_clear(vldata->gp_layer_pool, NULL); + BLI_memblock_clear(vldata->gp_vfx_pool, NULL); + + stl->pd->gp_light_pool = vldata->gp_light_pool; + stl->pd->gp_material_pool = vldata->gp_material_pool; + stl->pd->gp_object_pool = vldata->gp_object_pool; + stl->pd->gp_layer_pool = vldata->gp_layer_pool; + stl->pd->gp_vfx_pool = vldata->gp_vfx_pool; + stl->pd->last_light_pool = NULL; + stl->pd->last_material_pool = NULL; + stl->pd->tobjects.first = NULL; + stl->pd->tobjects.last = NULL; + stl->pd->tobjects_infront.first = NULL; + stl->pd->tobjects_infront.last = NULL; + stl->pd->sbuffer_tobjects.first = NULL; + stl->pd->sbuffer_tobjects.last = NULL; + stl->pd->dummy_tx = txl->dummy_texture; + stl->pd->draw_depth_only = !DRW_state_is_fbo() || (v3d && v3d->shading.type == OB_WIRE); + stl->pd->scene_depth_tx = stl->pd->draw_depth_only ? txl->dummy_texture : dtxl->depth; + stl->pd->scene_fb = dfbl->default_fb; + stl->pd->is_render = txl->render_depth_tx || (v3d && v3d->shading.type == OB_RENDER); + stl->pd->global_light_pool = gpencil_light_pool_add(stl->pd); + stl->pd->shadeless_light_pool = gpencil_light_pool_add(stl->pd); + /* Small HACK: we don't want the global pool to be reused, + * so we set the last light pool to NULL. */ + stl->pd->last_light_pool = NULL; + + bool use_scene_lights = false; + bool use_scene_world = false; + + if (v3d) { + use_scene_lights = ((v3d->shading.type == OB_MATERIAL) && + (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) || + ((v3d->shading.type == OB_RENDER) && + (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER)); + + use_scene_world = ((v3d->shading.type == OB_MATERIAL) && + (v3d->shading.flag & V3D_SHADING_SCENE_WORLD)) || + ((v3d->shading.type == OB_RENDER) && + (v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER)); + + stl->pd->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1; + copy_v3_v3(stl->pd->v3d_single_color, v3d->shading.single_color); + + /* For non active frame, use only lines in multiedit mode. */ + const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; + stl->pd->use_multiedit_lines_only = !overlays_on || + (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0; + } + else if (stl->pd->is_render) { + use_scene_lights = true; + use_scene_world = true; + stl->pd->use_multiedit_lines_only = false; + } + + stl->pd->use_lighting = (v3d && v3d->shading.type > OB_SOLID) || stl->pd->is_render; + stl->pd->use_lights = use_scene_lights; + + if (txl->render_depth_tx != NULL) { + stl->pd->scene_depth_tx = txl->render_depth_tx; + stl->pd->scene_fb = fbl->render_fb; + } + + gpencil_light_ambient_add(stl->pd->shadeless_light_pool, (float[3]){1.0f, 1.0f, 1.0f}); + + World *world = ctx->scene->world; + if (world != NULL && use_scene_world) { + gpencil_light_ambient_add(stl->pd->global_light_pool, &world->horr); + } + else if (v3d) { + float world_light[3]; + copy_v3_fl(world_light, v3d->shading.studiolight_intensity); + gpencil_light_ambient_add(stl->pd->global_light_pool, world_light); + } + + float viewmatinv[4][4]; + DRW_view_viewmat_get(NULL, viewmatinv, true); + copy_v3_v3(stl->pd->camera_z_axis, viewmatinv[2]); + copy_v3_v3(stl->pd->camera_pos, viewmatinv[3]); + stl->pd->camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]); + + if (ctx && ctx->rv3d && v3d) { + stl->pd->camera = (ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; + } + else { + stl->pd->camera = NULL; } } -static void GPENCIL_create_framebuffers(void *vedata) +void GPENCIL_cache_init(void *ved) { - GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl; - - /* Go full 32bits for rendering */ - eGPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F; + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_PassList *psl = vedata->psl; + GPENCIL_TextureList *txl = vedata->txl; + GPENCIL_FramebufferList *fbl = vedata->fbl; + GPENCIL_PrivateData *pd = vedata->stl->pd; + DRWShadingGroup *grp; - 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]}; + const DRWContextState *draw_ctx = DRW_context_state_get(); + pd->cfra = (int)DEG_get_ctime(draw_ctx->depsgraph); + pd->simplify_antialias = GPENCIL_SIMPLIFY_AA(draw_ctx->scene); + /* Antialiasing needs the layer buffer to output to. */ + pd->use_layer_fb = false || !pd->simplify_antialias; + pd->use_object_fb = false; + pd->use_mask_fb = false; + pd->use_signed_fb = false; + + if (draw_ctx->v3d) { + const bool hide_overlay = ((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) != 0); + const bool show_onion = ((draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) != 0); + const bool playing = (draw_ctx->evil_C != NULL) ? + ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != + NULL : + false; + pd->do_onion = show_onion && !hide_overlay && !playing; + /* Save simplify flags (can change while drawing, so it's better to save). */ + Scene *scene = draw_ctx->scene; + pd->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing); + pd->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, playing); + + /* Fade Layer. */ + const bool is_fade_layer = ((!hide_overlay) && (!pd->is_render) && + (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS)); + pd->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f; + /* Fade GPencil Objects. */ + const bool is_fade_object = ((!hide_overlay) && (!pd->is_render) && + (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) && + (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL)); + pd->fade_gp_object_opacity = (is_fade_object) ? draw_ctx->v3d->overlay.gpencil_paper_opacity : + -1.0f; + pd->fade_3d_object_opacity = ((!hide_overlay) && (!pd->is_render) && + (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS)) ? + draw_ctx->v3d->overlay.gpencil_paper_opacity : + -1.0f; + } + else { + pd->do_onion = true; + pd->simplify_fill = false; + pd->simplify_fx = false; + pd->fade_layer_opacity = -1.0f; + } - /* create multisample framebuffer for AA */ - if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) && - (stl->storage->multisamples > 0)) { - gpencil_multisample_ensure(vedata, size[0], size[1]); + { + pd->sbuffer_stroke = NULL; + pd->sbuffer_gpd = NULL; + pd->sbuffer_layer = NULL; + pd->stroke_batch = NULL; + pd->fill_batch = NULL; + pd->do_fast_drawing = false; + + pd->obact = draw_ctx->obact; + if (pd->obact && pd->obact->type == OB_GPENCIL) { + /* Check if active object has a temp stroke data. */ + bGPdata *gpd = (bGPdata *)pd->obact->data; + if (gpd->runtime.sbuffer_used > 0) { + pd->sbuffer_gpd = gpd; + pd->sbuffer_stroke = DRW_cache_gpencil_sbuffer_stroke_data_get(pd->obact); + pd->sbuffer_layer = BKE_gpencil_layer_active_get(pd->sbuffer_gpd); + pd->do_fast_drawing = false; /* TODO option */ + } } + } - /* Framebufers for basic object drawing */ - if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_BASIC) { - /* temp textures for ping-pong buffers */ - stl->g_data->temp_depth_tx_a = DRW_texture_pool_query_2d( - size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type); - stl->g_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(stl->g_data->temp_depth_tx_a), - GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_a), - }); + if (pd->do_fast_drawing) { + pd->snapshot_buffer_dirty = (txl->snapshot_color_tx == NULL); + const float *size = DRW_viewport_size_get(); + DRW_texture_ensure_2d(&txl->snapshot_depth_tx, size[0], size[1], GPU_DEPTH24_STENCIL8, 0); + DRW_texture_ensure_2d(&txl->snapshot_color_tx, size[0], size[1], GPU_R11F_G11F_B10F, 0); + DRW_texture_ensure_2d(&txl->snapshot_reveal_tx, size[0], size[1], GPU_R11F_G11F_B10F, 0); - stl->g_data->temp_depth_tx_b = DRW_texture_pool_query_2d( - size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type); - stl->g_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(stl->g_data->temp_depth_tx_b), - GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_b), - }); + GPU_framebuffer_ensure_config(&fbl->snapshot_fb, + { + GPU_ATTACHMENT_TEXTURE(txl->snapshot_depth_tx), + GPU_ATTACHMENT_TEXTURE(txl->snapshot_color_tx), + GPU_ATTACHMENT_TEXTURE(txl->snapshot_reveal_tx), + }); + } + else { + /* Free uneeded buffers. */ + GPU_FRAMEBUFFER_FREE_SAFE(fbl->snapshot_fb); + DRW_TEXTURE_FREE_SAFE(txl->snapshot_depth_tx); + DRW_TEXTURE_FREE_SAFE(txl->snapshot_color_tx); + DRW_TEXTURE_FREE_SAFE(txl->snapshot_reveal_tx); + } - /* used for FX effects and Layer blending */ - stl->g_data->temp_depth_tx_fx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type); - stl->g_data->temp_color_tx_fx = DRW_texture_pool_query_2d( - size[0], size[1], fb_format, &draw_engine_gpencil_type); - GPU_framebuffer_ensure_config(&fbl->temp_fb_fx, - { - GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_depth_tx_fx), - GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_fx), - }); - } + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM; + DRW_PASS_CREATE(psl->composite_ps, state); - /* background framebuffer to speed up drawing process */ - if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_DRAW) { - if (txl->background_color_tx == NULL) { - stl->storage->background_ready = false; - } - DRW_texture_ensure_2d( - &txl->background_depth_tx, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_FILTER); - DRW_texture_ensure_2d( - &txl->background_color_tx, size[0], size[1], GPU_RGBA16F, DRW_TEX_FILTER); - GPU_framebuffer_ensure_config(&fbl->background_fb, - { - GPU_ATTACHMENT_TEXTURE(txl->background_depth_tx), - GPU_ATTACHMENT_TEXTURE(txl->background_color_tx), - }); - } - else { - DRW_TEXTURE_FREE_SAFE(txl->background_depth_tx); - DRW_TEXTURE_FREE_SAFE(txl->background_color_tx); - } + GPUShader *sh = GPENCIL_shader_composite_get(); + grp = DRW_shgroup_create(sh, psl->composite_ps); + DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_tx); + DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_tx); + DRW_shgroup_uniform_bool_copy(grp, "doSrgb", txl->render_depth_tx == NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -} + { + DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + DRW_PASS_CREATE(psl->merge_depth_ps, state); -static void GPENCIL_create_shaders(void) -{ - /* blank texture used if no texture defined for fill shader */ - if (!e_data.gpencil_blank_texture) { - float rect[1][1][4] = {{{0.0f}}}; - e_data.gpencil_blank_texture = DRW_texture_create_2d( - 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect); - } - /* normal fill shader */ - if (!e_data.gpencil_fill_sh) { - e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({ - .vert = - (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_fill_vert_glsl, NULL}, - .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl, - 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 = GPU_shader_create_from_arrays({ - .vert = - (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_stroke_vert_glsl, NULL}, - .geom = (const char *[]){datatoc_gpencil_stroke_geom_glsl, NULL}, - .frag = (const char *[]){datatoc_common_colormanagement_lib_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 = GPU_shader_create_from_arrays({ - .vert = - (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_point_vert_glsl, NULL}, - .geom = (const char *[]){datatoc_gpencil_point_geom_glsl, NULL}, - .frag = (const char *[]){datatoc_common_colormanagement_lib_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_with_lib(datatoc_gpencil_edit_point_vert_glsl, - datatoc_gpencil_edit_point_geom_glsl, - datatoc_gpencil_edit_point_frag_glsl, - datatoc_common_view_lib_glsl, - NULL); - } - - /* used for edit lines for edit modes */ - if (!e_data.gpencil_line_sh) { - e_data.gpencil_line_sh = DRW_shader_create_with_lib( - datatoc_gpencil_edit_point_vert_glsl, - NULL, - datatoc_gpu_shader_3D_smooth_color_frag_glsl, - datatoc_common_view_lib_glsl, - NULL); - } - - /* 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); - } - - /* blend */ - if (!e_data.gpencil_blend_fullscreen_sh) { - e_data.gpencil_blend_fullscreen_sh = DRW_shader_create_fullscreen( - datatoc_gpencil_blend_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); + GPUShader *sh = GPENCIL_shader_depth_merge_get(); + grp = DRW_shgroup_create(sh, psl->merge_depth_ps); + DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx); + DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1); + DRW_shgroup_uniform_vec4(grp, "gpModelMatrix[0]", pd->object_bound_mat[0], 4); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -} -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"); - stl->storage->shade_render[0] = OB_RENDER; - stl->storage->shade_render[1] = 0; - } + Camera *cam = (pd->camera != NULL) ? pd->camera->data : NULL; - stl->storage->multisamples = U.gpencil_multisamples; + /* Pseudo DOF setup. */ + if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) { + const float *vp_size = DRW_viewport_size_get(); + float fstop = cam->dof.aperture_fstop; + float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); + float focus_dist = BKE_camera_object_dof_distance(pd->camera); + float focal_len = cam->lens; - /* create shaders */ - GPENCIL_create_shaders(); - GPENCIL_create_fx_shaders(&e_data); -} + const float scale_camera = 0.001f; + /* we want radius here for the aperture number */ + float aperture = 0.5f * scale_camera * focal_len / fstop; + float focal_len_scaled = scale_camera * focal_len; + float sensor_scaled = scale_camera * sensor; -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_line_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_blend_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); + if (draw_ctx->rv3d != NULL) { + sensor_scaled *= draw_ctx->rv3d->viewcamtexcofac[0]; + } + + pd->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); + pd->dof_params[1] *= vp_size[0] / sensor_scaled; + pd->dof_params[0] = -focus_dist * pd->dof_params[1]; + } + else { + /* Disable DoF blur scalling. */ + pd->camera = NULL; + } } -/* Helper: Check if the main overlay and onion switches are enabled in any screen. - * - * This is required to generate the onion skin and limit the times the cache is updated because the - * cache is generated only in the first screen and if the first screen has the onion disabled the - * cache for onion skin is not generated. The loop adds time, but always is faster than regenerate - * the cache all the times. - */ -static void gpencil_check_screen_switches(const DRWContextState *draw_ctx, - GPENCIL_StorageList *stl) +#define DRAW_NOW 2 + +typedef struct gpIterPopulateData { + Object *ob; + GPENCIL_tObject *tgp_ob; + GPENCIL_PrivateData *pd; + GPENCIL_MaterialPool *matpool; + DRWShadingGroup *grp; + /* Last material UBO bound. Used to avoid uneeded buffer binding. */ + GPUUniformBuffer *ubo_mat; + GPUUniformBuffer *ubo_lights; + /* Last texture bound. */ + GPUTexture *tex_fill; + GPUTexture *tex_stroke; + /* Offset in the material pool to the first material of this object. */ + int mat_ofs; + /* Is the sbuffer call need to be issued. */ + int do_sbuffer_call; + /* Indices to do correct insertion of the sbuffer stroke. */ + int stroke_index_last; + int stroke_index_offset; + /* Infos for call batching. */ + struct GPUBatch *geom; + bool instancing; + int vfirst, vcount; +} gpIterPopulateData; + +#define DISABLE_BATCHING 0 + +static void gp_drawcall_flush(gpIterPopulateData *iter) { - stl->storage->is_main_overlay = false; - stl->storage->is_main_onion = false; - /* Check if main onion switch is enabled in any screen. */ - Main *bmain = CTX_data_main(draw_ctx->evil_C); - - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - if (sa && sa->spacetype == SPACE_VIEW3D) { - View3D *v3d = sa->spacedata.first; - if (v3d == NULL) { - continue; - } - if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) { - stl->storage->is_main_overlay = true; - } - if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) { - stl->storage->is_main_onion = true; - } - } - /* If found, don't need loop more. */ - if ((stl->storage->is_main_overlay) && (stl->storage->is_main_onion)) { - return; - } +#if !DISABLE_BATCHING + if (iter->geom != NULL) { + if (iter->instancing) { + DRW_shgroup_call_instance_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); + } + else { + DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount); } } +#endif + + iter->geom = NULL; + iter->vfirst = -1; + iter->vcount = 0; } -void GPENCIL_cache_init(void *vedata) +/* Group drawcalls that are consecutive and with the same type. Reduces GPU driver overhead. */ +static void gp_drawcall_add( + gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count) { - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - ToolSettings *ts = scene->toolsettings; - View3D *v3d = draw_ctx->v3d; - Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); - const View3DCursor *cursor = &scene->cursor; - - /* 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; - /* use the brush material */ - Material *ma = BKE_gpencil_object_material_get_from_brush(obact, 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_gpencil_material_settings(obact, obact->actcol); - } +#if DISABLE_BATCHING + if (instancing) { + DRW_shgroup_call_instance_range(iter->grp, iter->ob, geom, v_first, v_count); } + else { + DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count); + } +#endif - 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 */ + int last = iter->vfirst + iter->vcount; + /* Interupt drawcall grouping if the sequence is not consecutive. */ + if ((geom != iter->geom) || (v_first - last > 3)) { + gp_drawcall_flush(iter); + } + iter->geom = geom; + iter->instancing = instancing; + if (iter->vfirst == -1) { + iter->vfirst = v_first; } - stl->storage->tonemapping = 0; + iter->vcount = v_first + v_count - iter->vfirst; +} - stl->g_data->shgrps_edit_line = NULL; - stl->g_data->shgrps_edit_point = NULL; +static void gp_stroke_cache_populate(bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, void *thunk); - /* reset textures */ - stl->g_data->batch_buffer_stroke = NULL; - stl->g_data->batch_buffer_fill = NULL; - stl->g_data->batch_buffer_ctrlpoint = NULL; - stl->g_data->batch_grid = NULL; +static void gp_sbuffer_cache_populate(gpIterPopulateData *iter) +{ + iter->do_sbuffer_call = DRAW_NOW; + /* In order to draw the sbuffer stroke correctly mixed with other strokes, + * we need to offset the stroke index of the sbuffer stroke and the subsequent strokes. + * Remember, sbuffer stroke indices start from 0. So we add last index to avoid + * masking issues. */ + iter->grp = DRW_shgroup_create_sub(iter->grp); + DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", iter->ubo_mat); + DRW_shgroup_uniform_float_copy(iter->grp, "strokeIndexOffset", iter->stroke_index_last); + + const DRWContextState *ctx = DRW_context_state_get(); + ToolSettings *ts = ctx->scene->toolsettings; + if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) { + /* In this case we can't do correct projection during stroke. We just disable depth test. */ + DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx); + } + + gp_stroke_cache_populate(NULL, NULL, iter->pd->sbuffer_stroke, iter); + gp_drawcall_flush(iter); + + iter->stroke_index_offset = iter->pd->sbuffer_stroke->totpoints + 1; + iter->do_sbuffer_call = 0; +} - if (!stl->shgroups) { - /* Alloc maximum size because count strokes is very slow and can be very complex due onion - * skinning. - */ - stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup"); +static void gp_layer_cache_populate(bGPDlayer *gpl, + bGPDframe *gpf, + bGPDstroke *UNUSED(gps), + void *thunk) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + gpIterPopulateData *iter = (gpIterPopulateData *)thunk; + bGPdata *gpd = (bGPdata *)iter->ob->data; + + gp_drawcall_flush(iter); + + if (iter->do_sbuffer_call) { + gp_sbuffer_cache_populate(iter); + } + else { + iter->do_sbuffer_call = !iter->pd->do_fast_drawing && (gpd == iter->pd->sbuffer_gpd) && + (gpl == iter->pd->sbuffer_layer); + } + + GPENCIL_tLayer *tgp_layer_prev = iter->tgp_ob->layers.last; + GPENCIL_tLayer *tgp_layer = gpencil_layer_cache_add(iter->pd, iter->ob, gpl); + BLI_LINKS_APPEND(&iter->tgp_ob->layers, tgp_layer); + + if (tgp_layer->is_masked && (tgp_layer_prev == NULL || !tgp_layer_prev->is_masked)) { + tgp_layer->do_masked_clear = true; + } + + gpencil_material_resources_get(iter->matpool, 0, NULL, NULL, &iter->ubo_mat); + + const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D) || iter->pd->draw_depth_only; + const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0; + + float object_scale = mat4_to_scale(iter->ob->obmat); + /* Negate thickness sign to tag that strokes are in screen space. + * Convert to world units (by default, 1 meter = 2000 px). */ + float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR); + + const bool use_lights = iter->pd->use_lighting && ((gpl->flag & GP_LAYER_USE_LIGHTS) != 0) && + (iter->ob->dtx & OB_USE_GPENCIL_LIGHTS); + iter->ubo_lights = (use_lights) ? iter->pd->global_light_pool->ubo : + iter->pd->shadeless_light_pool->ubo; + const bool is_in_front = (iter->ob->dtx & OB_DRAWXRAY); + + bool overide_vertcol = (iter->pd->v3d_color_type != -1); + bool is_vert_col_mode = (iter->pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) || + GPENCIL_VERTEX_MODE(gpd) || iter->pd->is_render; + float vert_col_opacity = (overide_vertcol) ? (is_vert_col_mode ? 1.0f : 0.0f) : + gpl->vertex_paint_opacity; + + /* Check if object is defined in front. */ + GPUTexture *depth_tex = (is_in_front) ? iter->pd->dummy_tx : iter->pd->scene_depth_tx; + + struct GPUShader *sh = GPENCIL_shader_geometry_get(); + iter->grp = DRW_shgroup_create(sh, tgp_layer->geom_ps); + DRW_shgroup_uniform_block_persistent(iter->grp, "gpLightBlock", iter->ubo_lights); + DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", iter->ubo_mat); + DRW_shgroup_uniform_texture(iter->grp, "gpFillTexture", iter->tex_fill); + DRW_shgroup_uniform_texture(iter->grp, "gpStrokeTexture", iter->tex_stroke); + DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", depth_tex); + DRW_shgroup_uniform_int_copy(iter->grp, "gpMaterialOffset", iter->mat_ofs); + DRW_shgroup_uniform_bool_copy(iter->grp, "strokeOrder3d", is_stroke_order_3d); + DRW_shgroup_uniform_vec3_copy(iter->grp, "gpNormal", iter->tgp_ob->plane_normal); + DRW_shgroup_uniform_vec2_copy(iter->grp, "sizeViewportInv", DRW_viewport_invert_size_get()); + DRW_shgroup_uniform_vec2_copy(iter->grp, "sizeViewport", DRW_viewport_size_get()); + DRW_shgroup_uniform_float_copy(iter->grp, "thicknessScale", object_scale); + DRW_shgroup_uniform_float_copy(iter->grp, "thicknessOffset", (float)gpl->line_change); + DRW_shgroup_uniform_float_copy(iter->grp, "thicknessWorldScale", thickness_scale); + DRW_shgroup_uniform_float_copy(iter->grp, "vertexColorOpacity", vert_col_opacity); + DRW_shgroup_uniform_float_copy(iter->grp, "strokeIndexOffset", iter->stroke_index_offset); + DRW_shgroup_stencil_mask(iter->grp, 0xFF); + + bool use_onion = gpf && gpf->runtime.onion_id != 0.0f; + if (use_onion) { + const bool use_onion_custom_col = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0; + const bool use_onion_fade = (gpd->onion_flag & GP_ONION_FADE) != 0; + const bool use_next_col = gpf->runtime.onion_id > 0.0f; + float *onion_col_custom = (use_next_col) ? gpd->gcolor_next : gpd->gcolor_prev; + onion_col_custom = (use_onion_custom_col) ? onion_col_custom : U.gpencil_new_layer_col; + float onion_col[4] = {UNPACK3(onion_col_custom), 1.0f}; + float onion_alpha = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f; + onion_alpha += (gpd->onion_factor * 2.0f - 1.0f); + onion_alpha = clamp_f(onion_alpha, 0.01f, 1.0f); + + DRW_shgroup_uniform_vec4_copy(iter->grp, "layerTint", onion_col); + DRW_shgroup_uniform_float_copy(iter->grp, "layerOpacity", onion_alpha); + } + else { + float alpha = GPENCIL_SIMPLIFY_TINT(scene) ? 0.0f : gpl->tintcolor[3]; + float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha}; + DRW_shgroup_uniform_vec4_copy(iter->grp, "layerTint", tintcolor); + DRW_shgroup_uniform_float_copy(iter->grp, "layerOpacity", 1.0f); } +} - /* 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; - stl->g_data->do_instances = false; +static void gp_stroke_cache_populate(bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, void *thunk) +{ + gpIterPopulateData *iter = (gpIterPopulateData *)thunk; - { - /* Stroke pass 2D */ - psl->stroke_pass_2d = DRW_pass_create("GPencil Stroke Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA | - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - stl->storage->shgroup_id = 0; - /* Stroke pass 3D */ - psl->stroke_pass_3d = DRW_pass_create("GPencil Stroke Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | - DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA | - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - stl->storage->shgroup_id = 0; - - /* edit pass */ - psl->edit_pass = DRW_pass_create("GPencil Edit Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); - - /* detect if playing animation */ - if (draw_ctx->evil_C) { - - bool playing = ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != NULL; - if (playing != stl->storage->is_playing) { - stl->storage->reset_cache = true; - } - stl->storage->is_playing = playing; + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1); - /* Found if main overlay and onion switches are enabled in any screen. */ - gpencil_check_screen_switches(draw_ctx, stl); - } - else { - stl->storage->is_playing = false; - stl->storage->reset_cache = false; - stl->storage->is_main_overlay = false; - stl->storage->is_main_onion = false; - } - /* save render state */ - stl->storage->is_render = DRW_state_is_scene_render(); - stl->storage->is_mat_preview = (bool)stl->storage->is_render && - STREQ(scene->id.name + 2, "preview"); - - 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->is_playing == true) { - 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; - } - } + bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; + bool show_fill = (gps->tot_triangles > 0) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) && + (!iter->pd->simplify_fill); - /* save simplify flags (can change while drawing, so it's better to save) */ - stl->storage->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, stl->storage->is_playing); - stl->storage->simplify_modif = GPENCIL_SIMPLIFY_MODIF(scene, stl->storage->is_playing); - stl->storage->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, stl->storage->is_playing); - stl->storage->simplify_blend = GPENCIL_SIMPLIFY_BLEND(scene, stl->storage->is_playing); + bool only_lines = gpl && gpf && gpl->actframe != gpf && iter->pd->use_multiedit_lines_only; - /* xray mode */ - if (v3d) { - stl->storage->is_xray = XRAY_ACTIVE(v3d); - } - else { - stl->storage->is_xray = 0; - } + if (hide_material || (!show_stroke && !show_fill) || only_lines) { + return; + } - /* 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; - } + GPUUniformBuffer *ubo_mat; + GPUTexture *tex_stroke, *tex_fill; + gpencil_material_resources_get(iter->matpool, gps->mat_nr, &tex_stroke, &tex_fill, &ubo_mat); - /* Detect if painting session. */ - if ((obact_gpd) && (obact_gpd->flag & GP_DATA_STROKE_PAINTMODE) && - (stl->storage->is_playing == false)) { - /* Need the original to avoid cow overhead while drawing. */ - bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&obact_gpd->id); - if (((gpd_orig->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) && - (gpd_orig->runtime.sbuffer_used > 0) && (!DRW_state_is_depth()) && - (stl->storage->background_ready == true)) { - 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; - } + bool resource_changed = (iter->ubo_mat != ubo_mat) || + (tex_fill && (iter->tex_fill != tex_fill)) || + (tex_stroke && (iter->tex_stroke != tex_stroke)); - 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; - } - } + if (resource_changed) { + gp_drawcall_flush(iter); + + iter->grp = DRW_shgroup_create_sub(iter->grp); + if (iter->ubo_mat != ubo_mat) { + DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", ubo_mat); + iter->ubo_mat = ubo_mat; } - else { - stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID; - stl->storage->color_type = GPENCIL_COLOR_SOLID; + if (tex_fill) { + DRW_shgroup_uniform_texture(iter->grp, "gpFillTexture", tex_fill); + iter->tex_fill = tex_fill; } - - /* drawing buffer pass for drawing the stroke that is being 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_ALPHA | - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | - DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL); - - /* 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_ALPHA | - 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(mix_shgrp, quad, NULL); - DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &stl->g_data->input_color_tx); - DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &stl->g_data->input_depth_tx); - DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1); - DRW_shgroup_uniform_int(mix_shgrp, "do_select", &stl->storage->do_select_outline, 1); - DRW_shgroup_uniform_vec4(mix_shgrp, "select_color", stl->storage->select_color, 1); - - /* Mix pass no blend used to copy between passes. A separated pass is required - * because if mix_pass is used, the accumulation 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(mix_shgrp_noblend, quad, NULL); - DRW_shgroup_uniform_texture_ref( - mix_shgrp_noblend, "strokeColor", &stl->g_data->input_color_tx); - DRW_shgroup_uniform_texture_ref( - mix_shgrp_noblend, "strokeDepth", &stl->g_data->input_depth_tx); - DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 1); - DRW_shgroup_uniform_int(mix_shgrp_noblend, "do_select", &stl->storage->do_select_outline, 1); - DRW_shgroup_uniform_vec4(mix_shgrp_noblend, "select_color", stl->storage->select_color, 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_ALPHA | - 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(background_shgrp, quad, NULL); - DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &txl->background_color_tx); - DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &txl->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_ALPHA); - DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass); - DRW_shgroup_call(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); + if (tex_stroke) { + DRW_shgroup_uniform_texture(iter->grp, "gpStrokeTexture", tex_stroke); + iter->tex_stroke = tex_stroke; } + } - /* grid pass */ - if ((v3d) && (obact) && (obact->type == OB_GPENCIL)) { - psl->grid_pass = DRW_pass_create("GPencil Grid Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); - stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass); - - /* define grid orientation */ - switch (ts->gp_sculpt.lock_axis) { - case GP_LOCKAXIS_VIEW: { - /* align always to view */ - invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat); - /* copy ob location */ - copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]); - break; - } - case GP_LOCKAXIS_CURSOR: { - float scale[3] = {1.0f, 1.0f, 1.0f}; - loc_eul_size_to_mat4( - stl->storage->grid_matrix, cursor->location, cursor->rotation_euler, scale); - break; - } - default: { - copy_m4_m4(stl->storage->grid_matrix, obact->obmat); - break; - } - } + bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW); - /* Move the origin to Object or Cursor */ - if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { - copy_v3_v3(stl->storage->grid_matrix[3], cursor->location); - } - else { - copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]); - } - DRW_shgroup_uniform_mat4( - stl->g_data->shgrps_grid, "gpModelMatrix", stl->storage->grid_matrix); - } + if (show_fill) { + GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_fill_get(iter->ob) : + DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra); + int vfirst = gps->runtime.fill_start * 3; + int vcount = gps->tot_triangles * 3; + gp_drawcall_add(iter, geom, false, vfirst, vcount); + } - /* blend layers pass */ - psl->blend_pass = DRW_pass_create("GPencil Blend Layers Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); - DRWShadingGroup *blend_shgrp = DRW_shgroup_create(e_data.gpencil_blend_fullscreen_sh, - psl->blend_pass); - DRW_shgroup_call(blend_shgrp, quad, NULL); - DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); - DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &stl->g_data->temp_color_tx_fx); - DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &stl->g_data->temp_depth_tx_fx); - DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1); - DRW_shgroup_uniform_int(blend_shgrp, "mask_layer", &stl->storage->mask_layer, 1); - DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1); - - /* create effects passes */ - if (!stl->storage->simplify_fx) { - GPENCIL_create_fx_passes(psl); - } + if (show_stroke) { + GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_stroke_get(iter->ob) : + DRW_cache_gpencil_strokes_get(iter->ob, iter->pd->cfra); + /* Start one vert before to have gl_InstanceID > 0 (see shader). */ + int vfirst = gps->runtime.stroke_start - 1; + /* Include "potential" cyclic vertex and start adj vertex (see shader). */ + int vcount = gps->totpoints + 1 + 1; + gp_drawcall_add(iter, geom, true, vfirst, vcount); } + + iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1; } -static void gpencil_add_draw_data(void *vedata, Object *ob) +static void gp_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter) { - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - bGPdata *gpd = (bGPdata *)ob->data; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); - const DRWContextState *draw_ctx = DRW_context_state_get(); - const View3D *v3d = draw_ctx->v3d; + bGPdata *gpd = (bGPdata *)iter->ob->data; + if (gpd != iter->pd->sbuffer_gpd) { + return; + } - int i = stl->g_data->gp_cache_used - 1; - tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i]; + GPENCIL_TextureList *txl = vedata->txl; + GPUTexture *depth_texture = iter->pd->scene_depth_tx; + GPENCIL_tObject *last_tgp_ob = iter->pd->tobjects.last; + /* Create another temp object that only contain the stroke. */ + iter->tgp_ob = gpencil_object_cache_add(iter->pd, iter->ob); + /* Remove from the main list. */ + iter->pd->tobjects.last = last_tgp_ob; + last_tgp_ob->next = NULL; + /* Add to sbuffer tgpobject list. */ + BLI_LINKS_APPEND(&iter->pd->sbuffer_tobjects, iter->tgp_ob); + /* Remove depth test with scene (avoid self occlusion). */ + iter->pd->scene_depth_tx = txl->dummy_texture; - if (!cache_ob->is_dup_ob) { - /* fill shading groups */ - if ((!is_multiedit) || (stl->storage->is_render)) { - gpencil_populate_datablock(&e_data, vedata, ob, cache_ob); - } - else { - gpencil_populate_multiedit(&e_data, vedata, ob, cache_ob); - } - } + gp_layer_cache_populate(iter->pd->sbuffer_layer, iter->pd->sbuffer_layer->actframe, NULL, iter); - /* FX passses */ - cache_ob->has_fx = false; - if ((!stl->storage->simplify_fx) && - ((!ELEM(cache_ob->shading_type[0], OB_WIRE, OB_SOLID)) || - ((v3d->spacetype != SPACE_VIEW3D))) && - (BKE_shaderfx_has_gpencil(ob))) { - cache_ob->has_fx = true; - if ((!stl->storage->simplify_fx) && (!is_multiedit)) { - gpencil_fx_prepare(&e_data, vedata, cache_ob); - } + const DRWContextState *ctx = DRW_context_state_get(); + ToolSettings *ts = ctx->scene->toolsettings; + if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) { + /* In this case we can't do correct projection during stroke. We just disable depth test. */ + DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx); } + + iter->do_sbuffer_call = DRAW_NOW; + gp_stroke_cache_populate(NULL, NULL, iter->pd->sbuffer_stroke, iter); + gp_drawcall_flush(iter); + + gpencil_vfx_cache_populate(vedata, iter->ob, iter->tgp_ob); + + /* Restore state. */ + iter->do_sbuffer_call = 0; + iter->pd->scene_depth_tx = depth_texture; } -void GPENCIL_cache_populate(void *vedata, Object *ob) +void GPENCIL_cache_populate(void *ved, Object *ob) { + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_TextureList *txl = vedata->txl; + /* object must be visible */ if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { 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; + if (ob->data && (ob->type == OB_GPENCIL) && (ob->dt >= OB_SOLID)) { + gpIterPopulateData iter = {0}; + iter.ob = ob; + iter.pd = pd; + iter.tgp_ob = gpencil_object_cache_add(pd, ob); + iter.matpool = gpencil_material_pool_create(pd, ob, &iter.mat_ofs); + iter.tex_fill = txl->dummy_texture; + iter.tex_stroke = txl->dummy_texture; - if (ob->type == OB_GPENCIL && ob->data) { + /* Specil case for rendering onion skin. */ bGPdata *gpd = (bGPdata *)ob->data; + bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS); - /* enable multisample and basic framebuffer creation */ - stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_MULTISAMPLE; - stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_BASIC; + BKE_gpencil_visible_stroke_iter( + ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, do_onion, pd->cfra); - /* when start/stop animation the cache must be set as dirty to reset all data */ - if (stl->storage->reset_cache) { - gpd->flag |= GP_DATA_CACHE_IS_DIRTY; - stl->storage->reset_cache = false; - } - - if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) { - /* bound box object are not visible, only external box*/ - if (ob->dt != OB_BOUNDBOX) { - /* save gp objects for drawing later */ - stl->g_data->gp_object_cache = gpencil_object_cache_add(stl->g_data->gp_object_cache, - ob, - &stl->g_data->gp_cache_size, - &stl->g_data->gp_cache_used); - - /* enable instance loop */ - if (!stl->g_data->do_instances) { - tGPencilObjectCache *cache_ob = - &stl->g_data->gp_object_cache[stl->g_data->gp_cache_used - 1]; - stl->g_data->do_instances = cache_ob->is_dup_ob; - } - - /* load drawing data */ - gpencil_add_draw_data(vedata, ob); - } - } + gp_drawcall_flush(&iter); - /* draw current painting strokes - * (only if region is equal to originated paint region) - * - * Need to use original data because to use the copy of data, the paint - * operator must update depsgraph and this makes that first events of the - * mouse are missed if the datablock is very big due the time required to - * copy the datablock. The search of the original data is faster than a - * full datablock copy. - * Using the original data doesn't require a copy and the feel when drawing - * is far better. - */ - - bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id); - if ((draw_ctx->obact == ob) && - ((gpd_orig->runtime.ar == NULL) || (gpd_orig->runtime.ar == draw_ctx->ar))) { - gpencil_populate_buffer_strokes(&e_data, vedata, ts, ob); + if (iter.do_sbuffer_call) { + gp_sbuffer_cache_populate(&iter); } - /* grid */ - if ((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID) && - (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact) && - ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0) && - ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) == 0)) { + gpencil_vfx_cache_populate(vedata, ob, iter.tgp_ob); - stl->g_data->batch_grid = gpencil_get_grid(ob); - DRW_shgroup_call(stl->g_data->shgrps_grid, stl->g_data->batch_grid, NULL); + if (pd->do_fast_drawing) { + gp_sbuffer_cache_populate_fast(vedata, &iter); } } + + if (ob->type == OB_LAMP && pd->use_lights) { + gpencil_light_pool_populate(pd->global_light_pool, ob); + } } -void GPENCIL_cache_finish(void *vedata) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - tGPencilObjectCache *cache_ob = NULL; - Object *ob = NULL; - - /* create data for instances */ - if (stl->g_data->do_instances) { - GHash *gh_objects = BLI_ghash_str_new(__func__); - /* create hash of real object (non duplicated) */ - for (int i = 0; i < stl->g_data->gp_cache_used; i++) { - cache_ob = &stl->g_data->gp_object_cache[i]; - if (!cache_ob->is_dup_ob) { - ob = cache_ob->ob; - char *name = BKE_id_to_unique_string_key(&ob->id); - BLI_ghash_insert(gh_objects, name, cache_ob->ob); - } - } +#define SORT_IMPL_LINKTYPE GPENCIL_tObject - /* draw particles */ - gpencil_populate_particles(&e_data, gh_objects, vedata); +#define SORT_IMPL_FUNC gpencil_tobject_sort_fn_r +#include "../../blenlib/intern/list_sort_impl.h" +#undef SORT_IMPL_FUNC - /* free hash */ - BLI_ghash_free(gh_objects, MEM_freeN, NULL); - } +#undef SORT_IMPL_LINKTYPE - if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) { - stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_DRAW; +static int gpencil_tobject_dist_sort(const void *a, const void *b) +{ + const GPENCIL_tObject *ob_a = (const GPENCIL_tObject *)a; + const GPENCIL_tObject *ob_b = (const GPENCIL_tObject *)b; + /* Reminder, camera_z is negative in front of the camera. */ + if (ob_a->camera_z > ob_b->camera_z) { + return 1; } - - /* create framebuffers (only for normal drawing) */ - if (!DRW_state_is_select() || !DRW_state_is_depth()) { - GPENCIL_create_framebuffers(vedata); + else if (ob_a->camera_z < ob_b->camera_z) { + return -1; + } + else { + return 0; } } -/* helper function to sort inverse gpencil objects using qsort */ -static int gpencil_object_cache_compare_zdepth(const void *a1, const void *a2) +void GPENCIL_cache_finish(void *ved) { - const tGPencilObjectCache *ps1 = a1, *ps2 = a2; + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_FramebufferList *fbl = vedata->fbl; - if (ps1->zdepth < ps2->zdepth) { - return 1; - } - else if (ps1->zdepth > ps2->zdepth) { - return -1; + /* Upload UBO data. */ + BLI_memblock_iter iter; + BLI_memblock_iternew(pd->gp_material_pool, &iter); + GPENCIL_MaterialPool *pool; + while ((pool = (GPENCIL_MaterialPool *)BLI_memblock_iterstep(&iter))) { + GPU_uniformbuffer_update(pool->ubo, pool->mat_data); } - return 0; -} + BLI_memblock_iternew(pd->gp_light_pool, &iter); + GPENCIL_LightPool *lpool; + while ((lpool = (GPENCIL_LightPool *)BLI_memblock_iterstep(&iter))) { + GPU_uniformbuffer_update(lpool->ubo, lpool->light_data); + } -/* 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_stencil(fbl->background_fb, clearcol, 1.0f, 0x0); - stl->g_data->session_flag = GP_DRW_PAINT_FILLING; + /* Sort object by distance to the camera. */ + if (pd->tobjects.first) { + pd->tobjects.first = gpencil_tobject_sort_fn_r(pd->tobjects.first, gpencil_tobject_dist_sort); + /* Relink last pointer. */ + while ((pd->tobjects.last->next != NULL)) { + pd->tobjects.last = pd->tobjects.last->next; } - /* repeat pass to fill temp texture */ - DRW_draw_pass(pass); - /* set default framebuffer again */ - GPU_framebuffer_bind(dfbl->default_fb); + } + if (pd->tobjects_infront.first) { + pd->tobjects_infront.first = gpencil_tobject_sort_fn_r(pd->tobjects_infront.first, + gpencil_tobject_dist_sort); + /* Relink last pointer. */ + while ((pd->tobjects_infront.last->next != NULL)) { + pd->tobjects_infront.last = pd->tobjects_infront.last->next; + } + } - stl->storage->background_ready = true; + /* Join both lists, adding infront. */ + if (pd->tobjects_infront.first != NULL) { + if (pd->tobjects.last != NULL) { + pd->tobjects.last->next = pd->tobjects_infront.first; + pd->tobjects.last = pd->tobjects_infront.last; + } + else { + /* Only in front objects. */ + pd->tobjects.first = pd->tobjects_infront.first; + pd->tobjects.last = pd->tobjects_infront.last; + } } -} -void DRW_gpencil_free_runtime_data(void *ved) -{ - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + /* Create framebuffers only if needed. */ + if (pd->tobjects.first) { + eGPUTextureFormat format = pd->use_signed_fb ? GPU_RGBA16F : GPU_R11F_G11F_B10F; + + const float *size = DRW_viewport_size_get(); + pd->depth_tx = DRW_texture_pool_query_2d( + size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type); + pd->color_tx = DRW_texture_pool_query_2d(size[0], size[1], format, &draw_engine_gpencil_type); + pd->reveal_tx = DRW_texture_pool_query_2d(size[0], size[1], format, &draw_engine_gpencil_type); - /* free gpu data */ - GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_stroke); - MEM_SAFE_FREE(stl->g_data->batch_buffer_stroke); + GPU_framebuffer_ensure_config(&fbl->gpencil_fb, + { + GPU_ATTACHMENT_TEXTURE(pd->depth_tx), + GPU_ATTACHMENT_TEXTURE(pd->color_tx), + GPU_ATTACHMENT_TEXTURE(pd->reveal_tx), + }); - GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_fill); - MEM_SAFE_FREE(stl->g_data->batch_buffer_fill); + if (pd->use_layer_fb) { + pd->color_layer_tx = DRW_texture_pool_query_2d( + size[0], size[1], format, &draw_engine_gpencil_type); + pd->reveal_layer_tx = DRW_texture_pool_query_2d( + size[0], size[1], format, &draw_engine_gpencil_type); - GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_ctrlpoint); - MEM_SAFE_FREE(stl->g_data->batch_buffer_ctrlpoint); + GPU_framebuffer_ensure_config(&fbl->layer_fb, + { + GPU_ATTACHMENT_TEXTURE(pd->depth_tx), + GPU_ATTACHMENT_TEXTURE(pd->color_layer_tx), + GPU_ATTACHMENT_TEXTURE(pd->reveal_layer_tx), + }); + }; - GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_grid); - MEM_SAFE_FREE(stl->g_data->batch_grid); + if (pd->use_object_fb) { + pd->color_object_tx = DRW_texture_pool_query_2d( + size[0], size[1], format, &draw_engine_gpencil_type); + pd->reveal_object_tx = DRW_texture_pool_query_2d( + size[0], size[1], format, &draw_engine_gpencil_type); - if (stl->g_data->gp_object_cache == NULL) { - return; - } + GPU_framebuffer_ensure_config(&fbl->object_fb, + { + GPU_ATTACHMENT_TEXTURE(pd->depth_tx), + GPU_ATTACHMENT_TEXTURE(pd->color_object_tx), + GPU_ATTACHMENT_TEXTURE(pd->reveal_object_tx), + }); + } + + if (pd->use_mask_fb) { + /* We need to separate all the masked layer together in order to correctly mix them. */ + pd->color_masked_tx = DRW_texture_pool_query_2d( + size[0], size[1], format, &draw_engine_gpencil_type); + pd->reveal_masked_tx = DRW_texture_pool_query_2d( + size[0], size[1], format, &draw_engine_gpencil_type); - /* reset all cache flags */ - for (int i = 0; i < stl->g_data->gp_cache_used; i++) { - tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i]; - if (cache_ob) { - bGPdata *gpd = cache_ob->gpd; - gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; + GPU_framebuffer_ensure_config(&fbl->masked_fb, + { + GPU_ATTACHMENT_TEXTURE(pd->depth_tx), + GPU_ATTACHMENT_TEXTURE(pd->color_masked_tx), + GPU_ATTACHMENT_TEXTURE(pd->reveal_masked_tx), + }); + } - /* free shgrp array */ - cache_ob->tot_layers = 0; - MEM_SAFE_FREE(cache_ob->name); - MEM_SAFE_FREE(cache_ob->shgrp_array); + if (!pd->simplify_antialias) { + GPENCIL_antialiasing_init(vedata); } } - - /* free the cache itself */ - MEM_SAFE_FREE(stl->g_data->gp_object_cache); } -static void gpencil_draw_pass_range(GPENCIL_FramebufferList *fbl, - GPENCIL_StorageList *stl, - GPENCIL_PassList *psl, - GPENCIL_TextureList *txl, - GPUFrameBuffer *fb, - Object *ob, - bGPdata *gpd, - DRWShadingGroup *init_shgrp, - DRWShadingGroup *end_shgrp, - bool multi) +static void GPENCIL_draw_scene_depth_only(void *ved) { - if (init_shgrp == NULL) { - return; - } - - const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi)); + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_PrivateData *pd = vedata->stl->pd; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - if (do_antialiasing) { - MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(dfbl->depth_only_fb); } - DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d, - init_shgrp, - end_shgrp); + for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) { + for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) { + DRW_draw_pass(layer->geom_ps); + } + } - if (do_antialiasing) { - MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl); + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(dfbl->default_fb); } -} -/* draw strokes to use for selection */ -static void drw_gpencil_select_render(GPENCIL_StorageList *stl, GPENCIL_PassList *psl) -{ - tGPencilObjectCache *cache_ob; - tGPencilObjectCache_shgrp *array_elm = NULL; - DRWShadingGroup *init_shgrp = NULL; - DRWShadingGroup *end_shgrp = NULL; - - /* Draw all pending objects */ - if ((stl->g_data->gp_cache_used > 0) && (stl->g_data->gp_object_cache)) { - /* 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_ob = &stl->g_data->gp_object_cache[i]; - if (cache_ob) { - Object *ob = cache_ob->ob; - bGPdata *gpd = cache_ob->gpd; - init_shgrp = NULL; - if (cache_ob->tot_layers > 0) { - for (int e = 0; e < cache_ob->tot_layers; e++) { - array_elm = &cache_ob->shgrp_array[e]; - if (init_shgrp == NULL) { - init_shgrp = array_elm->init_shgrp; - } - end_shgrp = array_elm->end_shgrp; - } - /* draw group */ - DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : - psl->stroke_pass_2d, - init_shgrp, - end_shgrp); - } - /* the cache must be dirty for next loop */ - gpd->flag |= GP_DATA_CACHE_IS_DIRTY; - } - } + pd->gp_object_pool = pd->gp_layer_pool = pd->gp_vfx_pool = NULL; + + /* Free temp stroke buffers. */ + if (pd->sbuffer_gpd) { + DRW_cache_gpencil_sbuffer_clear(pd->obact); } } -/* draw scene */ -void GPENCIL_draw_scene(void *ved) +static void GPENCIL_draw_object(GPENCIL_Data *vedata, GPENCIL_tObject *ob) { - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = vedata->psl; + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_FramebufferList *fbl = vedata->fbl; + float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}; - 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; + DRW_stats_group_start("GPencil Object"); - tGPencilObjectCache *cache_ob; - tGPencilObjectCache_shgrp *array_elm = NULL; - DRWShadingGroup *init_shgrp = NULL; - DRWShadingGroup *end_shgrp = NULL; + GPUFrameBuffer *fb_object = (ob->vfx.first) ? fbl->object_fb : fbl->gpencil_fb; - const float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_bind(fb_object); + GPU_framebuffer_clear_depth_stencil(fb_object, ob->is_drawmode3d ? 1.0f : 0.0f, 0x00); - const DRWContextState *draw_ctx = DRW_context_state_get(); - View3D *v3d = draw_ctx->v3d; - Object *obact = draw_ctx->obact; - const bool playing = stl->storage->is_playing; - const bool is_render = stl->storage->is_render; - bGPdata *gpd_act = (obact) && (obact->type == OB_GPENCIL) ? (bGPdata *)obact->data : NULL; - const bool is_edit = (GPENCIL_ANY_EDIT_MODE(gpd_act) || GPENCIL_VERTEX_MODE(gpd_act)); - const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true; - - /* if the draw is for select, do a basic drawing and return */ - if (DRW_state_is_select() || DRW_state_is_depth()) { - drw_gpencil_select_render(stl, psl); - return; + if (ob->vfx.first) { + GPU_framebuffer_multi_clear(fb_object, clear_cols); } - /* paper pass to display a comfortable area to draw over complex scenes with geometry */ - if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { - if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_PAPER)) { - DRW_draw_pass(psl->paper_pass); + for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) { + if (layer->blend_ps) { + GPU_framebuffer_bind(fbl->layer_fb); + GPU_framebuffer_multi_clear(fbl->layer_fb, clear_cols); + } + else if (layer->is_masked) { + GPU_framebuffer_bind(fbl->masked_fb); + if (layer->do_masked_clear) { + GPU_framebuffer_multi_clear(fbl->masked_fb, clear_cols); + } + } + else { + GPU_framebuffer_bind(fb_object); } - } - /* 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); + DRW_draw_pass(layer->geom_ps); - if (obact->dt != OB_BOUNDBOX) { - DRW_draw_pass(psl->background_pass); + if (layer->blend_ps) { + if (layer->is_masked) { + GPU_framebuffer_bind(fbl->masked_fb); + if (layer->do_masked_clear) { + GPU_framebuffer_multi_clear(fbl->masked_fb, clear_cols); + } + } + else { + GPU_framebuffer_bind(fb_object); + } + DRW_draw_pass(layer->blend_ps); } + } - MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); + for (GPENCIL_tVfx *vfx = ob->vfx.first; vfx; vfx = vfx->next) { + GPU_framebuffer_bind(*(vfx->target_fb)); + DRW_draw_pass(vfx->vfx_ps); + } - DRW_draw_pass(psl->drawing_pass); + copy_m4_m4(pd->object_bound_mat, ob->plane_mat); + pd->is_stroke_order_3d = ob->is_drawmode3d; - MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, dfbl->default_fb, txl); + if (pd->scene_fb) { + GPU_framebuffer_bind(pd->scene_fb); + DRW_draw_pass(psl->merge_depth_ps); + } - /* grid pass */ - if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { - if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID)) { - DRW_draw_pass(psl->grid_pass); - } - } + DRW_stats_group_end(); +} - /* free memory */ - DRW_gpencil_free_runtime_data(ved); +static void GPENCIL_fast_draw_start(GPENCIL_Data *vedata) +{ + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_FramebufferList *fbl = vedata->fbl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - return; + if (!pd->snapshot_buffer_dirty) { + /* Copy back cached render. */ + GPU_framebuffer_blit(fbl->snapshot_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT); + GPU_framebuffer_blit(fbl->snapshot_fb, 0, fbl->gpencil_fb, 0, GPU_COLOR_BIT); + GPU_framebuffer_blit(fbl->snapshot_fb, 1, fbl->gpencil_fb, 1, GPU_COLOR_BIT); + /* Bypass drawing. */ + pd->tobjects.first = pd->tobjects.last = NULL; } +} - if (DRW_state_is_fbo()) { +static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata) +{ + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_FramebufferList *fbl = vedata->fbl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - /* 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_ob = &stl->g_data->gp_object_cache[i]; - Object *ob = cache_ob->ob; - bGPdata *gpd = cache_ob->gpd; - init_shgrp = NULL; - /* Render stroke in separated framebuffer */ - GPU_framebuffer_bind(fbl->temp_fb_a); - GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_a, clearcol, 1.0f, 0x0); - /* Stroke Pass: - * draw only a subset that usually starts with a fill and ends with stroke - */ - bool use_blend = false; - if (cache_ob->tot_layers > 0) { - for (int e = 0; e < cache_ob->tot_layers; e++) { - bool is_last = (e == cache_ob->tot_layers - 1) ? true : false; - array_elm = &cache_ob->shgrp_array[e]; - - if (((array_elm->mode == eGplBlendMode_Regular) && (!use_blend) && - (!array_elm->mask_layer)) || - (e == 0)) { - if (init_shgrp == NULL) { - init_shgrp = array_elm->init_shgrp; - } - end_shgrp = array_elm->end_shgrp; - } - else { - use_blend = true; - /* draw pending groups */ - gpencil_draw_pass_range( - fbl, stl, psl, txl, fbl->temp_fb_a, ob, gpd, init_shgrp, end_shgrp, is_last); - - /* Draw current group in separated texture to blend later */ - init_shgrp = array_elm->init_shgrp; - end_shgrp = array_elm->end_shgrp; - - GPU_framebuffer_bind(fbl->temp_fb_fx); - GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_fx, clearcol, 1.0f, 0x0); - gpencil_draw_pass_range( - fbl, stl, psl, txl, fbl->temp_fb_fx, ob, gpd, init_shgrp, end_shgrp, is_last); - - /* Blend A texture and FX texture */ - GPU_framebuffer_bind(fbl->temp_fb_b); - GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_b, clearcol, 1.0f, 0x0); - stl->storage->blend_mode = array_elm->mode; - stl->storage->mask_layer = (int)array_elm->mask_layer; - stl->storage->tonemapping = DRW_state_do_color_management() ? 0 : 1; - DRW_draw_pass(psl->blend_pass); - stl->storage->tonemapping = 0; - - /* Copy B texture to A texture to follow loop */ - stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b; - stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b; - - GPU_framebuffer_bind(fbl->temp_fb_a); - GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_a, clearcol, 1.0f, 0x0); - DRW_draw_pass(psl->mix_pass_noblend); - - /* prepare next group */ - init_shgrp = NULL; - } - } - /* last group */ - gpencil_draw_pass_range( - fbl, stl, psl, txl, fbl->temp_fb_a, ob, gpd, init_shgrp, end_shgrp, true); - } + if (pd->snapshot_buffer_dirty) { + /* Save to snapshot buffer. */ + GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->snapshot_fb, 0, GPU_DEPTH_BIT); + GPU_framebuffer_blit(fbl->gpencil_fb, 0, fbl->snapshot_fb, 0, GPU_COLOR_BIT); + GPU_framebuffer_blit(fbl->gpencil_fb, 1, fbl->snapshot_fb, 1, GPU_COLOR_BIT); + pd->snapshot_buffer_dirty = false; + } + /* Draw the sbuffer stroke(s). */ + for (GPENCIL_tObject *ob = pd->sbuffer_tobjects.first; ob; ob = ob->next) { + GPENCIL_draw_object(vedata, ob); + } +} - /* Current buffer drawing */ - if ((!is_render) && (cache_ob->is_dup_ob == false)) { - DRW_draw_pass(psl->drawing_pass); - } - /* fx passes */ - if (cache_ob->has_fx == true) { - stl->storage->tonemapping = 0; - gpencil_fx_draw(&e_data, vedata, cache_ob); - } +void GPENCIL_draw_scene(void *ved) +{ + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; + GPENCIL_PassList *psl = vedata->psl; + GPENCIL_PrivateData *pd = vedata->stl->pd; + GPENCIL_FramebufferList *fbl = vedata->fbl; + float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}; - stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_a; - stl->g_data->input_color_tx = stl->g_data->temp_color_tx_a; + /* Fade 3D objects. */ + if ((!pd->is_render) && (pd->fade_3d_object_opacity > -1.0f)) { + mul_v4_fl(clear_cols[1], pd->fade_3d_object_opacity); + } - /* 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 = DRW_state_do_color_management() ? 0 : 1; + if (pd->draw_depth_only) { + GPENCIL_draw_scene_depth_only(vedata); + return; + } - /* active select flag and selection color */ - if (!is_render) { - UI_GetThemeColorShadeAlpha4fv( - (ob == draw_ctx->obact) ? TH_ACTIVE : TH_SELECT, 0, -40, stl->storage->select_color); - } - stl->storage->do_select_outline = ((overlay) && (ob->base_flag & BASE_SELECTED) && - (ob->mode == OB_MODE_OBJECT) && (!is_render) && - (!playing) && (v3d->flag & V3D_SELECT_OUTLINE)); - - /* if active object is not object mode, disable for all objects */ - if ((stl->storage->do_select_outline) && (draw_ctx->obact) && - (draw_ctx->obact->mode != OB_MODE_OBJECT)) { - stl->storage->do_select_outline = 0; - } + if (pd->tobjects.first == NULL) { + return; + } - /* draw mix pass */ - DRW_draw_pass(psl->mix_pass); + if (pd->do_fast_drawing) { + GPENCIL_fast_draw_start(vedata); + } - /* disable select flag */ - stl->storage->do_select_outline = 0; + if (pd->tobjects.first) { + GPU_framebuffer_bind(fbl->gpencil_fb); + GPU_framebuffer_multi_clear(fbl->gpencil_fb, clear_cols); + } - /* prepare for fast drawing */ - if (!is_render) { - if (!playing) { - gpencil_prepare_fast_drawing(stl, dfbl, fbl, psl->mix_pass_noblend, clearcol); - } - } - else { - /* if render, the cache must be dirty for next loop */ - gpd->flag |= GP_DATA_CACHE_IS_DIRTY; - } - } - /* edit points */ - if ((!is_render) && (!playing) && (is_edit)) { - DRW_draw_pass(psl->edit_pass); - } - } - /* grid pass */ - if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) { - if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID)) { - DRW_draw_pass(psl->grid_pass); - } - } + for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) { + GPENCIL_draw_object(vedata, ob); } - /* free memory */ - DRW_gpencil_free_runtime_data(ved); - /* reset */ - if (DRW_state_is_fbo()) { - /* attach again default framebuffer */ - if (!is_render) { - GPU_framebuffer_bind(dfbl->default_fb); - } + if (pd->do_fast_drawing) { + GPENCIL_fast_draw_end(vedata); + } - /* 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; - } + if (!pd->simplify_antialias) { + GPENCIL_antialiasing_draw(vedata); + } + + if (pd->scene_fb) { + GPU_framebuffer_bind(pd->scene_fb); + DRW_draw_pass(psl->composite_ps); + } + + pd->gp_object_pool = pd->gp_layer_pool = pd->gp_vfx_pool = NULL; + + /* Free temp stroke buffers. */ + if (pd->sbuffer_gpd) { + DRW_cache_gpencil_sbuffer_clear(pd->obact); } } +static void GPENCIL_engine_free(void) +{ + GPENCIL_shader_free(); +} + static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data); DrawEngineType draw_engine_gpencil_type = { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index aaafa689202..3ebefe83ce6 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -23,6 +23,8 @@ #ifndef __GPENCIL_ENGINE_H__ #define __GPENCIL_ENGINE_H__ +#include "DNA_gpencil_types.h" + #include "GPU_batch.h" extern DrawEngineType draw_engine_gpencil_type; @@ -35,207 +37,191 @@ struct RenderEngine; struct RenderLayer; struct bGPDstroke; struct View3D; - +struct GpencilBatchCache; struct GPUBatch; struct GPUVertBuf; struct GPUVertFormat; -#define GPENCIL_CACHE_BLOCK_SIZE 8 -#define GPENCIL_MAX_SHGROUPS 65536 -#define GPENCIL_GROUPS_BLOCK_SIZE 1024 +/* used to convert pixel scale. */ +#define GPENCIL_PIXEL_FACTOR 2000.0f /* used to expand VBOs. Size has a big impact in the speed */ #define GPENCIL_VBO_BLOCK_SIZE 128 -#define GPENCIL_COLOR_SOLID 0 -#define GPENCIL_COLOR_TEXTURE 1 -#define GPENCIL_COLOR_PATTERN 2 - #define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera)) -/* *********** OBJECTS CACHE *********** */ -typedef struct tGPencilObjectCache_shgrp { - /** type of blend (regular, add, mult, etc...) */ - int mode; - /** flag to enable the layer clamping */ - bool mask_layer; - /** factor to define the opacity of the layer */ - float blend_opacity; - DRWShadingGroup *init_shgrp; - DRWShadingGroup *end_shgrp; -} tGPencilObjectCache_shgrp; - -/* used to save gpencil object data for drawing */ -typedef struct tGPencilObjectCache { - struct Object *ob; - struct bGPdata *gpd; - int idx; /*original index, can change after sort */ - char *name; - - /* effects */ - bool has_fx; - ListBase shader_fx; - float pixfactor; - DRWShadingGroup *fx_wave_sh; - DRWShadingGroup *fx_blur_sh; - DRWShadingGroup *fx_colorize_sh; - DRWShadingGroup *fx_pixel_sh; - DRWShadingGroup *fx_rim_sh; - DRWShadingGroup *fx_shadow_sh; - DRWShadingGroup *fx_glow_sh; - DRWShadingGroup *fx_swirl_sh; - DRWShadingGroup *fx_flip_sh; - DRWShadingGroup *fx_light_sh; - - float loc[3]; - float obmat[4][4]; - float zdepth; /* z-depth value to sort gp object */ - bool is_dup_ob; /* flag to tag duplicate objects */ - float scale; - - /* shading type */ - int shading_type[2]; - - /* GPU data size */ - int tot_vertex; - int tot_triangles; - - /* Save shader groups by layer */ - int tot_layers; - tGPencilObjectCache_shgrp *shgrp_array; - -} tGPencilObjectCache; +/* UBO structure. Watch out for padding. Must match GLSL declaration. */ +typedef struct gpMaterial { + float stroke_color[4]; + float fill_color[4]; + float fill_mix_color[4]; + float fill_uv_transform[3][2], _pad0[2]; + float stroke_texture_mix; + float stroke_u_scale; + float fill_texture_mix; + int flag; +} gpMaterial; + +/* gpMaterial->flag */ +/* WATCH Keep in sync with GLSL declaration. */ +#define GP_STROKE_ALIGNMENT_STROKE 1 +#define GP_STROKE_ALIGNMENT_OBJECT 2 +#define GP_STROKE_ALIGNMENT_FIXED 3 +#define GP_STROKE_ALIGNMENT 0x3 +#define GP_STROKE_OVERLAP (1 << 2) +#define GP_STROKE_TEXTURE_USE (1 << 3) +#define GP_STROKE_TEXTURE_STENCIL (1 << 4) +#define GP_STROKE_TEXTURE_PREMUL (1 << 5) +#define GP_STROKE_DOTS (1 << 6) +#define GP_FILL_TEXTURE_USE (1 << 10) +#define GP_FILL_TEXTURE_PREMUL (1 << 11) +#define GP_FILL_TEXTURE_CLIP (1 << 12) +#define GP_FILL_GRADIENT_USE (1 << 13) +#define GP_FILL_GRADIENT_RADIAL (1 << 14) + +#define GPENCIL_LIGHT_BUFFER_LEN 128 + +/* UBO structure. Watch out for padding. Must match GLSL declaration. */ +typedef struct gpLight { + float color[3], type; + float right[3], spotsize; + float up[3], spotblend; + float forward[4]; + float position[4]; +} gpLight; + +/* gpLight->type */ +/* WATCH Keep in sync with GLSL declaration. */ +#define GP_LIGHT_TYPE_POINT 0.0 +#define GP_LIGHT_TYPE_SPOT 1.0 +#define GP_LIGHT_TYPE_SUN 2.0 +#define GP_LIGHT_TYPE_AMBIENT 3.0 + +BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16) +BLI_STATIC_ASSERT_ALIGN(gpLight, 16) + +/* *********** Draw Datas *********** */ +typedef struct GPENCIL_MaterialPool { + /* Linklist. */ + struct GPENCIL_MaterialPool *next; + /* GPU representatin of materials. */ + gpMaterial mat_data[GP_MATERIAL_BUFFER_LEN]; + /* Matching ubo. */ + struct GPUUniformBuffer *ubo; + /* Texture per material. NULL means none. */ + struct GPUTexture *tex_fill[GP_MATERIAL_BUFFER_LEN]; + struct GPUTexture *tex_stroke[GP_MATERIAL_BUFFER_LEN]; + /* Number of material used in this pool. */ + int used_count; +} GPENCIL_MaterialPool; + +typedef struct GPENCIL_LightPool { + /* GPU representatin of materials. */ + gpLight light_data[GPENCIL_LIGHT_BUFFER_LEN]; + /* Matching ubo. */ + struct GPUUniformBuffer *ubo; + /* Number of light in the pool. */ + int light_used; +} GPENCIL_LightPool; + +typedef struct GPENCIL_ViewLayerData { + /* GPENCIL_tObject */ + struct BLI_memblock *gp_object_pool; + /* GPENCIL_tLayer */ + struct BLI_memblock *gp_layer_pool; + /* GPENCIL_tVfx */ + struct BLI_memblock *gp_vfx_pool; + /* GPENCIL_MaterialPool */ + struct BLI_memblock *gp_material_pool; + /* GPENCIL_LightPool */ + struct BLI_memblock *gp_light_pool; +} GPENCIL_ViewLayerData; + +/* *********** GPencil *********** */ + +typedef struct GPENCIL_tVfx { + /** Linklist */ + struct GPENCIL_tVfx *next; + DRWPass *vfx_ps; + /* Framebuffer reference since it may not be allocated yet. */ + GPUFrameBuffer **target_fb; +} GPENCIL_tVfx; + +typedef struct GPENCIL_tLayer { + /** Linklist */ + struct GPENCIL_tLayer *next; + /** Geometry pass (draw all strokes). */ + DRWPass *geom_ps; + /** Blend pass to composite onto the target buffer (blends modes). NULL if not needed. */ + DRWPass *blend_ps; + /** Used to identify which layers are masks and which are masked. */ + bool is_mask; + bool is_masked; + bool do_masked_clear; +} GPENCIL_tLayer; + +typedef struct GPENCIL_tObject { + /** Linklist */ + struct GPENCIL_tObject *next; + + struct { + GPENCIL_tLayer *first, *last; + } layers; + + struct { + GPENCIL_tVfx *first, *last; + } vfx; + + /* Distance to camera. Used for sorting. */ + float camera_z; + /* Normal used for shading. Based on view angle. */ + float plane_normal[3]; + /* Used for drawing depth merge pass. */ + float plane_mat[4][4]; + + bool is_drawmode3d; +} GPENCIL_tObject; /* *********** 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; - int caps_mode[2]; - float obj_scale; - int xray_mode; - int alignment_mode; - - float gradient_f; - float gradient_s[2]; - - float mix_stroke_factor; - - /* color of the wireframe */ - float wire_color[4]; - /* shading type and mode */ - int shading_type[2]; - int is_xray; -} GPENCIL_shgroup; - -typedef struct GPENCIL_Storage { - int shgroup_id; /* total elements */ - int stroke_style; - int color_type; - int mode; - int xray; - int keep_size; - float obj_scale; - float pixfactor; - bool is_playing; - bool is_render; - bool is_mat_preview; - bool is_main_overlay; - bool is_main_onion; - bool background_ready; - int is_xray; - bool is_ontop; - bool reset_cache; - const float *pixsize; - float render_pixsize; - int tonemapping; - int do_select_outline; - float select_color[4]; - short multisamples; - float grid_matrix[4][4]; - - short framebuffer_flag; /* flag what framebuffer need to create */ - - int blend_mode; - int mask_layer; - - /* simplify settings*/ - bool simplify_fill; - bool simplify_modif; - bool simplify_fx; - bool simplify_blend; - - float gradient_f; - float gradient_s[2]; - int alignment_mode; - - float mix_stroke_factor; - - /* Render Matrices and data */ - float view_vecs[2][4]; /* vec4[2] */ - - int shade_render[2]; - - Object *camera; /* camera pointer for render mode */ -} GPENCIL_Storage; - -typedef enum eGpencilFramebuffer_Flag { - GP_FRAMEBUFFER_MULTISAMPLE = (1 << 0), - GP_FRAMEBUFFER_BASIC = (1 << 1), - GP_FRAMEBUFFER_DRAW = (1 << 2), -} eGpencilFramebuffer_Flag; - typedef struct GPENCIL_StorageList { - struct GPENCIL_Storage *storage; - struct g_data *g_data; - struct GPENCIL_shgroup *shgroups; + struct GPENCIL_PrivateData *pd; } GPENCIL_StorageList; typedef struct GPENCIL_PassList { - struct DRWPass *stroke_pass_2d; - struct DRWPass *stroke_pass_3d; - 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; - struct DRWPass *blend_pass; - - /* effects */ - struct DRWPass *fx_shader_pass; - struct DRWPass *fx_shader_pass_blend; - + /* Composite the main GPencil buffer onto the rendered image. */ + struct DRWPass *composite_ps; + /* Composite the object depth to the default depth buffer to occlude overlays. */ + struct DRWPass *merge_depth_ps; + /* Anti-Aliasing. */ + struct DRWPass *smaa_edge_ps; + struct DRWPass *smaa_weight_ps; + struct DRWPass *smaa_resolve_ps; } GPENCIL_PassList; typedef struct GPENCIL_FramebufferList { - struct GPUFrameBuffer *main; - struct GPUFrameBuffer *temp_fb_a; - struct GPUFrameBuffer *temp_fb_b; - struct GPUFrameBuffer *temp_fb_fx; - struct GPUFrameBuffer *background_fb; - - struct GPUFrameBuffer *multisample_fb; + struct GPUFrameBuffer *render_fb; + struct GPUFrameBuffer *gpencil_fb; + struct GPUFrameBuffer *snapshot_fb; + struct GPUFrameBuffer *layer_fb; + struct GPUFrameBuffer *object_fb; + struct GPUFrameBuffer *masked_fb; + struct GPUFrameBuffer *smaa_edge_fb; + struct GPUFrameBuffer *smaa_weight_fb; } GPENCIL_FramebufferList; typedef struct GPENCIL_TextureList { - struct GPUTexture *texture; - - /* multisample textures */ - struct GPUTexture *multisample_color; - struct GPUTexture *multisample_depth; - - /* Background textures for speed-up drawing. */ - struct GPUTexture *background_depth_tx; - struct GPUTexture *background_color_tx; - + /* Dummy texture to avoid errors cause by empty sampler. */ + struct GPUTexture *dummy_texture; + /* Snapshot for smoother drawing. */ + struct GPUTexture *snapshot_depth_tx; + struct GPUTexture *snapshot_color_tx; + struct GPUTexture *snapshot_reveal_tx; + /* Textures used by Antialiasing. */ + struct GPUTexture *smaa_area_tx; + struct GPUTexture *smaa_search_tx; + /* Textures used during render. Containing underlying rendered scene. */ + struct GPUTexture *render_depth_tx; + struct GPUTexture *render_color_tx; } GPENCIL_TextureList; typedef struct GPENCIL_Data { @@ -244,255 +230,156 @@ typedef struct GPENCIL_Data { 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; - - int gp_cache_used; /* total objects in cache */ - int gp_cache_size; /* size of the cache */ - struct tGPencilObjectCache *gp_object_cache; - - /* for buffer only one batch is nedeed because the drawing is only of one stroke */ - GPUBatch *batch_buffer_stroke; - GPUBatch *batch_buffer_fill; - GPUBatch *batch_buffer_ctrlpoint; - - /* grid geometry */ - GPUBatch *batch_grid; - - /* 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_fx; - struct GPUTexture *temp_depth_tx_fx; - - int session_flag; - bool do_instances; - -} 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 { - /* textures */ - struct GPUTexture *gpencil_blank_texture; - - /* 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_blend_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_glow_prepare_sh; - struct GPUShader *gpencil_fx_glow_resolve_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_shadow_prepare_sh; - struct GPUShader *gpencil_fx_shadow_resolve_sh; - struct GPUShader *gpencil_fx_swirl_sh; - struct GPUShader *gpencil_fx_wave_sh; - -} GPENCIL_e_data; /* Engine data */ - -/* GPUBatch Cache Element */ -typedef struct GpencilBatchCacheElem { - GPUBatch *batch; - GPUVertBuf *vbo; - int vbo_len; - /* attr ids */ - GPUVertFormat *format; - uint pos_id; - uint color_id; - uint thickness_id; - uint uvdata_id; - uint prev_pos_id; - - /* size for VBO alloc */ - int tot_vertex; -} GpencilBatchCacheElem; - -/* Defines each batch group to define later the shgroup */ -typedef struct GpencilBatchGroup { - struct bGPDlayer *gpl; /* reference to original layer */ - struct bGPDframe *gpf; /* reference to original frame */ - struct bGPDstroke *gps; /* reference to original stroke */ - short type; /* type of element */ - bool onion; /* the group is part of onion skin */ - int vertex_idx; /* index of vertex data */ -} GpencilBatchGroup; - -typedef enum GpencilBatchGroup_Type { - eGpencilBatchGroupType_Stroke = 1, - eGpencilBatchGroupType_Point = 2, - eGpencilBatchGroupType_Fill = 3, - eGpencilBatchGroupType_Edit = 4, - eGpencilBatchGroupType_Edlin = 5, -} GpencilBatchGroup_Type; - -/* Runtime data for GPU and evaluated frames after applying modifiers */ -typedef struct GpencilBatchCache { - GpencilBatchCacheElem b_stroke; - GpencilBatchCacheElem b_point; - GpencilBatchCacheElem b_fill; - GpencilBatchCacheElem b_edit; - GpencilBatchCacheElem b_edlin; - - /** Cache is dirty */ - bool is_dirty; - /** Edit mode flag */ - bool is_editmode; - /** Last cache frame */ - int cache_frame; - - /** Total groups in arrays */ - int grp_used; - /** Max size of the array */ - int grp_size; - /** Array of cache elements */ - struct GpencilBatchGroup *grp_cache; -} GpencilBatchCache; - -/* general drawing functions */ -struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data, - struct GPENCIL_Data *vedata, - struct DRWPass *pass, - struct GPUShader *shader, - struct Object *ob, - float (*obmat)[4], - struct bGPdata *gpd, - struct bGPDlayer *gpl, - struct bGPDstroke *gps, - struct MaterialGPencilStyle *gp_style, - int id, - bool onion, - const float scale, - const int shading_type[2]); -void gpencil_populate_datablock(struct GPENCIL_e_data *e_data, - void *vedata, - struct Object *ob, - struct tGPencilObjectCache *cache_ob); -void gpencil_populate_buffer_strokes(struct GPENCIL_e_data *e_data, - void *vedata, - struct ToolSettings *ts, - struct Object *ob); -void gpencil_populate_multiedit(struct GPENCIL_e_data *e_data, - void *vedata, - struct Object *ob, - struct tGPencilObjectCache *cache_ob); -void gpencil_populate_particles(struct GPENCIL_e_data *e_data, - struct GHash *gh_objects, - void *vedata); - -void gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h); - -/* create geometry functions */ -void gpencil_get_point_geom(struct GpencilBatchCacheElem *be, - struct bGPDlayer *gpl, - struct bGPDstroke *gps, - short thickness, - const float ink[4], - const float tintcolor[4], - const int follow_mode, - const bool onion); -void gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, - struct bGPDlayer *gpl, - struct bGPDstroke *gps, - short thickness, - const float ink[4], - const float tintcolor[4], - const bool onion); -void gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, - struct Object *ob, - struct bGPDstroke *gps, - const float color[4]); -void gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, - struct bGPDstroke *gps, - float alpha, - short dflag); -void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, - struct bGPDstroke *gps, - float alpha, - const bool hide_select); - -struct GPUBatch *gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, short thickness); -struct GPUBatch *gpencil_get_buffer_fill_geom(struct bGPdata *gpd); -struct GPUBatch *gpencil_get_buffer_point_geom(struct bGPdata *gpd, short thickness); -struct GPUBatch *gpencil_get_buffer_ctrlpoint_geom(struct bGPdata *gpd); -struct GPUBatch *gpencil_get_grid(Object *ob); - -/* object cache functions */ -struct tGPencilObjectCache *gpencil_object_cache_add(struct tGPencilObjectCache *cache_array, - struct Object *ob, - int *gp_cache_size, - int *gp_cache_used); - -bool gpencil_onion_active(struct bGPdata *gpd); -float gpencil_get_vertex_paint_factor(struct View3D *v3d); - -/* shading groups cache functions */ -struct GpencilBatchGroup *gpencil_group_cache_add(struct GpencilBatchGroup *cache_array, - struct bGPDlayer *gpl, - struct bGPDframe *gpf, - struct bGPDstroke *gps, - const short type, - const bool onion, - const int vertex_idx, - int *grp_size, - int *grp_used); +typedef struct GPENCIL_PrivateData { + /* Pointers copied from GPENCIL_ViewLayerData. */ + struct BLI_memblock *gp_object_pool; + struct BLI_memblock *gp_layer_pool; + struct BLI_memblock *gp_vfx_pool; + struct BLI_memblock *gp_material_pool; + struct BLI_memblock *gp_light_pool; + /* Last used material pool. */ + GPENCIL_MaterialPool *last_material_pool; + /* Last used light pool. */ + GPENCIL_LightPool *last_light_pool; + /* Common lightpool containing all lights in the scene. */ + GPENCIL_LightPool *global_light_pool; + /* Common lightpool containing one ambient white light. */ + GPENCIL_LightPool *shadeless_light_pool; + /* Linked list of tObjects. */ + struct { + GPENCIL_tObject *first, *last; + } tobjects, tobjects_infront; + /* Temp Textures (shared with other engines). */ + GPUTexture *depth_tx; + GPUTexture *color_tx; + GPUTexture *color_layer_tx; + GPUTexture *color_object_tx; + GPUTexture *color_masked_tx; + /* Revealage is 1 - alpha */ + GPUTexture *reveal_tx; + GPUTexture *reveal_layer_tx; + GPUTexture *reveal_object_tx; + GPUTexture *reveal_masked_tx; + /* Anti-Aliasing. */ + GPUTexture *smaa_edge_tx; + GPUTexture *smaa_weight_tx; + /* Pointer to dtxl->depth */ + GPUTexture *scene_depth_tx; + GPUFrameBuffer *scene_fb; + /* Copy of txl->dummy_tx */ + GPUTexture *dummy_tx; + /* Copy of v3d->shading.single_color. */ + float v3d_single_color[3]; + /* Copy of v3d->shading.color_type or -1 to ignore. */ + int v3d_color_type; + /* Current frame */ + int cfra; + /* If we are rendering for final render (F12). */ + bool is_render; + /* True in selection and auto_depth drawing */ + bool draw_depth_only; + /* Used by the depth merge step. */ + int is_stroke_order_3d; + float object_bound_mat[4][4]; + /* Used for computing object distance to camera. */ + float camera_z_axis[3], camera_z_offset; + float camera_pos[3]; + /* Pseudo depth of field parameter. Used to scale blur radius. */ + float dof_params[2]; + /* Used for DoF Setup. */ + Object *camera; + + /* Active object. */ + Object *obact; + /* Object being in draw mode. */ + struct bGPdata *sbuffer_gpd; + /* Layer to append the temp stroke to. */ + struct bGPDlayer *sbuffer_layer; + /* Temporary stroke currently being drawn. */ + struct bGPDstroke *sbuffer_stroke; + /* List of temp objects containing the stroke. */ + struct { + GPENCIL_tObject *first, *last; + } sbuffer_tobjects; + /* Batches containing the temp stroke. */ + GPUBatch *stroke_batch; + GPUBatch *fill_batch; + bool do_fast_drawing; + bool snapshot_buffer_dirty; + + /* Display onion skinning */ + bool do_onion; + /* simplify settings */ + bool simplify_fill; + bool simplify_fx; + bool simplify_antialias; + /* Use scene lighting or flat shading (global setting). */ + bool use_lighting; + /* Use physical lights or just ambient lighting. */ + bool use_lights; + /* Do we need additional framebuffers? */ + bool use_layer_fb; + bool use_object_fb; + bool use_mask_fb; + /* Some blend mode needs to add negative values. + * This is only supported if target texture is signed. */ + bool use_signed_fb; + /* Use only lines for multiedit and not active frame. */ + bool use_multiedit_lines_only; + /* Layer opacity for fading. */ + float fade_layer_opacity; + /* Opacity for fading gpencil objects. */ + float fade_gp_object_opacity; + /* Opacity for fading 3D objects. */ + float fade_3d_object_opacity; +} GPENCIL_PrivateData; /* geometry batch cache functions */ struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra); -/* 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); +GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob); +GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd, + Object *ob, + struct bGPDlayer *layer); +GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs); +void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool, + int mat_id, + struct GPUTexture **r_tex_stroke, + struct GPUTexture **r_tex_fill, + struct GPUUniformBuffer **r_ubo_mat); +/* Meh, TODO fix naming...*/ +void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]); +void gpencil_light_pool_populate(GPENCIL_LightPool *matpool, Object *ob); +GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd); +GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *ob); -void gpencil_fx_prepare(struct GPENCIL_e_data *e_data, - struct GPENCIL_Data *vedata, - struct tGPencilObjectCache *cache_ob); -void gpencil_fx_draw(struct GPENCIL_e_data *e_data, - struct GPENCIL_Data *vedata, - struct tGPencilObjectCache *cache_ob); +/* effects */ +void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob); + +/* Shaders */ +struct GPUShader *GPENCIL_shader_antialiasing(int stage); +struct GPUShader *GPENCIL_shader_geometry_get(void); +struct GPUShader *GPENCIL_shader_composite_get(void); +struct GPUShader *GPENCIL_shader_layer_blend_get(void); +struct GPUShader *GPENCIL_shader_layer_mask_get(void); +struct GPUShader *GPENCIL_shader_depth_merge_get(void); +struct GPUShader *GPENCIL_shader_fx_blur_get(void); +struct GPUShader *GPENCIL_shader_fx_colorize_get(void); +struct GPUShader *GPENCIL_shader_fx_composite_get(void); +struct GPUShader *GPENCIL_shader_fx_transform_get(void); +struct GPUShader *GPENCIL_shader_fx_glow_get(void); +struct GPUShader *GPENCIL_shader_fx_pixelize_get(void); +struct GPUShader *GPENCIL_shader_fx_rim_get(void); +struct GPUShader *GPENCIL_shader_fx_shadow_get(void); + +void GPENCIL_shader_free(void); + +/* Antialiasing */ +void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata); +void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata); /* main functions */ void GPENCIL_engine_init(void *vedata); @@ -504,44 +391,19 @@ void GPENCIL_draw_scene(void *vedata); /* render */ void GPENCIL_render_init(struct GPENCIL_Data *ved, struct RenderEngine *engine, - struct Depsgraph *depsgraph); + struct RenderLayer *render_layer, + const struct Depsgraph *depsgraph); void GPENCIL_render_to_image(void *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect); -/* TODO: GPXX workaround function to call free memory from draw manager while draw manager support - * scene finish callback. */ -void DRW_gpencil_free_runtime_data(void *ved); - -/* Use of multisample framebuffers. */ -#define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) \ - { \ - if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \ - DRW_stats_query_start("GP Multisample Blit"); \ - GPU_framebuffer_bind(fbl->multisample_fb); \ - GPU_framebuffer_clear_color_depth_stencil( \ - fbl->multisample_fb, (const float[4]){0.0f}, 1.0f, 0x0); \ - DRW_stats_query_end(); \ - } \ - } \ - ((void)0) - -#define MULTISAMPLE_GP_SYNC_DISABLE(lvl, fbl, fb, txl) \ - { \ - if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \ - 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(); \ - } \ - } \ - ((void)0) +/* Draw Data. */ +void gpencil_light_pool_free(void *storage); +void gpencil_material_pool_free(void *storage); +GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void); #define GPENCIL_3D_DRAWMODE(ob, gpd) \ ((gpd) && (gpd->draw_mode == GP_DRAWMODE_3D) && ((ob->dtx & OB_DRAWXRAY) == 0)) -#define GPENCIL_USE_SOLID(stl) \ - ((stl) && ((stl->storage->is_render) || (stl->storage->is_mat_preview))) - #endif /* __GPENCIL_ENGINE_H__ */ diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index 8c126310ea2..ebb87880ce7 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -33,66 +33,21 @@ #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) +void GPENCIL_render_init(GPENCIL_Data *vedata, + RenderEngine *engine, + struct RenderLayer *render_layer, + const Depsgraph *depsgraph) { - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; - GPENCIL_StorageList *stl = vedata->stl; GPENCIL_FramebufferList *fbl = vedata->fbl; + GPENCIL_TextureList *txl = vedata->txl; 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 multisample framebuffer for AA */ - if (U.gpencil_multisamples > 0) { - int rect_w = (int)viewport_size[0]; - int rect_h = (int)viewport_size[1]; - gpencil_multisample_ensure(vedata, rect_w, rect_h); - } - - vedata->render_depth_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_DEPTH_COMPONENT24, &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. */ - float winmat[4][4], viewmat[4][4], viewinv[4][4], persmat[4][4]; + float winmat[4][4], viewmat[4][4], viewinv[4][4]; struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); float frame = BKE_scene_frame_get(scene); @@ -105,85 +60,70 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra DRW_view_default_set(view); DRW_view_set_active(view); - DRW_view_persmat_get(NULL, persmat, false); + /* Create depth texture & color texture from render result. */ + const char *viewname = RE_GetActiveRenderView(engine->re); + RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname); + RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); - /* calculate pixel size for render */ - stl->storage->render_pixsize = get_render_pixelsize(persmat, viewport_size[0], viewport_size[1]); + float *pix_z = (rpass_z_src) ? rpass_z_src->rect : NULL; + float *pix_col = (rpass_col_src) ? rpass_col_src->rect : NULL; - /* INIT CACHE */ - GPENCIL_cache_init(vedata); + if (!pix_z || !pix_col) { + /* TODO: put this message in a better place */ + printf("Warning: To render grease pencil, enable Combined and Z passes.\n"); + } + + if (pix_z) { + /* Depth need to be remapped to [0..1] range. */ + pix_z = MEM_dupallocN(pix_z); + + int pix_ct = rpass_z_src->rectx * rpass_z_src->recty; + + if (DRW_view_is_persp_get(view)) { + for (int i = 0; i < pix_ct; i++) { + pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2]; + pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f); + } + } + else { + /* Keep in mind, near and far distance are negatives. */ + float near = DRW_view_near_distance_get(view); + float far = DRW_view_far_distance_get(view); + float range_inv = 1.0f / fabsf(far - near); + for (int i = 0; i < pix_ct; i++) { + pix_z[i] = (pix_z[i] + near) * range_inv; + pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f); + } + } + } + + /* FIXME(fclem): we have a precision loss in the depth buffer because of this reupload. + * Find where it comes from! */ + txl->render_depth_tx = DRW_texture_create_2d(size[0], size[1], GPU_DEPTH_COMPONENT24, 0, pix_z); + txl->render_color_tx = DRW_texture_create_2d(size[0], size[1], GPU_RGBA16F, 0, pix_col); + + GPU_framebuffer_ensure_config(&fbl->render_fb, + { + GPU_ATTACHMENT_TEXTURE(txl->render_depth_tx), + GPU_ATTACHMENT_TEXTURE(txl->render_color_tx), + }); + + MEM_SAFE_FREE(pix_z); } /* 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)) + Depsgraph *UNUSED(depsgraph)) { - if (ob && ob->type == OB_GPENCIL) { + if (ob && ELEM(ob->type, OB_GPENCIL, OB_LAMP)) { if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) { 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], - const 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_view_winmat_get(NULL, winmat, false); - DRW_view_winmat_get(NULL, invproj, true); - - /* 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, @@ -191,45 +131,52 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl, { 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, + GPU_framebuffer_read_depth(vedata->fbl->render_fb, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), rp->rect); - bool is_persp = DRW_view_is_persp_get(NULL); - - GPENCIL_render_update_vecs(vedata); - float winmat[4][4]; DRW_view_winmat_get(NULL, winmat, false); + int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); + /* 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) { + if (DRW_view_is_persp_get(NULL)) { + for (int i = 0; i < pix_ct; i++) { + if (rp->rect[i] == 1.0f) { + rp->rect[i] = 1e10f; /* Background */ + } + else { rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]); } + } + } + else { + /* Keep in mind, near and far distance are negatives. */ + float near = DRW_view_near_distance_get(NULL); + float far = DRW_view_far_distance_get(NULL); + float range = fabsf(far - near); + + for (int i = 0; i < pix_ct; i++) { + if (rp->rect[i] == 1.0f) { + rp->rect[i] = 1e10f; /* Background */ + } else { - rp->rect[i] = -stl->storage->view_vecs[0][2] + - rp->rect[i] * -stl->storage->view_vecs[1][2]; + rp->rect[i] = -rp->rect[i] * range + near; } } } } } -/* read combined render result */ static void GPENCIL_render_result_combined(struct RenderLayer *rl, const char *viewname, GPENCIL_Data *vedata, @@ -238,8 +185,8 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl, 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, + GPU_framebuffer_bind(fbl->render_fb); + GPU_framebuffer_read_color(vedata->fbl->render_fb, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), @@ -249,135 +196,31 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl, rp->rect); } -/* helper to blend pixels */ -static void blend_pixel(float top_color[4], float bottom_color[4], float dst_color[4]) -{ - float alpha = top_color[3]; - - /* use blend: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA */ - dst_color[0] = (top_color[0] * alpha) + (bottom_color[0] * (1.0f - alpha)); - dst_color[1] = (top_color[1] * alpha) + (bottom_color[1] * (1.0f - alpha)); - dst_color[2] = (top_color[2] * alpha) + (bottom_color[2] * (1.0f - alpha)); -} - -/* render grease pencil to image */ -void GPENCIL_render_to_image(void *vedata, +void GPENCIL_render_to_image(void *ved, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) { + GPENCIL_Data *vedata = (GPENCIL_Data *)ved; 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"); - } + Depsgraph *depsgraph = draw_ctx->depsgraph; + GPENCIL_render_init(vedata, engine, render_layer, depsgraph); 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); + vedata->stl->pd->camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + /* Loop over all objects and create draw structure. */ + GPENCIL_cache_init(vedata); + DRW_render_object_iter(vedata, engine, depsgraph, GPENCIL_render_cache); GPENCIL_cache_finish(vedata); DRW_render_instance_buffer_finish(); + /* Render the gpencil object and merge the result to the underlying render. */ 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; - - 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) { - if (src_pixel_rgba[3] > 0.0f) { - /* 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 object on top */ - if (src_pixel_rgba[3] < 1.0f) { - blend_pixel(src_pixel_rgba, gp_pixel_rgba, gp_pixel_rgba); - } - else { - copy_v4_v4(gp_pixel_rgba, src_pixel_rgba); - } - } - else { - /* blend gp render */ - if (gp_pixel_rgba[3] < 1.0f) { - /* premult alpha factor to remove double blend effects */ - mul_v3_fl(gp_pixel_rgba, 1.0f / gp_pixel_rgba[3]); - - blend_pixel(gp_pixel_rgba, src_pixel_rgba, gp_pixel_rgba); - - gp_pixel_rgba[3] = gp_pixel_rgba[3] > src_pixel_rgba[3] ? gp_pixel_rgba[3] : - src_pixel_rgba[3]; - } - } - } - } - 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.c b/source/blender/draw/engines/gpencil/gpencil_shader.c new file mode 100644 index 00000000000..3e436d27922 --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_shader.c @@ -0,0 +1,305 @@ +/* + * 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. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup draw + */ +#include "DRW_render.h" + +#include "gpencil_engine.h" + +extern char datatoc_gpencil_common_lib_glsl[]; +extern char datatoc_gpencil_frag_glsl[]; +extern char datatoc_gpencil_vert_glsl[]; +extern char datatoc_gpencil_antialiasing_frag_glsl[]; +extern char datatoc_gpencil_antialiasing_vert_glsl[]; +extern char datatoc_gpencil_composite_frag_glsl[]; +extern char datatoc_gpencil_layer_blend_frag_glsl[]; +extern char datatoc_gpencil_layer_mask_frag_glsl[]; +extern char datatoc_gpencil_depth_merge_frag_glsl[]; +extern char datatoc_gpencil_depth_merge_vert_glsl[]; +extern char datatoc_gpencil_vfx_frag_glsl[]; + +extern char datatoc_common_colormanagement_lib_glsl[]; +extern char datatoc_common_fullscreen_vert_glsl[]; +extern char datatoc_common_smaa_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; + +static struct { + /* SMAA antialiasing */ + GPUShader *antialiasing_sh[3]; + /* GPencil Object rendering */ + GPUShader *gpencil_sh; + /* Final Compositing over rendered background. */ + GPUShader *composite_sh; + /* All layer blend types in one shader! */ + GPUShader *layer_blend_sh; + /* To blend masked layer with other layers. */ + GPUShader *layer_mask_sh; + /* Merge the final object depth to the depth buffer. */ + GPUShader *depth_merge_sh; + /* Effects. */ + GPUShader *fx_composite_sh; + GPUShader *fx_colorize_sh; + GPUShader *fx_blur_sh; + GPUShader *fx_glow_sh; + GPUShader *fx_pixel_sh; + GPUShader *fx_rim_sh; + GPUShader *fx_shadow_sh; + GPUShader *fx_transform_sh; + /* general drawing shaders */ + GPUShader *gpencil_fill_sh; + GPUShader *gpencil_stroke_sh; + GPUShader *gpencil_point_sh; + GPUShader *gpencil_edit_point_sh; + GPUShader *gpencil_line_sh; + GPUShader *gpencil_drawing_fill_sh; + GPUShader *gpencil_fullscreen_sh; + GPUShader *gpencil_simple_fullscreen_sh; + GPUShader *gpencil_blend_fullscreen_sh; + GPUShader *gpencil_background_sh; + GPUShader *gpencil_paper_sh; +} g_shaders = {{NULL}}; + +void GPENCIL_shader_free(void) +{ + GPUShader **sh_data_as_array = (GPUShader **)&g_shaders; + for (int i = 0; i < (sizeof(g_shaders) / sizeof(GPUShader *)); i++) { + DRW_SHADER_FREE_SAFE(sh_data_as_array[i]); + } +} + +GPUShader *GPENCIL_shader_antialiasing(int stage) +{ + BLI_assert(stage < 3); + + if (!g_shaders.antialiasing_sh[stage]) { + char stage_define[32]; + BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage); + + g_shaders.antialiasing_sh[stage] = GPU_shader_create_from_arrays({ + .vert = + (const char *[]){ + "#define SMAA_INCLUDE_VS 1\n", + "#define SMAA_INCLUDE_PS 0\n", + "uniform vec4 viewportMetrics;\n", + datatoc_common_smaa_lib_glsl, + datatoc_gpencil_antialiasing_vert_glsl, + NULL, + }, + .frag = + (const char *[]){ + "#define SMAA_INCLUDE_VS 0\n", + "#define SMAA_INCLUDE_PS 1\n", + "uniform vec4 viewportMetrics;\n", + datatoc_common_smaa_lib_glsl, + datatoc_gpencil_antialiasing_frag_glsl, + NULL, + }, + .defs = + (const char *[]){ + "#define SMAA_GLSL_3\n", + "#define SMAA_RT_METRICS viewportMetrics\n", + "#define SMAA_PRESET_HIGH\n", + "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 0.0)\n", + "#define SMAA_NO_DISCARD\n", + stage_define, + NULL, + }, + }); + } + return g_shaders.antialiasing_sh[stage]; +} + +GPUShader *GPENCIL_shader_geometry_get(void) +{ + if (!g_shaders.gpencil_sh) { + g_shaders.gpencil_sh = GPU_shader_create_from_arrays({ + .vert = + (const char *[]){ + datatoc_common_view_lib_glsl, + datatoc_gpencil_common_lib_glsl, + datatoc_gpencil_vert_glsl, + NULL, + }, + .frag = + (const char *[]){ + datatoc_common_colormanagement_lib_glsl, + datatoc_gpencil_common_lib_glsl, + datatoc_gpencil_frag_glsl, + NULL, + }, + .defs = + (const char *[]){ + "#define GP_MATERIAL_BUFFER_LEN " STRINGIFY(GP_MATERIAL_BUFFER_LEN) "\n", + "#define GPENCIL_LIGHT_BUFFER_LEN " STRINGIFY(GPENCIL_LIGHT_BUFFER_LEN) "\n", + "#define UNIFORM_RESOURCE_ID\n", + NULL, + }, + }); + } + return g_shaders.gpencil_sh; +} + +GPUShader *GPENCIL_shader_composite_get(void) +{ + if (!g_shaders.composite_sh) { + g_shaders.composite_sh = DRW_shader_create_fullscreen(datatoc_gpencil_composite_frag_glsl, + NULL); + } + return g_shaders.composite_sh; +} + +GPUShader *GPENCIL_shader_layer_blend_get(void) +{ + if (!g_shaders.layer_blend_sh) { + g_shaders.layer_blend_sh = GPU_shader_create_from_arrays({ + .vert = + (const char *[]){ + datatoc_common_fullscreen_vert_glsl, + NULL, + }, + .frag = + (const char *[]){ + datatoc_gpencil_common_lib_glsl, + datatoc_gpencil_layer_blend_frag_glsl, + NULL, + }, + }); + } + return g_shaders.layer_blend_sh; +} + +GPUShader *GPENCIL_shader_layer_mask_get(void) +{ + if (!g_shaders.layer_mask_sh) { + g_shaders.layer_mask_sh = DRW_shader_create_fullscreen(datatoc_gpencil_layer_mask_frag_glsl, + NULL); + } + return g_shaders.layer_mask_sh; +} + +GPUShader *GPENCIL_shader_depth_merge_get(void) +{ + if (!g_shaders.depth_merge_sh) { + g_shaders.depth_merge_sh = GPU_shader_create_from_arrays({ + .vert = + (const char *[]){ + datatoc_common_view_lib_glsl, + datatoc_gpencil_depth_merge_vert_glsl, + NULL, + }, + .frag = + (const char *[]){ + datatoc_gpencil_depth_merge_frag_glsl, + NULL, + }, + }); + } + return g_shaders.depth_merge_sh; +} + +/* ------- FX Shaders --------- */ + +GPUShader *GPENCIL_shader_fx_blur_get(void) +{ + if (!g_shaders.fx_blur_sh) { + g_shaders.fx_blur_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl, + "#define BLUR\n"); + } + return g_shaders.fx_blur_sh; +} + +GPUShader *GPENCIL_shader_fx_colorize_get(void) +{ + if (!g_shaders.fx_colorize_sh) { + g_shaders.fx_colorize_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl, + "#define COLORIZE\n"); + } + return g_shaders.fx_colorize_sh; +} + +GPUShader *GPENCIL_shader_fx_composite_get(void) +{ + if (!g_shaders.fx_composite_sh) { + g_shaders.fx_composite_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl, + "#define COMPOSITE\n"); + } + return g_shaders.fx_composite_sh; +} + +GPUShader *GPENCIL_shader_fx_glow_get(void) +{ + if (!g_shaders.fx_glow_sh) { + g_shaders.fx_glow_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl, + "#define GLOW\n"); + } + return g_shaders.fx_glow_sh; +} + +GPUShader *GPENCIL_shader_fx_pixelize_get(void) +{ + if (!g_shaders.fx_pixel_sh) { + g_shaders.fx_pixel_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl, + "#define PIXELIZE\n"); + } + return g_shaders.fx_pixel_sh; +} + +GPUShader *GPENCIL_shader_fx_rim_get(void) +{ + if (!g_shaders.fx_rim_sh) { + g_shaders.fx_rim_sh = GPU_shader_create_from_arrays({ + .vert = + (const char *[]){ + datatoc_common_fullscreen_vert_glsl, + NULL, + }, + .frag = + (const char *[]){ + datatoc_gpencil_common_lib_glsl, + datatoc_gpencil_vfx_frag_glsl, + NULL, + }, + .defs = + (const char *[]){ + "#define RIM\n", + NULL, + }, + }); + } + return g_shaders.fx_rim_sh; +} + +GPUShader *GPENCIL_shader_fx_shadow_get(void) +{ + if (!g_shaders.fx_shadow_sh) { + g_shaders.fx_shadow_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl, + "#define SHADOW\n"); + } + return g_shaders.fx_shadow_sh; +} + +GPUShader *GPENCIL_shader_fx_transform_get(void) +{ + if (!g_shaders.fx_transform_sh) { + g_shaders.fx_transform_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl, + "#define TRANSFORM\n"); + } + return g_shaders.fx_transform_sh; +} diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index f6a62e0d472..6e1eb4bfc47 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -26,26 +26,15 @@ #include "BKE_gpencil.h" +#include "BLI_link_utils.h" +#include "BLI_memblock.h" + #include "DRW_render.h" #include "BKE_camera.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_shadow_prepare_frag_glsl[]; -extern char datatoc_gpencil_fx_shadow_resolve_frag_glsl[]; -extern char datatoc_gpencil_fx_glow_prepare_frag_glsl[]; -extern char datatoc_gpencil_fx_glow_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(bGPdata *gpd, ShaderFxData *fx, bool is_render) { @@ -70,995 +59,563 @@ static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_render) 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]) +typedef struct gpIterVfxData { + GPENCIL_PrivateData *pd; + GPENCIL_tObject *tgp_ob; + GPUFrameBuffer **target_fb; + GPUFrameBuffer **source_fb; + GPUTexture **target_color_tx; + GPUTexture **source_color_tx; + GPUTexture **target_reveal_tx; + GPUTexture **source_reveal_tx; +} gpIterVfxData; + +static DRWShadingGroup *gpencil_vfx_pass_create(const char *name, + DRWState state, + gpIterVfxData *iter, + GPUShader *sh) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->flag & GP_LAYER_HIDE) { - continue; - } + DRWPass *pass = DRW_pass_create(name, state); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_texture_ref(grp, "colorBuf", iter->source_color_tx); + DRW_shgroup_uniform_texture_ref(grp, "revealBuf", iter->source_reveal_tx); - /* 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; - } - Camera *cam = camera->data; + GPENCIL_tVfx *tgp_vfx = BLI_memblock_alloc(iter->pd->gp_vfx_pool); + tgp_vfx->target_fb = iter->target_fb; + tgp_vfx->vfx_ps = pass; - float fstop = cam->dof.aperture_fstop; - float focus_dist = BKE_camera_object_dof_distance(camera); - float focal_len = cam->lens; + SWAP(GPUFrameBuffer **, iter->target_fb, iter->source_fb); + SWAP(GPUTexture **, iter->target_color_tx, iter->source_color_tx); + SWAP(GPUTexture **, iter->target_reveal_tx, iter->source_reveal_tx); - const float scale_camera = 0.001f; - /* 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; + BLI_LINKS_APPEND(&iter->tgp_ob->vfx, tgp_vfx); - 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); + return grp; } -/* **************** 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 gpencil_fx_blur(ShaderFxData *fx, - int ob_idx, - GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache) +static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *iter) { - 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; - bGPdata *gpd = cache->gpd; - copy_v3_v3(fxd->runtime.loc, cache->loc); - - 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; - } - } - - GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + DRWShadingGroup *grp; - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); - DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); - DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2); + float winmat[4][4], persmat[4][4]; + float blur_size[2] = {fx->radius[0], fx->radius[1]}; + DRW_view_persmat_get(NULL, persmat, false); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); - - fxd->runtime.fx_sh = fx_shgrp; -} - -/* Colorize FX */ -static void gpencil_fx_colorize(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata) -{ - if (fx == NULL) { - return; + if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) { + /* Compute circle of confusion size. */ + float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1]; + copy_v2_fl(blur_size, fabsf(coc)); } - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - DRWShadingGroup *fx_shgrp; - - 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_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; + else { + /* Modify by distance to camera and object scale. */ + DRW_view_winmat_get(NULL, winmat, false); + const float *vp_size = DRW_viewport_size_get(); + float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; + float scale = mat4_to_scale(ob->obmat); + float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w; + mul_v2_fl(blur_size, distance_factor); + } + + GPUShader *sh = GPENCIL_shader_fx_blur_get(); + + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Blur H", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){blur_size[0], 0.0f}); + DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0]))); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + grp = gpencil_vfx_pass_create("Fx Blur V", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){0.0f, blur_size[1]}); + DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1]))); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -/* Flip FX */ -static void gpencil_fx_flip(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata) +static void gpencil_vfx_colorize(ColorizeShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter) { - if (fx == NULL) { - return; - } - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - 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; - } - - 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); - DRW_shgroup_uniform_int(fx_shgrp, "flipmode", &fxd->flipmode, 1); + DRWShadingGroup *grp; - DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1); + GPUShader *sh = GPENCIL_shader_fx_colorize_get(); - fxd->runtime.fx_sh = fx_shgrp; + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Colorize", state, iter, sh); + DRW_shgroup_uniform_vec3_copy(grp, "lowColor", fx->low_color); + DRW_shgroup_uniform_vec3_copy(grp, "highColor", fx->high_color); + DRW_shgroup_uniform_float_copy(grp, "factor", fx->factor); + DRW_shgroup_uniform_int_copy(grp, "mode", fx->mode); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -/* Light FX */ -static void gpencil_fx_light(ShaderFxData *fx, - GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache) +static void gpencil_vfx_flip(FlipShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter) { - if (fx == NULL) { - return; - } - 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; - - 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_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->obmat[3]); - - /* 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 = cache->gpd; - if (!get_normal_vector(gpd, r_point, r_normal)) { - return; - } - mul_mat3_m4_v3(cache->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->obmat[3], r_plane); - fxd->loc[3] = dt; /* use last element to save it */ + DRWShadingGroup *grp; - DRW_shgroup_uniform_vec4(fx_shgrp, "loc", &fxd->loc[0], 1); + float axis_flip[2]; + axis_flip[0] = (fx->flag & FX_FLIP_HORIZONTAL) ? -1.0f : 1.0f; + axis_flip[1] = (fx->flag & FX_FLIP_VERTICAL) ? -1.0f : 1.0f; - DRW_shgroup_uniform_float(fx_shgrp, "energy", &fxd->energy, 1); - DRW_shgroup_uniform_float(fx_shgrp, "ambient", &fxd->ambient, 1); + GPUShader *sh = GPENCIL_shader_fx_transform_get(); - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); - - fxd->runtime.fx_sh = fx_shgrp; + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", axis_flip); + DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", (float[2]){0.0f, 0.0f}); + DRW_shgroup_uniform_float_copy(grp, "swirlRadius", 0.0f); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -/* Pixelate FX */ -static void gpencil_fx_pixel(ShaderFxData *fx, - GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache) +static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter) { - if (fx == NULL) { - return; + DRWShadingGroup *grp; + + float winmat[4][4], persmat[4][4]; + float offset[2] = {fx->offset[0], fx->offset[1]}; + float blur_size[2] = {fx->blur[0], fx->blur[1]}; + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_persmat_get(NULL, persmat, false); + const float *vp_size = DRW_viewport_size_get(); + const float *vp_size_inv = DRW_viewport_invert_size_get(); + + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + + /* Modify by distance to camera and object scale. */ + float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; + float scale = mat4_to_scale(ob->obmat); + float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; + mul_v2_fl(offset, distance_factor); + mul_v2_v2(offset, vp_size_inv); + mul_v2_fl(blur_size, distance_factor); + + GPUShader *sh = GPENCIL_shader_fx_rim_get(); + + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Rim H", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "blurDir", (float[2]){blur_size[0] * vp_size_inv[0], 0.0f}); + DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", offset); + DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0]))); + DRW_shgroup_uniform_vec3_copy(grp, "maskColor", fx->mask_rgb); + DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", true); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + switch (fx->mode) { + case eShaderFxRimMode_Normal: + state |= DRW_STATE_BLEND_ALPHA_PREMUL; + break; + case eShaderFxRimMode_Add: + state |= DRW_STATE_BLEND_ADD_FULL; + break; + case eShaderFxRimMode_Subtract: + state |= DRW_STATE_BLEND_SUB; + break; + case eShaderFxRimMode_Multiply: + case eShaderFxRimMode_Divide: + case eShaderFxRimMode_Overlay: + state |= DRW_STATE_BLEND_MUL; + break; + } + + zero_v2(offset); + + grp = gpencil_vfx_pass_create("Fx Rim V", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "blurDir", (float[2]){0.0f, blur_size[1] * vp_size_inv[1]}); + DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", offset); + DRW_shgroup_uniform_vec3_copy(grp, "rimColor", fx->rim_rgb); + DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1]))); + DRW_shgroup_uniform_int_copy(grp, "blendMode", fx->mode); + DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", false); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + if (fx->mode == eShaderFxRimMode_Overlay) { + /* We cannot do custom blending on MultiTarget framebuffers. + * Workaround by doing 2 passes. */ + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL); + DRW_shgroup_uniform_int_copy(grp, "blendMode", 999); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } - PixelShaderFxData *fxd = (PixelShaderFxData *)fx; - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - DRWShadingGroup *fx_shgrp; - bGPdata *gpd = cache->gpd; - copy_v3_v3(fxd->runtime.loc, cache->loc); - - fxd->size[2] = (int)fxd->flag & FX_PIXEL_USE_LINES; - - 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_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", fxd->runtime.loc, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); - - fxd->runtime.fx_sh = fx_shgrp; } -/* Rim FX */ -static void gpencil_fx_rim(ShaderFxData *fx, - GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache) +static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxData *iter) { - if (fx == NULL) { - return; + DRWShadingGroup *grp; + + float persmat[4][4], winmat[4][4], ob_center[3], pixsize_uniform[2]; + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_persmat_get(NULL, persmat, false); + const float *vp_size = DRW_viewport_size_get(); + const float *vp_size_inv = DRW_viewport_invert_size_get(); + float pixel_size[2] = {fx->size[0], fx->size[1]}; + mul_v2_v2(pixel_size, vp_size_inv); + + /* Fixed pixelisation center from object center. */ + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + mul_v3_m4v3(ob_center, persmat, ob->obmat[3]); + mul_v3_fl(ob_center, 1.0f / w); + + /* Convert to uvs. */ + mul_v2_fl(ob_center, 0.5f); + add_v2_fl(ob_center, 0.5f); + + /* Modify by distance to camera and object scale. */ + float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; + float scale = mat4_to_scale(ob->obmat); + mul_v2_fl(pixel_size, (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w); + + /* Center to texel */ + madd_v2_v2fl(ob_center, pixel_size, -0.5f); + + GPUShader *sh = GPENCIL_shader_fx_pixelize_get(); + + DRWState state = DRW_STATE_WRITE_COLOR; + + /* Only if pixelated effect is bigger than 1px. */ + if (pixel_size[0] > vp_size_inv[0]) { + copy_v2_fl2(pixsize_uniform, pixel_size[0], vp_size_inv[1]); + grp = gpencil_vfx_pass_create("Fx Pixelize X", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform); + DRW_shgroup_uniform_vec2_copy(grp, "targetPixelOffset", ob_center); + DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){pixel_size[0], 0.0f}); + DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + + if (pixel_size[1] > vp_size_inv[1]) { + copy_v2_fl2(pixsize_uniform, vp_size_inv[0], pixel_size[1]); + grp = gpencil_vfx_pass_create("Fx Pixelize Y", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform); + DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){0.0f, pixel_size[1]}); + DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } - RimShaderFxData *fxd = (RimShaderFxData *)fx; - bGPdata *gpd = cache->gpd; - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - DRWShadingGroup *fx_shgrp; - - GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); - copy_v3_v3(fxd->runtime.loc, cache->loc); - - /* prepare pass */ - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_prepare_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_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", fxd->runtime.loc, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx); - DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); - DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2); - - DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeRim", &stl->g_data->temp_color_tx_fx); - 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; } -/* Shadow FX */ -static void gpencil_fx_shadow(ShaderFxData *fx, - GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache) +static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData *iter) { - if (fx == NULL) { - return; - } - ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx; - if ((!fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) { - fxd->runtime.fx_sh = NULL; - fxd->runtime.fx_sh_b = NULL; - fxd->runtime.fx_sh_c = NULL; - return; - } - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - DRWShadingGroup *fx_shgrp; - bGPdata *gpd = cache->gpd; - copy_v3_v3(fxd->runtime.loc, cache->loc); - - GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); - /* prepare pass */ - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_shadow_prepare_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_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_float(fx_shgrp, "scale", &fxd->scale[0], 2); - DRW_shgroup_uniform_float(fx_shgrp, "rotation", &fxd->rotation, 1); - DRW_shgroup_uniform_vec4(fx_shgrp, "shadow_color", &fxd->shadow_rgba[0], 1); - - if ((fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) { - DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->object->obmat[3], 1); - } - else { - DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1); - } - - if (fxd->flag & FX_SHADOW_USE_WAVE) { - DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1); + DRWShadingGroup *grp; + + const bool use_obj_pivot = (fx->flag & FX_SHADOW_USE_OBJECT) != 0; + const bool use_wave = (fx->flag & FX_SHADOW_USE_WAVE) != 0; + + float uv_mat[4][4], winmat[4][4], persmat[4][4], rot_center[3]; + float wave_ofs[3], wave_dir[3], wave_phase, blur_dir[2], tmp[2]; + float offset[2] = {fx->offset[0], fx->offset[1]}; + float blur_size[2] = {fx->blur[0], fx->blur[1]}; + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_persmat_get(NULL, persmat, false); + const float *vp_size = DRW_viewport_size_get(); + const float *vp_size_inv = DRW_viewport_invert_size_get(); + const float ratio = vp_size_inv[1] / vp_size_inv[0]; + + copy_v3_v3(rot_center, (use_obj_pivot && fx->object) ? fx->object->obmat[3] : ob->obmat[3]); + + const float w = fabsf(mul_project_m4_v3_zfac(persmat, rot_center)); + mul_v3_m4v3(rot_center, persmat, rot_center); + mul_v3_fl(rot_center, 1.0f / w); + + /* Modify by distance to camera and object scale. */ + float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; + float scale = mat4_to_scale(ob->obmat); + float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; + mul_v2_fl(offset, distance_factor); + mul_v2_v2(offset, vp_size_inv); + mul_v2_fl(blur_size, distance_factor); + + rot_center[0] = rot_center[0] * 0.5f + 0.5f; + rot_center[1] = rot_center[1] * 0.5f + 0.5f; + + /* UV transform matrix. (loc, rot, scale) Sent to shader as 2x3 matrix. */ + unit_m4(uv_mat); + translate_m4(uv_mat, rot_center[0], rot_center[1], 0.0f); + rescale_m4(uv_mat, (float[3]){1.0f / fx->scale[0], 1.0f / fx->scale[1], 1.0f}); + translate_m4(uv_mat, -offset[0], -offset[1], 0.0f); + rescale_m4(uv_mat, (float[3]){1.0f / ratio, 1.0f, 1.0f}); + rotate_m4(uv_mat, 'Z', fx->rotation); + rescale_m4(uv_mat, (float[3]){ratio, 1.0f, 1.0f}); + translate_m4(uv_mat, -rot_center[0], -rot_center[1], 0.0f); + + if (use_wave) { + float dir[2]; + if (fx->orientation == 0) { + /* Horizontal */ + copy_v2_fl2(dir, 1.0f, 0.0f); + } + else { + /* Vertical */ + copy_v2_fl2(dir, 0.0f, 1.0f); + } + /* This is applied after rotation. Counter the rotation to keep aligned with global axis. */ + rotate_v2_v2fl(wave_dir, dir, fx->rotation); + /* Rotate 90°. */ + copy_v2_v2(wave_ofs, wave_dir); + SWAP(float, wave_ofs[0], wave_ofs[1]); + wave_ofs[1] *= -1.0f; + /* Keep world space scalling and aspect ratio. */ + mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor)); + mul_v2_v2(wave_dir, vp_size); + mul_v2_fl(wave_ofs, fx->amplitude * distance_factor); + mul_v2_v2(wave_ofs, vp_size_inv); + /* Phase start at shadow center. */ + wave_phase = fx->phase - dot_v2v2(rot_center, wave_dir); } else { - DRW_shgroup_uniform_int_copy(fx_shgrp, "orientation", -1); - } - 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_float(fx_shgrp, "pixsize", stl->storage->pixsize, 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx); - DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); - DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2); - - DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 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_shadow_resolve_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowColor", &stl->g_data->temp_color_tx_fx); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowDepth", &stl->g_data->temp_depth_tx_fx); - - fxd->runtime.fx_sh_c = fx_shgrp; + zero_v2(wave_dir); + zero_v2(wave_ofs); + wave_phase = 0.0f; + } + + GPUShader *sh = GPENCIL_shader_fx_shadow_get(); + + copy_v2_fl2(blur_dir, blur_size[0] * vp_size_inv[0], 0.0f); + + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Shadow H", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "blurDir", blur_dir); + DRW_shgroup_uniform_vec2_copy(grp, "waveDir", wave_dir); + DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs); + DRW_shgroup_uniform_float_copy(grp, "wavePhase", wave_phase); + DRW_shgroup_uniform_vec2_copy(grp, "uvRotX", uv_mat[0]); + DRW_shgroup_uniform_vec2_copy(grp, "uvRotY", uv_mat[1]); + DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", uv_mat[3]); + DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0]))); + DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", true); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + unit_m4(uv_mat); + zero_v2(wave_ofs); + + /* We reseted the uv_mat so we need to accound for the rotation in the */ + copy_v2_fl2(tmp, 0.0f, blur_size[1]); + rotate_v2_v2fl(blur_dir, tmp, -fx->rotation); + mul_v2_v2(blur_dir, vp_size_inv); + + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; + grp = gpencil_vfx_pass_create("Fx Shadow V", state, iter, sh); + DRW_shgroup_uniform_vec4_copy(grp, "shadowColor", fx->shadow_rgba); + DRW_shgroup_uniform_vec2_copy(grp, "blurDir", blur_dir); + DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs); + DRW_shgroup_uniform_vec2_copy(grp, "uvRotX", uv_mat[0]); + DRW_shgroup_uniform_vec2_copy(grp, "uvRotY", uv_mat[1]); + DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", uv_mat[3]); + DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1]))); + DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", false); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -/* Glow FX */ -static void gpencil_fx_glow(ShaderFxData *fx, - GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache) +static void gpencil_vfx_glow(GlowShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter) { - if (fx == NULL) { - return; - } - GlowShaderFxData *fxd = (GlowShaderFxData *)fx; - bGPdata *gpd = cache->gpd; - copy_v3_v3(fxd->runtime.loc, cache->loc); - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - DRWShadingGroup *fx_shgrp; - - GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); - /* prepare pass */ - fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_glow_prepare_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); - - DRW_shgroup_uniform_vec3(fx_shgrp, "glow_color", &fxd->glow_color[0], 1); - DRW_shgroup_uniform_vec3(fx_shgrp, "select_color", &fxd->select_color[0], 1); - DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1); - DRW_shgroup_uniform_float(fx_shgrp, "threshold", &fxd->threshold, 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx); - DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); - DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2); - - DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 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_glow_resolve_sh, psl->fx_shader_pass_blend); - DRW_shgroup_call(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowColor", &stl->g_data->temp_color_tx_fx); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowDepth", &stl->g_data->temp_depth_tx_fx); - - /* reuse field */ - DRW_shgroup_uniform_int(fx_shgrp, "alpha_mode", &fxd->blur[1], 1); - - fxd->runtime.fx_sh_c = fx_shgrp; -} + DRWShadingGroup *grp; -/* Swirl FX */ -static void gpencil_fx_swirl(ShaderFxData *fx, - GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache) -{ - if (fx == NULL) { - return; - } - SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; - if (fxd->object == NULL) { - return; - } + GPUShader *sh = GPENCIL_shader_fx_glow_get(); - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - DRWShadingGroup *fx_shgrp; - bGPdata *gpd = cache->gpd; + float ref_col[3]; - fxd->transparent = (int)fxd->flag & FX_SWIRL_MAKE_TRANSPARENT; + if (fx->mode == eShaderFxGlowMode_Luminance) { + ref_col[0] = fx->threshold; + ref_col[1] = -1.0f; + ref_col[2] = -1.0f; + } + else { + copy_v3_v3(ref_col, fx->select_color); + } + + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Glow H", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){fx->blur[0], 0.0f}); + DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, fx->blur[0]))); + DRW_shgroup_uniform_vec3_copy(grp, "threshold", ref_col); + DRW_shgroup_uniform_vec3_copy(grp, "glowColor", fx->glow_color); + DRW_shgroup_uniform_bool_copy(grp, "useAlphaMode", false); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + ref_col[0] = -1.0f; + + state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL; + grp = gpencil_vfx_pass_create("Fx Glow V", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){0.0f, fx->blur[0]}); + DRW_shgroup_uniform_vec3_copy(grp, "threshold", ref_col); + DRW_shgroup_uniform_vec3_copy(grp, "glowColor", (float[3]){1.0f, 1.0f, 1.0f}); + DRW_shgroup_uniform_bool_copy(grp, "useAlphaMode", (fx->flag & FX_GLOW_USE_ALPHA) != 0); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); +} - 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(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a); +static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *iter) +{ + DRWShadingGroup *grp; - DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); + float winmat[4][4], persmat[4][4], wave_center[3]; + float wave_ofs[3], wave_dir[3], wave_phase; + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_persmat_get(NULL, persmat, false); + const float *vp_size = DRW_viewport_size_get(); + const float *vp_size_inv = DRW_viewport_invert_size_get(); - DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->object->obmat[3], 1); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); + mul_v3_m4v3(wave_center, persmat, ob->obmat[3]); + mul_v3_fl(wave_center, 1.0f / w); - 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); + /* Modify by distance to camera and object scale. */ + float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; + float scale = mat4_to_scale(ob->obmat); + float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; - DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); - DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); + wave_center[0] = wave_center[0] * 0.5f + 0.5f; + wave_center[1] = wave_center[1] * 0.5f + 0.5f; - fxd->runtime.fx_sh = fx_shgrp; + if (fx->orientation == 0) { + /* Horizontal */ + copy_v2_fl2(wave_dir, 1.0f, 0.0f); + } + else { + /* Vertical */ + copy_v2_fl2(wave_dir, 0.0f, 1.0f); + } + /* Rotate 90°. */ + copy_v2_v2(wave_ofs, wave_dir); + SWAP(float, wave_ofs[0], wave_ofs[1]); + wave_ofs[1] *= -1.0f; + /* Keep world space scalling and aspect ratio. */ + mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor)); + mul_v2_v2(wave_dir, vp_size); + mul_v2_fl(wave_ofs, fx->amplitude * distance_factor); + mul_v2_v2(wave_ofs, vp_size_inv); + /* Phase start at shadow center. */ + wave_phase = fx->phase - dot_v2v2(wave_center, wave_dir); + + GPUShader *sh = GPENCIL_shader_fx_transform_get(); + + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Wave", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", (float[2]){1.0f, 1.0f}); + DRW_shgroup_uniform_vec2_copy(grp, "waveDir", wave_dir); + DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs); + DRW_shgroup_uniform_float_copy(grp, "wavePhase", wave_phase); + DRW_shgroup_uniform_float_copy(grp, "swirlRadius", 0.0f); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -/* Wave Distortion FX */ -static void gpencil_fx_wave(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata) +static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter) { - if (fx == NULL) { + DRWShadingGroup *grp; + + if (fx->object == NULL) { return; } - WaveShaderFxData *fxd = (WaveShaderFxData *)fx; - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPUBatch *fxquad = DRW_cache_fullscreen_quad_get(); + float winmat[4][4], persmat[4][4], swirl_center[3]; + DRW_view_winmat_get(NULL, winmat, false); + DRW_view_persmat_get(NULL, persmat, false); + const float *vp_size = DRW_viewport_size_get(); - DRWShadingGroup *fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_wave_sh, psl->fx_shader_pass); - DRW_shgroup_call(fx_shgrp, fxquad, NULL); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a); - DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_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); + copy_v3_v3(swirl_center, fx->object->obmat[3]); - 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); + const float w = fabsf(mul_project_m4_v3_zfac(persmat, swirl_center)); + mul_v3_m4v3(swirl_center, persmat, swirl_center); + mul_v3_fl(swirl_center, 1.0f / w); - e_data->gpencil_fx_rim_resolve_sh = DRW_shader_create_fullscreen( - datatoc_gpencil_fx_rim_resolve_frag_glsl, NULL); - } - if (!e_data->gpencil_fx_shadow_prepare_sh) { - e_data->gpencil_fx_shadow_prepare_sh = DRW_shader_create_fullscreen( - datatoc_gpencil_fx_shadow_prepare_frag_glsl, NULL); + /* Modify by distance to camera and object scale. */ + float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR; + float scale = mat4_to_scale(fx->object->obmat); + float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w; - e_data->gpencil_fx_shadow_resolve_sh = DRW_shader_create_fullscreen( - datatoc_gpencil_fx_shadow_resolve_frag_glsl, NULL); - } - if (!e_data->gpencil_fx_glow_prepare_sh) { - e_data->gpencil_fx_glow_prepare_sh = DRW_shader_create_fullscreen( - datatoc_gpencil_fx_glow_prepare_frag_glsl, NULL); + mul_v2_fl(swirl_center, 0.5f); + add_v2_fl(swirl_center, 0.5f); + mul_v2_v2(swirl_center, vp_size); - e_data->gpencil_fx_glow_resolve_sh = DRW_shader_create_fullscreen( - datatoc_gpencil_fx_glow_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); + float radius = fx->radius * distance_factor; + if (radius < 1.0f) { + return; } -} -/* 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_shadow_prepare_sh); - DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_shadow_resolve_sh); - DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_prepare_sh); - DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_resolve_sh); - DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_swirl_sh); - DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_wave_sh); -} + GPUShader *sh = GPENCIL_shader_fx_transform_get(); -/* 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_ALPHA | - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + DRWState state = DRW_STATE_WRITE_COLOR; + grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh); + DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", (float[2]){1.0f, 1.0f}); + DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", (float[2]){0.0f, 0.0f}); + DRW_shgroup_uniform_vec2_copy(grp, "swirlCenter", swirl_center); + DRW_shgroup_uniform_float_copy(grp, "swirlAngle", fx->angle); + DRW_shgroup_uniform_float_copy(grp, "swirlRadius", radius); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -/* prepare fx shading groups */ -void gpencil_fx_prepare(GPENCIL_e_data *e_data, - GPENCIL_Data *vedata, - tGPencilObjectCache *cache_ob) +void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob) { - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - const bool wiremode = (bool)(cache_ob->shading_type[0] == OB_WIRE); - - int ob_idx = cache_ob->idx; - - if ((wiremode) || (cache_ob->shader_fx.first == NULL)) { + bGPdata *gpd = (bGPdata *)ob->data; + GPENCIL_FramebufferList *fbl = vedata->fbl; + GPENCIL_PrivateData *pd = vedata->stl->pd; + /* If simplify enabled, nothing more to do. */ + if (pd->simplify_fx) { return; } - /* loop FX */ - for (ShaderFxData *fx = cache_ob->shader_fx.first; fx; fx = fx->next) { - if (effect_is_active(cache_ob->gpd, fx, stl->storage->is_render)) { + + /* These may not be allocated yet, use adress of future pointer. */ + gpIterVfxData iter = { + .pd = pd, + .tgp_ob = tgp_ob, + .target_fb = &fbl->layer_fb, + .source_fb = &fbl->object_fb, + .target_color_tx = &pd->color_layer_tx, + .source_color_tx = &pd->color_object_tx, + .target_reveal_tx = &pd->reveal_layer_tx, + .source_reveal_tx = &pd->reveal_object_tx, + }; + + LISTBASE_FOREACH (ShaderFxData *, fx, &ob->shader_fx) { + if (effect_is_active(gpd, fx, pd->is_render)) { switch (fx->type) { case eShaderFxType_Blur: - gpencil_fx_blur(fx, ob_idx, e_data, vedata, cache_ob); + gpencil_vfx_blur((BlurShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Colorize: - gpencil_fx_colorize(fx, e_data, vedata); + gpencil_vfx_colorize((ColorizeShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Flip: - gpencil_fx_flip(fx, e_data, vedata); - break; - case eShaderFxType_Light: - gpencil_fx_light(fx, e_data, vedata, cache_ob); + gpencil_vfx_flip((FlipShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Pixel: - gpencil_fx_pixel(fx, e_data, vedata, cache_ob); + gpencil_vfx_pixelize((PixelShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Rim: - gpencil_fx_rim(fx, e_data, vedata, cache_ob); + gpencil_vfx_rim((RimShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Shadow: - gpencil_fx_shadow(fx, e_data, vedata, cache_ob); + gpencil_vfx_shadow((ShadowShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Glow: - gpencil_fx_glow(fx, e_data, vedata, cache_ob); + gpencil_vfx_glow((GlowShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Swirl: - gpencil_fx_swirl(fx, e_data, vedata, cache_ob); + gpencil_vfx_swirl((SwirlShaderFxData *)fx, ob, &iter); break; case eShaderFxType_Wave: - gpencil_fx_wave(fx, e_data, vedata); + gpencil_vfx_wave((WaveShaderFxData *)fx, ob, &iter); break; default: break; } } } -} - -/* helper to draw one FX pass and do ping-pong copy */ -static void gpencil_draw_fx_pass(GPENCIL_Data *vedata, DRWShadingGroup *shgrp, bool blend) -{ - if (shgrp == NULL) { - return; - } - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; - - const float clearcol[4] = {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 */ - stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b; - stl->g_data->input_color_tx = stl->g_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(GPENCIL_Data *vedata, BlurShaderFxData *fxd) -{ - if (fxd->runtime.fx_sh == NULL) { - return; - } - - 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(vedata, shgrp, true); - } - /* vertical */ - if (by > 0) { - fxd->blur[0] = 0; - fxd->blur[1] = by; - gpencil_draw_fx_pass(vedata, shgrp, true); - } - } -} - -/* blur intermediate pass */ -static void draw_gpencil_midpass_blur(GPENCIL_Data *vedata, ShaderFxData_Runtime *runtime) -{ - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; - const float clearcol[4] = {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, runtime->fx_sh_b, runtime->fx_sh_b); - - /* copy pass from b for ping-pong frame buffers */ - GPU_framebuffer_bind(fbl->temp_fb_fx); - GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f); - DRW_draw_pass(psl->mix_pass_noblend); -} - -/* do blur of mid passes */ -static void draw_gpencil_do_blur( - GPENCIL_Data *vedata, ShaderFxData_Runtime *runtime, int samples, int bx, int by, int blur[2]) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - - stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b; - stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b; - - if ((samples > 0) && ((bx > 0) || (by > 0))) { - for (int x = 0; x < samples; x++) { - - /* horizontal */ - blur[0] = bx; - blur[1] = 0; - draw_gpencil_midpass_blur(vedata, runtime); - - /* Vertical */ - blur[0] = 0; - blur[1] = by; - draw_gpencil_midpass_blur(vedata, runtime); - - blur[0] = bx; - blur[1] = by; - } - } -} - -/* helper to draw RIM passes */ -static void draw_gpencil_rim_passes(GPENCIL_Data *vedata, RimShaderFxData *fxd) -{ - if (fxd->runtime.fx_sh_b == NULL) { - return; - } - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; - - const float clearcol[4] = {0.0f}; - - /* prepare mask */ - GPU_framebuffer_bind(fbl->temp_fb_fx); - GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f); - DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh); - - /* blur rim */ - draw_gpencil_do_blur( - vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[1], &fxd->blur[0]); - - /* 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 */ - stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b; - stl->g_data->input_color_tx = stl->g_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 draw SHADOW passes */ -static void draw_gpencil_shadow_passes(GPENCIL_Data *vedata, ShadowShaderFxData *fxd) -{ - if (fxd->runtime.fx_sh_b == NULL) { - return; - } - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; - const float clearcol[4] = {0.0f}; - - /* prepare shadow */ - GPU_framebuffer_bind(fbl->temp_fb_fx); - GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f); - DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh); - - /* blur shadow */ - draw_gpencil_do_blur( - vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[1], &fxd->blur[0]); - - /* 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 */ - stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b; - stl->g_data->input_color_tx = stl->g_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 draw GLOW passes */ -static void draw_gpencil_glow_passes(GPENCIL_Data *vedata, GlowShaderFxData *fxd) -{ - if (fxd->runtime.fx_sh_b == NULL) { - return; - } - - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; - - const float clearcol[4] = {0.0f}; - /* prepare glow */ - GPU_framebuffer_bind(fbl->temp_fb_fx); - GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f); - DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh); + if (tgp_ob->vfx.first != NULL) { + /* We need an extra pass to combine result to main buffer. */ + iter.target_fb = &fbl->gpencil_fb; - /* blur glow */ - draw_gpencil_do_blur( - vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[0], &fxd->blur[0]); + GPUShader *sh = GPENCIL_shader_fx_composite_get(); - /* resolve */ - GPU_framebuffer_bind(fbl->temp_fb_b); - GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; + DRWShadingGroup *grp = gpencil_vfx_pass_create("GPencil Object Compose", state, &iter, sh); + DRW_shgroup_uniform_int_copy(grp, "isFirstPass", true); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - /* reuses blur field to keep alpha mode */ - fxd->blur[1] = (fxd->flag & FX_GLOW_USE_ALPHA) ? 1 : 0; + /* We cannot do custom blending on MultiTarget framebuffers. + * Workaround by doing 2 passes. */ + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL); + DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL); + DRW_shgroup_uniform_int_copy(grp, "isFirstPass", false); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); - 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 */ - stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b; - stl->g_data->input_color_tx = stl->g_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 gpencil_fx_draw(GPENCIL_e_data *UNUSED(e_data), - GPENCIL_Data *vedata, - tGPencilObjectCache *cache_ob) -{ - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - - /* loop FX modifiers */ - for (ShaderFxData *fx = cache_ob->shader_fx.first; fx; fx = fx->next) { - if (effect_is_active(cache_ob->gpd, fx, stl->storage->is_render)) { - switch (fx->type) { - - case eShaderFxType_Blur: { - BlurShaderFxData *fxd = (BlurShaderFxData *)fx; - draw_gpencil_blur_passes(vedata, fxd); - break; - } - case eShaderFxType_Colorize: { - ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx; - gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false); - break; - } - case eShaderFxType_Flip: { - FlipShaderFxData *fxd = (FlipShaderFxData *)fx; - gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false); - break; - } - case eShaderFxType_Light: { - LightShaderFxData *fxd = (LightShaderFxData *)fx; - gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false); - break; - } - case eShaderFxType_Pixel: { - PixelShaderFxData *fxd = (PixelShaderFxData *)fx; - gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false); - break; - } - case eShaderFxType_Rim: { - RimShaderFxData *fxd = (RimShaderFxData *)fx; - draw_gpencil_rim_passes(vedata, fxd); - break; - } - case eShaderFxType_Shadow: { - ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx; - draw_gpencil_shadow_passes(vedata, fxd); - break; - } - case eShaderFxType_Glow: { - GlowShaderFxData *fxd = (GlowShaderFxData *)fx; - draw_gpencil_glow_passes(vedata, fxd); - break; - } - case eShaderFxType_Swirl: { - SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; - gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false); - break; - } - case eShaderFxType_Wave: { - WaveShaderFxData *fxd = (WaveShaderFxData *)fx; - gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false); - break; - } - default: - break; - } - } + pd->use_object_fb = true; } } 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 deleted file mode 100644 index 0f64f54c67b..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl +++ /dev/null @@ -1,85 +0,0 @@ -uniform mat4 ProjectionMatrix; -uniform mat4 ViewMatrix; - -uniform sampler2D strokeColor; -uniform sampler2D strokeDepth; -uniform vec2 Viewport; - -uniform int blur[2]; - -uniform vec3 loc; -uniform float pixsize; /* rv3d->pixsize */ -uniform float pixfactor; - -float defaultpixsize = pixsize * (1000.0 / pixfactor); -vec2 noffset = vec2(blur[0], blur[1]); - -out vec4 FragColor; - -float get_zdepth(ivec2 poxy) -{ - /* if outside viewport set as infinite depth */ - if ((poxy.x < 0) || (poxy.x > Viewport.x)) { - return 1.0f; - } - if ((poxy.y < 0) || (poxy.y > Viewport.y)) { - return 1.0f; - } - - float zdepth = texelFetch(strokeDepth, poxy, 0).r; - return zdepth; -} - -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); - - /* round to avoid shift when add more samples */ - dx = floor(dx) + 1.0; - dy = floor(dy) + 1.0; - - /* apply blurring, using a 9-tap filter with predefined gaussian weights */ - /* depth (get the value of the surrounding pixels) */ - float outdepth = get_zdepth(ivec2(uv.x, uv.y)); - for (int x = -1; x < 2; x++) { - for (int y = -1; y < 2; y++) { - float depth = get_zdepth(ivec2(uv.x + x * dx, uv.y + y * dy)); - if (depth < outdepth) { - outdepth = depth; - break; - } - } - } - 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); - - /* discar extreme values */ - if (outcolor.a < 0.02f) { - discard; - } - if ((outdepth <= 0.000001) || (outdepth >= 0.999999)) { - discard; - } -} 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 deleted file mode 100644 index 52f42d30d06..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl +++ /dev/null @@ -1,82 +0,0 @@ -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_DUOTONE 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_DUOTONE: { - 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 deleted file mode 100644 index 2cd77007b36..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl +++ /dev/null @@ -1,37 +0,0 @@ -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_glow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl deleted file mode 100644 index 676b9b05db9..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl +++ /dev/null @@ -1,68 +0,0 @@ -uniform mat4 ProjectionMatrix; -uniform mat4 ViewMatrix; - -/* ******************************************************************* */ -/* create glow mask */ -/* ******************************************************************* */ -uniform sampler2D strokeColor; -uniform sampler2D strokeDepth; - -uniform vec3 glow_color; -uniform vec3 select_color; -uniform float threshold; -uniform int mode; - -out vec4 FragColor; - -#define MODE_LUMINANCE 0 -#define MODE_COLOR 1 - -/* calc luminance */ -float luma(vec3 color) -{ - /* the color is linear, so do not apply tonemapping */ - return (color.r + color.g + color.b) / 3.0; -} - -bool check_color(vec3 color_a, vec3 color_b) -{ - /* need round the number to avoid precision errors */ - if ((floor(color_a.r * 100) == floor(color_b.r * 100)) && - (floor(color_a.g * 100) == floor(color_b.g * 100)) && - (floor(color_a.b * 100) == floor(color_b.b * 100))) { - return true; - } - - return false; -} - -void main() -{ - vec2 uv = vec2(gl_FragCoord.xy); - - float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r; - vec4 src_pixel = texelFetch(strokeColor, ivec2(uv.xy), 0); - vec4 outcolor; - - /* is transparent */ - if (src_pixel.a == 0.0f) { - discard; - } - - if (mode == MODE_LUMINANCE) { - if (luma(src_pixel.rgb) < threshold) { - discard; - } - } - else if (mode == MODE_COLOR) { - if (!check_color(src_pixel.rgb, select_color.rgb)) { - discard; - } - } - else { - discard; - } - - gl_FragDepth = stroke_depth; - FragColor = vec4(glow_color.rgb, 1.0); -} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl deleted file mode 100644 index e2aceb9eefe..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl +++ /dev/null @@ -1,46 +0,0 @@ -/* ******************************************************************* */ -/* Resolve GLOW pass */ -/* ******************************************************************* */ -uniform sampler2D strokeColor; -uniform sampler2D strokeDepth; -uniform sampler2D glowColor; -uniform sampler2D glowDepth; -uniform int alpha_mode; - -out vec4 FragColor; - -void main() -{ - vec4 outcolor; - ivec2 uv = ivec2(gl_FragCoord.xy); - - float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r; - vec4 src_pixel = texelFetch(strokeColor, uv.xy, 0); - vec4 glow_pixel = texelFetch(glowColor, uv.xy, 0); - float glow_depth = texelFetch(glowDepth, uv.xy, 0).r; - - if (alpha_mode == 0) { - outcolor = src_pixel + glow_pixel; - } - else { - if ((src_pixel.a < 0.1) || (glow_pixel.a < 0.1)) { - outcolor = src_pixel + glow_pixel; - } - else { - outcolor = src_pixel; - } - } - - if (src_pixel.a < glow_pixel.a) { - gl_FragDepth = glow_depth; - } - else { - gl_FragDepth = stroke_depth; - } - - if (outcolor.a < 0.001) { - discard; - } - - 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 deleted file mode 100644 index a5c321c20c1..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl +++ /dev/null @@ -1,70 +0,0 @@ -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 pixfactor; - -out vec4 FragColor; - -float defaultpixsize = pixsize * (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 deleted file mode 100644 index 46b3c4286b4..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl +++ /dev/null @@ -1,51 +0,0 @@ -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 pixfactor; - -out vec4 FragColor; - -int uselines = size[2]; -float defaultpixsize = pixsize * (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 deleted file mode 100644 index 2a17e573978..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl +++ /dev/null @@ -1,65 +0,0 @@ -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 pixfactor; - -float defaultpixsize = pixsize * (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 deleted file mode 100644 index fa010baa32f..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl +++ /dev/null @@ -1,98 +0,0 @@ -/* ******************************************************************* */ -/* 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_shadow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl deleted file mode 100644 index d2e20feae18..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl +++ /dev/null @@ -1,98 +0,0 @@ -uniform mat4 ProjectionMatrix; -uniform mat4 ViewMatrix; - -/* ******************************************************************* */ -/* create shadow */ -/* ******************************************************************* */ -uniform sampler2D strokeColor; -uniform sampler2D strokeDepth; -uniform vec2 Viewport; - -uniform int offset[2]; -uniform float scale[2]; -uniform float rotation; -uniform vec4 shadow_color; - -uniform float amplitude; -uniform float period; -uniform float phase; -uniform int orientation; - -uniform vec3 loc; -uniform float pixsize; /* rv3d->pixsize */ -uniform float pixfactor; - -#define M_PI 3.1415926535897932384626433832795 - -#define HORIZONTAL 0 -#define VERTICAL 1 - -float defaultpixsize = pixsize * (1000.0 / pixfactor); -vec2 noffset = vec2(offset[0], offset[1]); -float cosv = cos(rotation); -float sinv = sin(rotation); - -out vec4 FragColor; - -/* 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() -{ - vec2 uv = vec2(gl_FragCoord.xy); - vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0); - vec2 loc2d = toScreenSpace(nloc); - - 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); - - /* move point to new coords system */ - vec2 tpos = vec2(uv.x, uv.y) - loc2d; - - /* rotation */ - if (rotation != 0) { - vec2 rotpoint = vec2((tpos.x * cosv) - (tpos.y * sinv), (tpos.x * sinv) + (tpos.y * cosv)); - tpos = rotpoint; - } - - /* apply offset */ - tpos = vec2(tpos.x - dx, tpos.y - dy); - - /* apply scale */ - tpos.x *= 1.0 / scale[0]; - tpos.y *= 1.0 / scale[1]; - - /* back to original coords system */ - vec2 texpos = tpos + loc2d; - - /* wave */ - if (orientation == HORIZONTAL) { - float pval = (uv.x * M_PI) / Viewport[0]; - texpos.y += amplitude * sin((period * pval) + phase); - } - else if (orientation == VERTICAL) { - float pval = (uv.y * M_PI) / Viewport[1]; - texpos.x += amplitude * sin((period * pval) + phase); - } - - vec4 src_pixel = texelFetch(strokeColor, ivec2(texpos.x, texpos.y), 0); - /* is transparent */ - if (src_pixel.a == 0.0f) { - discard; - } - - gl_FragDepth = texelFetch(strokeDepth, ivec2(texpos.x, texpos.y), 0).r; - FragColor = shadow_color; -} diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl deleted file mode 100644 index 3ef11008adf..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl +++ /dev/null @@ -1,32 +0,0 @@ -/* ******************************************************************* */ -/* Resolve Shadow pass */ -/* ******************************************************************* */ -uniform sampler2D strokeColor; -uniform sampler2D strokeDepth; -uniform sampler2D shadowColor; -uniform sampler2D shadowDepth; - -out vec4 FragColor; - -void main() -{ - ivec2 uv = ivec2(gl_FragCoord.xy); - - float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r; - float shadow_depth = texelFetch(shadowDepth, uv.xy, 0).r; - vec4 stroke_pixel = texelFetch(strokeColor, uv.xy, 0); - vec4 shadow_pixel = texelFetch(shadowColor, uv.xy, 0); - - /* copy original pixel */ - vec4 outcolor = stroke_pixel; - float outdepth = stroke_depth; - - /* if stroke is not on top, copy shadow */ - if ((stroke_pixel.a <= 0.2) && (shadow_pixel.a > 0.0)) { - outcolor = shadow_pixel; - outdepth = shadow_depth; - } - - gl_FragDepth = outdepth; - 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 deleted file mode 100644 index 01d4fe40195..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl +++ /dev/null @@ -1,74 +0,0 @@ -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 pixfactor; - -out vec4 FragColor; - -float defaultpixsize = pixsize * (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 locpixsize = abs((loc.z * defaultpixsize)); - if (locpixsize == 0) { - locpixsize = 1; - } - float pxradius = (ProjectionMatrix[3][3] == 0.0) ? (radius / locpixsize) : - (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 deleted file mode 100644 index 0a5df9f6d77..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl +++ /dev/null @@ -1,44 +0,0 @@ - -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; - - if (outcolor.a < 0.02f) { - discard; - } -} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl new file mode 100644 index 00000000000..cdcd978015c --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl @@ -0,0 +1,43 @@ + +uniform sampler2D edgesTex; +uniform sampler2D areaTex; +uniform sampler2D searchTex; +uniform sampler2D blendTex; +uniform sampler2D colorTex; +uniform sampler2D revealTex; + +in vec2 uvs; +in vec2 pixcoord; +in vec4 offset[3]; + +#if SMAA_STAGE == 0 +out vec2 fragColor; +#elif SMAA_STAGE == 1 +out vec4 fragColor; +#elif SMAA_STAGE == 2 +layout(location = 0) out vec4 outColor; +layout(location = 1) out vec4 outReveal; +#endif + +void main() +{ +#if SMAA_STAGE == 0 + /* Detect edges in color and revealage buffer. */ + fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex); + fragColor = max(fragColor, SMAALumaEdgeDetectionPS(uvs, offset, revealTex)); + /* Discard if there is no edge. */ + if (dot(fragColor, float2(1.0, 1.0)) == 0.0) { + discard; + } + +#elif SMAA_STAGE == 1 + fragColor = SMAABlendingWeightCalculationPS( + uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0)); + +#elif SMAA_STAGE == 2 + /* Resolve both buffers. */ + outColor = SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex); + outReveal = SMAANeighborhoodBlendingPS(uvs, offset[0], revealTex, blendTex); + +#endif +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl new file mode 100644 index 00000000000..07734d19972 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl @@ -0,0 +1,21 @@ + +out vec2 uvs; +out vec2 pixcoord; +out vec4 offset[3]; + +void main() +{ + int v = gl_VertexID % 3; + float x = -1.0 + float((v & 1) << 2); + float y = -1.0 + float((v & 2) << 1); + gl_Position = vec4(x, y, 1.0, 1.0); + uvs = (gl_Position.xy + 1.0) * 0.5; + +#if SMAA_STAGE == 0 + SMAAEdgeDetectionVS(uvs, offset); +#elif SMAA_STAGE == 1 + SMAABlendingWeightCalculationVS(uvs, pixcoord, offset); +#elif SMAA_STAGE == 2 + SMAANeighborhoodBlendingVS(uvs, offset[0]); +#endif +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl deleted file mode 100644 index 18803bfa3fa..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl +++ /dev/null @@ -1,12 +0,0 @@ -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_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl deleted file mode 100644 index 85dee4390a5..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl +++ /dev/null @@ -1,157 +0,0 @@ -in vec4 uvcoordsvar; - -out vec4 FragColor; - -uniform sampler2D strokeColor; -uniform sampler2D strokeDepth; -uniform sampler2D blendColor; -uniform sampler2D blendDepth; -uniform int mode; -uniform int mask_layer; -uniform int tonemapping; - -#define ON 1 -#define OFF 0 - -#define MODE_REGULAR 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 (mix_color.a == 0) { - return src_color; - } - - switch (mode) { - case MODE_REGULAR: { - /* premult */ - src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a); - mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a); - - outcolor = vec4(mix(src_color.rgb, mix_color.rgb, mix_color.a), src_color.a); - break; - } - case MODE_OVERLAY: { - src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a); - mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a); - - mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a); - 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); - outcolor.a = src_color.a; - break; - } - case MODE_ADD: { - mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a); - outcolor = src_color + mix_color; - outcolor.a = src_color.a; - break; - } - case MODE_SUB: { - mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a); - outcolor = src_color - mix_color; - outcolor.a = clamp(src_color.a - mix_color.a, 0.0, 1.0); - break; - } - case MODE_MULTIPLY: { - src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a); - mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a); - - mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a); - outcolor = src_color * mix_color; - outcolor.a = src_color.a; - break; - } - case MODE_DIVIDE: { - mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a); - outcolor = src_color / mix_color; - outcolor.a = src_color.a; - break; - } - default: { - outcolor = mix_color; - outcolor.a = src_color.a; - break; - } - } - return clamp(outcolor, 0.0, 1.0); -} - -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; - } -} - -vec4 tone(vec4 stroke_color) -{ - if (tonemapping == 1) { - vec4 color = vec4(0, 0, 0, stroke_color.a); - color.r = linearrgb_to_srgb(stroke_color.r); - color.g = linearrgb_to_srgb(stroke_color.g); - color.b = linearrgb_to_srgb(stroke_color.b); - return color; - } - else { - return stroke_color; - } -} - -void main() -{ - vec4 outcolor; - ivec2 uv = ivec2(gl_FragCoord.xy); - vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba; - float stroke_depth = texelFetch(strokeDepth, uv, 0).r; - - vec4 mix_color = texelFetch(blendColor, uv, 0).rgba; - float mix_depth = texelFetch(blendDepth, uv, 0).r; - - if (stroke_color.a > 0) { - if (mix_color.a > 0) { - /* apply blend mode */ - FragColor = get_blend_color(mode, stroke_color, mix_color); - } - else { - FragColor = stroke_color; - } - gl_FragDepth = min(stroke_depth, mix_depth); - } - else { - if (mask_layer == ON) { - discard; - } - else { - /* if not using mask, return mix color */ - FragColor = mix_color; - gl_FragDepth = mix_depth; - } - } - - /* apply tone mapping */ - FragColor = tone(FragColor); -} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl new file mode 100644 index 00000000000..83fa9d5d0f6 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl @@ -0,0 +1,549 @@ + +/* Must match C declaration. */ +struct gpMaterial { + vec4 stroke_color; + vec4 fill_color; + vec4 fill_mix_color; + vec4 fill_uv_rot_scale; + vec4 fill_uv_offset; + /* Put float/int at the end to avoid padding error */ + float stroke_texture_mix; + float stroke_u_scale; + float fill_texture_mix; + int flag; + /* Please ensure 16 byte alignment (multiple of vec4). */ +}; + +/* flag */ +#define GP_STROKE_ALIGNMENT_STROKE 1 +#define GP_STROKE_ALIGNMENT_OBJECT 2 +#define GP_STROKE_ALIGNMENT_FIXED 3 +#define GP_STROKE_ALIGNMENT 0x3 +#define GP_STROKE_OVERLAP (1 << 2) +#define GP_STROKE_TEXTURE_USE (1 << 3) +#define GP_STROKE_TEXTURE_STENCIL (1 << 4) +#define GP_STROKE_TEXTURE_PREMUL (1 << 5) +#define GP_STROKE_DOTS (1 << 6) +#define GP_FILL_TEXTURE_USE (1 << 10) +#define GP_FILL_TEXTURE_PREMUL (1 << 11) +#define GP_FILL_TEXTURE_CLIP (1 << 12) +#define GP_FILL_GRADIENT_USE (1 << 13) +#define GP_FILL_GRADIENT_RADIAL (1 << 14) +/* High bits are used to pass material ID to fragment shader. */ +#define GP_MATID_SHIFT 16 + +/* Multiline defines can crash blender with certain GPU drivers. */ +/* clang-format off */ +#define GP_FILL_FLAGS (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP | GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL) +/* clang-format on */ + +#define GP_FLAG_TEST(flag, val) (((flag) & (val)) != 0) + +/* Must match C declaration. */ +struct gpLight { + vec4 color_type; + vec4 right; + vec4 up; + vec4 forward; + vec4 position; + /* Please ensure 16 byte alignment (multiple of vec4). */ +}; + +#define spot_size right.w +#define spot_blend up.w + +#define GP_LIGHT_TYPE_POINT 0.0 +#define GP_LIGHT_TYPE_SPOT 1.0 +#define GP_LIGHT_TYPE_SUN 2.0 +#define GP_LIGHT_TYPE_AMBIENT 3.0 + +#ifdef GP_MATERIAL_BUFFER_LEN + +layout(std140) uniform gpMaterialBlock +{ + gpMaterial materials[GP_MATERIAL_BUFFER_LEN]; +}; + +#endif + +#ifdef GPENCIL_LIGHT_BUFFER_LEN + +layout(std140) uniform gpLightBlock +{ + gpLight lights[GPENCIL_LIGHT_BUFFER_LEN]; +}; + +#endif + +/* Must match eGPLayerBlendModes */ +#define MODE_REGULAR 0 +#define MODE_OVERLAY 1 +#define MODE_ADD 2 +#define MODE_SUB 3 +#define MODE_MULTIPLY 4 +#define MODE_DIVIDE 5 +#define MODE_OVERLAY_SECOND_PASS 999 + +void blend_mode_output( + int blend_mode, vec4 color, float opacity, out vec4 frag_color, out vec4 frag_revealage) +{ + switch (blend_mode) { + case MODE_REGULAR: + /* Reminder: Blending func is premult alpha blend (dst.rgba * (1 - src.a) + src.rgb).*/ + color *= opacity; + frag_color = color; + frag_revealage = vec4(0.0, 0.0, 0.0, color.a); + break; + case MODE_MULTIPLY: + /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/ + color.a *= opacity; + frag_revealage = frag_color = (1.0 - color.a) + color.a * color; + break; + case MODE_DIVIDE: + /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/ + color.a *= opacity; + frag_revealage = frag_color = clamp(1.0 / (1.0 - color * color.a), 0.0, 1e18); + break; + case MODE_OVERLAY: + /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/ + /** + * We need to separate the overlay equation into 2 term (one mul and one add). + * This is the standard overlay equation (per channel): + * rtn = (src < 0.5) ? (2.0 * src * dst) : (1.0 - 2.0 * (1.0 - src) * (1.0 - dst)); + * We rewrite the second branch like this: + * rtn = 1 - 2 * (1 - src) * (1 - dst); + * rtn = 1 - 2 (1 - dst + src * dst - src); + * rtn = 1 - 2 (1 - dst * (1 - src) - src); + * rtn = 1 - 2 + dst * (2 - 2 * src) + 2 * src; + * rtn = (- 1 + 2 * src) + dst * (2 - 2 * src); + **/ + color = mix(vec4(0.5), color, color.a * opacity); + vec4 s = step(-0.5, -color); + frag_revealage = frag_color = 2.0 * s + 2.0 * color * (1.0 - s * 2.0); + break; + case MODE_OVERLAY_SECOND_PASS: + /* Reminder: Blending func is additive blend (dst.rgba + src.rgba).*/ + color = mix(vec4(0.5), color, color.a * opacity); + frag_revealage = frag_color = (-1.0 + 2.0 * color) * step(-0.5, -color); + break; + case MODE_SUB: + case MODE_ADD: + /* Reminder: Blending func is additive / subtractive blend (dst.rgba +/- src.rgba).*/ + frag_color = color * color.a * opacity; + frag_revealage = vec4(0.0); + break; + } +} + +#ifdef GPU_VERTEX_SHADER +# define IN_OUT out +#else +# define IN_OUT in +#endif + +/* Shader interface. */ +IN_OUT vec4 finalColorMul; +IN_OUT vec4 finalColorAdd; +IN_OUT vec3 finalPos; +IN_OUT vec2 finalUvs; +noperspective IN_OUT float strokeThickness; +flat IN_OUT vec2 strokePt1; +flat IN_OUT vec2 strokePt2; +flat IN_OUT int matFlag; +flat IN_OUT float depth; + +#ifdef GPU_FRAGMENT_SHADER + +float stroke_round_cap_mask(vec2 p1, vec2 p2, float thickness) +{ + /* We create our own uv space to avoid issues with triangulation and linear + * interpolation artifacts. */ + vec2 line = p2.xy - p1.xy; + vec2 pos = gl_FragCoord.xy - p1.xy; + float line_len = length(line); + float half_line_len = line_len * 0.5; + /* Normalize */ + line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0); + /* Create a uv space that englobe the whole segment into a capsule. */ + vec2 uv_end; + uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0); + uv_end.y = dot(vec2(-line.y, line.x), pos); + /* Divide by stroke radius. */ + uv_end /= thickness; + + return (dot(uv_end, uv_end) > 0.25) ? 0.0 : 1.0; +} + +#endif + +/* TODO UBO */ +uniform vec2 sizeViewport; +uniform vec2 sizeViewportInv; + +/* Per Object */ +uniform bool strokeOrder3d; +uniform int gpMaterialOffset; +uniform float thicknessScale; +uniform float thicknessWorldScale; +#define thicknessIsScreenSpace (thicknessWorldScale < 0.0) +#define MATERIAL(m) materials[m + gpMaterialOffset] + +#ifdef GPU_VERTEX_SHADER + +/* Per Layer */ +uniform float thicknessOffset; +uniform float vertexColorOpacity; +uniform vec4 layerTint; +uniform float layerOpacity; /* Used for onion skin. */ +uniform float strokeIndexOffset = 0.0; + +in vec4 ma; +in vec4 ma1; +in vec4 ma2; +in vec4 ma3; +# define strength1 ma1.y +# define strength2 ma2.y +# define stroke_id1 ma1.z +# define point_id1 ma1.w +/* Position contains thickness in 4th component. */ +in vec4 pos; /* Prev adj vert */ +in vec4 pos1; /* Current edge */ +in vec4 pos2; /* Current edge */ +in vec4 pos3; /* Next adj vert */ +# define thickness1 pos1.w +# define thickness2 pos2.w +/* xy is UV for fills, z is U of stroke, w is cosine of UV angle with sign of sine. */ +in vec4 uv1; +in vec4 uv2; + +in vec4 col1; +in vec4 col2; + +in vec4 fcol1; + +void discard_vert() +{ + /* We set the vertex at the camera origin to generate 0 fragments. */ + gl_Position = vec4(0.0, 0.0, -3e36, 0.0); +} + +vec2 project_to_screenspace(vec4 v) +{ + return ((v.xy / v.w) * 0.5 + 0.5) * sizeViewport; +} + +vec2 rotate_90deg(vec2 v) +{ + /* Counter Clock-Wise. */ + return vec2(-v.y, v.x); +} + +mat4 model_matrix_get() +{ + return ModelMatrix; +} + +vec3 transform_point(mat4 m, vec3 v) +{ + return (m * vec4(v, 1.0)).xyz; +} + +vec2 safe_normalize(vec2 v) +{ + float len_sqr = dot(v, v); + if (len_sqr > 0.0) { + return v / sqrt(len_sqr); + } + else { + return vec2(1.0, 0.0); + } +} + +vec2 safe_normalize_len(vec2 v, out float len) +{ + len = sqrt(dot(v, v)); + if (len > 0.0) { + return v / len; + } + else { + return vec2(1.0, 0.0); + } +} + +float stroke_thickness_modulate(float thickness) +{ + /* Modify stroke thickness by object and layer factors.-*/ + thickness *= thicknessScale; + thickness += thicknessOffset; + thickness = max(1.0, thickness); + + if (thicknessIsScreenSpace) { + /* Multiply offset by view Z so that offset is constant in screenspace. + * (e.i: does not change with the distance to camera) */ + thickness *= gl_Position.w; + } + else { + /* World space point size. */ + thickness *= thicknessWorldScale * ProjectionMatrix[1][1] * sizeViewport.y; + } + return thickness; +} + +# ifdef GP_MATERIAL_BUFFER_LEN +void color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex) +{ + /* Mix stroke with other colors. */ + vec4 mixed_col = stroke_col; + mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a * vertexColorOpacity); + mixed_col.rgb = mix(mixed_col.rgb, layerTint.rgb, layerTint.a); + mixed_col.a *= vert_strength * layerOpacity; + /** + * This is what the fragment shader looks like. + * out = col * finalColorMul + col.a * finalColorAdd. + * finalColorMul is how much of the texture color to keep. + * finalColorAdd is how much of the mixed color to add. + * Note that we never add alpha. This is to keep the texture act as a stencil. + * We do however, modulate the alpha (reduce it). + **/ + /* We add the mixed color. This is 100% mix (no texture visible). */ + finalColorMul = vec4(mixed_col.aaa, mixed_col.a); + finalColorAdd = vec4(mixed_col.rgb * mixed_col.a, 0.0); + /* Then we blend according to the texture mix factor. + * Note that we keep the alpha modulation. */ + finalColorMul.rgb *= mix_tex; + finalColorAdd.rgb *= 1.0 - mix_tex; +} +# endif + +void stroke_vertex() +{ + int m = int(ma1.x); + bool is_dot = false; + bool is_squares = false; + +# ifdef GP_MATERIAL_BUFFER_LEN + if (m != -1.0) { + is_dot = GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_ALIGNMENT); + is_squares = !GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_DOTS); + } +# endif + + /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */ + if (!is_dot && ma.x == -1.0 && ma2.x == -1.0) { + is_dot = true; + is_squares = false; + } + + /* Enpoints, we discard the vertices. */ + if (ma1.x == -1.0 || (!is_dot && ma2.x == -1.0)) { + discard_vert(); + return; + } + + mat4 model_mat = model_matrix_get(); + + /* Avoid using a vertex attrib for quad positioning. */ + float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */ + float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */ + + bool use_curr = is_dot || (x == -1.0); + + vec3 wpos_adj = transform_point(model_mat, (use_curr) ? pos.xyz : pos3.xyz); + vec3 wpos1 = transform_point(model_mat, pos1.xyz); + vec3 wpos2 = transform_point(model_mat, pos2.xyz); + + vec4 ndc_adj = point_world_to_ndc(wpos_adj); + vec4 ndc1 = point_world_to_ndc(wpos1); + vec4 ndc2 = point_world_to_ndc(wpos2); + + gl_Position = (use_curr) ? ndc1 : ndc2; + finalPos = (use_curr) ? wpos1 : wpos2; + + /* TODO case where ndc1 & ndc2 is behind camera */ + vec2 ss_adj = project_to_screenspace(ndc_adj); + vec2 ss1 = project_to_screenspace(ndc1); + vec2 ss2 = project_to_screenspace(ndc2); + /* Screenspace Lines tangents. */ + float line_len; + vec2 line = safe_normalize_len(ss2 - ss1, line_len); + vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2)); + + float thickness = abs((use_curr) ? thickness1 : thickness2); + thickness = stroke_thickness_modulate(thickness); + + finalUvs = vec2(x, y) * 0.5 + 0.5; + + if (is_dot) { +# ifdef GP_MATERIAL_BUFFER_LEN + int alignement = MATERIAL(m).flag & GP_STROKE_ALIGNMENT; +# endif + + vec2 x_axis; +# ifdef GP_MATERIAL_BUFFER_LEN + if (alignement == GP_STROKE_ALIGNMENT_STROKE) { + x_axis = (ma2.x == -1.0) ? line_adj : line; + } + else if (alignement == GP_STROKE_ALIGNMENT_FIXED) { + /* Default for no-material drawing. */ + x_axis = vec2(1.0, 0.0); + } + else +# endif + { /* GP_STROKE_ALIGNMENT_OBJECT */ + vec4 ndc_x = point_world_to_ndc(wpos1 + model_mat[0].xyz); + vec2 ss_x = project_to_screenspace(ndc_x); + x_axis = safe_normalize(ss_x - ss1); + } + + /* Rotation: Encoded as Cos + Sin sign. */ + float rot_sin = sqrt(1.0 - uv1.w * uv1.w) * sign(uv1.w); + float rot_cos = abs(uv1.w); + x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis; + + vec2 y_axis = rotate_90deg(x_axis); + + gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * thickness; + + strokePt1 = ss1; + strokePt2 = ss1 + vec2(0.5, 0.0); + strokeThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w); + } + else { + /* Mitter tangent vector. */ + vec2 miter_tan = safe_normalize(line_adj + line); + float miter_dot = dot(miter_tan, line_adj); + /* Break corners after a certain angle to avoid really thick corners. */ + const float miter_limit = 0.5; /* cos(60°) */ + bool miter_break = (miter_dot < miter_limit); + miter_tan = (miter_break) ? line : (miter_tan / miter_dot); + + vec2 miter = rotate_90deg(miter_tan); + + strokePt1.xy = ss1; + strokePt2.xy = ss2; + strokeThickness = thickness / gl_Position.w; + + /* Reminder: we packed the cap flag into the sign of stength and thickness sign. */ + bool is_stroke_start = (ma.x == -1.0 && x == -1.0 && strength1 > 0.0) || miter_break; + bool is_stroke_end = (ma3.x == -1.0 && x == 1.0 && thickness1 > 0.0) || miter_break; + + vec2 screen_ofs = miter * y; + + if (is_stroke_start || is_stroke_end) { + screen_ofs += line * x; + } + + gl_Position.xy += screen_ofs * sizeViewportInv.xy * thickness; + + finalUvs.x = (use_curr) ? uv1.z : uv2.z; +# ifdef GP_MATERIAL_BUFFER_LEN + finalUvs.x *= MATERIAL(m).stroke_u_scale; +# endif + } + +# ifdef GP_MATERIAL_BUFFER_LEN + vec4 vert_col = (use_curr) ? col1 : col2; + float vert_strength = abs((use_curr) ? strength1 : strength2); + vec4 stroke_col = MATERIAL(m).stroke_color; + float mix_tex = MATERIAL(m).stroke_texture_mix; + + color_output(stroke_col, vert_col, vert_strength, mix_tex); + + matFlag = MATERIAL(m).flag & ~GP_FILL_FLAGS; +# endif + + if (strokeOrder3d) { + /* Use the fragment depth (see fragment shader). */ + depth = -1.0; + } +# ifdef GP_MATERIAL_BUFFER_LEN + else if (GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_OVERLAP)) { + /* Use the index of the point as depth. + * This means the stroke can overlap itself. */ + depth = (point_id1 + 1.0) * 0.0000002; + } +# endif + else { + /* Use the index of first point of the stroke as depth. + * We render using a greater depth test this means the stroke + * cannot overlap itself. + * We offset by one so that the fill can be overlapped by its stroke. + * The offset is ok since we pad the strokes data because of adjacency infos. */ + depth = (stroke_id1 + strokeIndexOffset + 1.0) * 0.0000002; + } +} + +void fill_vertex() +{ + mat4 model_mat = model_matrix_get(); + + vec3 wpos = transform_point(model_mat, pos1.xyz); + gl_Position = point_world_to_ndc(wpos); + finalPos = wpos; + +# ifdef GP_MATERIAL_BUFFER_LEN + int m = int(ma1.x); + + vec4 fill_col = MATERIAL(m).fill_color; + float mix_tex = MATERIAL(m).fill_texture_mix; + + /* Special case: We don't modulate alpha in gradient mode. */ + if (GP_FLAG_TEST(MATERIAL(m).flag, GP_FILL_GRADIENT_USE)) { + fill_col.a = 1.0; + } + + /* Decode fill opacity. */ + vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0)); + float fill_opacity = fcol1.a - (fcol_decode.a * 10); + fcol_decode.a /= 10000.0f; + + /* Apply opacity. */ + fill_col.a *= fill_opacity; + /* If factor is > 1 force opacity. */ + if (fill_opacity > 1.0) { + fill_col.a += fill_opacity - 1.0f; + } + + fill_col.a = clamp(fill_col.a, 0.0, 1.0); + + color_output(fill_col, fcol_decode, 1.0, mix_tex); + + matFlag = MATERIAL(m).flag & GP_FILL_FLAGS; + matFlag |= m << GP_MATID_SHIFT; + + vec2 loc = MATERIAL(m).fill_uv_offset.xy; + mat2x2 rot_scale = mat2x2(MATERIAL(m).fill_uv_rot_scale.xy, MATERIAL(m).fill_uv_rot_scale.zw); + finalUvs = rot_scale * uv1.xy + loc; +# endif + + strokeThickness = 1e18; + strokePt1 = strokePt2 = vec2(0.0); + + if (strokeOrder3d) { + /* Use the fragment depth (see fragment shader). */ + depth = -1.0; + /* We still offset the fills a little to avoid overlaps */ + gl_Position.z += 0.000002; + } + else { + /* Use the index of first point of the stroke as depth. */ + depth = (stroke_id1 + strokeIndexOffset) * 0.0000002; + } +} + +void gpencil_vertex() +{ + /* Trick to detect if a drawcall is stroke or fill. + * This does mean that we need to draw an empty stroke segment before starting + * to draw the real stroke segments. */ + bool is_fill = (gl_InstanceID == 0); + + if (!is_fill) { + stroke_vertex(); + } + else { + fill_vertex(); + } +} + +#endif diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_composite_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_composite_frag.glsl new file mode 100644 index 00000000000..bc283952322 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_composite_frag.glsl @@ -0,0 +1,41 @@ + +uniform sampler2D colorBuf; +uniform sampler2D revealBuf; +uniform bool doSrgb; + +in vec4 uvcoordsvar; + +/* Reminder: Blending func is fragRevealage * DST + fragColor .*/ +layout(location = 0, index = 0) out vec4 fragColor; +layout(location = 0, index = 1) out vec4 fragRevealage; + +/* TODO Remove. */ +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() +{ + /* Revealage, how much light passes through. */ + fragRevealage.rgb = textureLod(revealBuf, uvcoordsvar.xy, 0.0).rgb; + /* Average for alpha channel. */ + fragRevealage.a = clamp(dot(fragRevealage.rgb, vec3(0.333334)), 0.0, 1.0); + /* Color buf is already premultiplied. Just add it to the color. */ + fragColor.rgb = textureLod(colorBuf, uvcoordsvar.xy, 0.0).rgb; + /* Add the alpha. */ + fragColor.a = 1.0 - fragRevealage.a; + + if (doSrgb) { + /* Temporary srgb conversion. + * TODO do color management / tonemapping here. */ + fragColor.r = linearrgb_to_srgb(fragColor.r); + fragColor.g = linearrgb_to_srgb(fragColor.g); + fragColor.b = linearrgb_to_srgb(fragColor.b); + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl new file mode 100644 index 00000000000..71597197bd8 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl @@ -0,0 +1,17 @@ + +uniform sampler2D depthBuf; +uniform float strokeDepth2d; +uniform bool strokeOrder3d; + +noperspective in vec4 uvcoordsvar; + +void main() +{ + float depth = textureLod(depthBuf, uvcoordsvar.xy, 0).r; + if (strokeOrder3d) { + gl_FragDepth = depth; + } + else { + gl_FragDepth = (depth != 0.0) ? gl_FragCoord.z : 1.0; + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl new file mode 100644 index 00000000000..1e5a900f486 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl @@ -0,0 +1,14 @@ + +uniform vec4 gpModelMatrix[4]; + +noperspective out vec4 uvcoordsvar; + +void main() +{ + mat4 model_matrix = mat4(gpModelMatrix[0], gpModelMatrix[1], gpModelMatrix[2], gpModelMatrix[3]); + int v = gl_VertexID % 3; + float x = -1.0 + float((v & 1) << 2); + float y = -1.0 + float((v & 2) << 1); + gl_Position = ViewProjectionMatrix * (model_matrix * vec4(x, y, 0.0, 1.0)); + uvcoordsvar = vec4((gl_Position.xy / gl_Position.w + 1.0) * 0.5, 0.0, 0.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 deleted file mode 100644 index 6a2a4f68dc9..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index e0634a7d1a7..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl +++ /dev/null @@ -1,53 +0,0 @@ -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; -} - -/* get zdepth value */ -float getZdepth(vec4 point) -{ - return min(-0.05, (point.z / point.w)); -} - -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, getZdepth(P0), 1.0); - EmitVertex(); - - mTexCoord = vec2(0, 0); - mColor = finalColor[0]; - gl_Position = vec4(vec2(sp0.x - size, sp0.y - size) / Viewport, getZdepth(P0), 1.0); - EmitVertex(); - - mTexCoord = vec2(1, 1); - mColor = finalColor[0]; - gl_Position = vec4(vec2(sp0.x + size, sp0.y + size) / Viewport, getZdepth(P0), 1.0); - EmitVertex(); - - mTexCoord = vec2(1, 0); - mColor = finalColor[0]; - gl_Position = vec4(vec2(sp0.x + size, sp0.y - size) / Viewport, getZdepth(P0), 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 deleted file mode 100644 index f75322f90e2..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl +++ /dev/null @@ -1,16 +0,0 @@ - -uniform mat4 gpModelMatrix; - -in vec3 pos; -in vec4 color; -in float size; - -out vec4 finalColor; -out float finalThickness; - -void main() -{ - gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); - 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 deleted file mode 100644 index 8285541e0b4..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl +++ /dev/null @@ -1,234 +0,0 @@ -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 int drawmode; -uniform float layer_opacity; - -uniform sampler2D myTexture; -uniform bool myTexturePremultiplied; -uniform int texture_clamp; - -uniform int viewport_xray; -uniform int shading_type[2]; -uniform vec4 wire_color; - -uniform int fade_layer; -uniform float fade_layer_factor; -uniform bool fade_ob; -uniform vec3 fade_color; -uniform float fade_ob_factor; - -/* keep this list synchronized with list in gpencil_draw_utils.c */ -#define SOLID 0 -#define GRADIENT 1 -#define RADIAL 2 -#define CHECKER 3 -#define TEXTURE 4 -#define PATTERN 5 - -#define GP_XRAY_FRONT 0 -#define GP_XRAY_3DSPACE 1 - -#define GP_DRAWMODE_2D 0 -#define GP_DRAWMODE_3D 1 - -#define OB_WIRE 2 -#define OB_SOLID 3 - -#define V3D_SHADING_MATERIAL_COLOR 0 -#define V3D_SHADING_TEXTURE_COLOR 3 -#define V3D_SHADING_VERTEX_COLOR 5 - -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); - } - } - ocolor.a *= layer_opacity; -} - -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) ? - texture_read_as_srgb( - myTexture, myTexturePremultiplied, rot_tex * texture_scale) : - texture_read_as_srgb( - myTexture, myTexturePremultiplied, 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 checker_color; - - /* wireframe with x-ray discard */ - if ((viewport_xray == 1) && (shading_type[0] == OB_WIRE)) { - discard; - } - - /* 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); - } - /* Checkerboard */ - if (fill_type == CHECKER) { - 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)) { - checker_color = (texture_flip == 0) ? finalColor : color2; - } - else { - checker_color = (texture_flip == 0) ? color2 : finalColor; - } - /* mix with texture */ - fragColor = (texture_mix == 1) ? mix(checker_color, text_color, mix_factor) : checker_color; - fragColor.a *= layer_opacity; - } - /* texture */ - if (fill_type == TEXTURE) { - fragColor = (texture_mix == 1) ? mix(text_color, finalColor, mix_factor) : text_color; - fragColor.a *= layer_opacity; - } - /* pattern */ - if (fill_type == PATTERN) { - fragColor = finalColor; - fragColor.a = min(text_color.a, finalColor.a) * layer_opacity; - } - } - - /* set zdepth */ - if (xraymode == GP_XRAY_FRONT) { - gl_FragDepth = min(-0.05, (gl_FragCoord.z / gl_FragCoord.w)); - } - else if (xraymode == GP_XRAY_3DSPACE) { - /* if 3D mode, move slightly the fill to avoid z-fighting between stroke and fill on same - * stroke */ - if (drawmode == GP_DRAWMODE_3D) { - gl_FragDepth = gl_FragCoord.z * 1.0001; - } - else { - gl_FragDepth = gl_FragCoord.z; - } - } - else { - gl_FragDepth = 0.000001; - } - - /* if wireframe override colors */ - if (shading_type[0] == OB_WIRE) { - fragColor = wire_color; - } - - /* for solid override color */ - if (shading_type[0] == OB_SOLID) { - if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) && - (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) && - (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) { - fragColor = wire_color; - } - if (viewport_xray == 1) { - fragColor.a *= 0.5; - } - } - /* Apply paper opacity */ - if (fade_layer == 1) { - /* Layer is below, mix with background. */ - fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor); - } - else if (fade_layer == 2) { - /* Layer is above, change opacity. */ - fragColor.a *= fade_layer_factor; - } - else if (fade_ob == true) { - fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor); - } -} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl deleted file mode 100644 index 263dc570423..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl +++ /dev/null @@ -1,16 +0,0 @@ - -uniform mat4 gpModelMatrix; - -in vec3 pos; -in vec4 color; -in vec2 texCoord; - -out vec4 finalColor; -out vec2 texCoord_interp; - -void main(void) -{ - gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); - finalColor = color; - texCoord_interp = texCoord; -} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl new file mode 100644 index 00000000000..bca922ec018 --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl @@ -0,0 +1,117 @@ + +uniform sampler2D gpFillTexture; +uniform sampler2D gpStrokeTexture; +uniform sampler2D gpSceneDepthTexture; +uniform vec3 gpNormal; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 revealColor; + +float length_squared(vec2 v) +{ + return dot(v, v); +} +float length_squared(vec3 v) +{ + return dot(v, v); +} + +vec3 gpencil_lighting(void) +{ + vec3 light_accum = vec3(0.0); + for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) { + if (lights[i].color_type.x == -1.0) { + break; + } + vec3 L = lights[i].position.xyz - finalPos; + float vis = 1.0; + /* Spot Attenuation. */ + if (lights[i].color_type.w == GP_LIGHT_TYPE_SPOT) { + mat3 rot_scale = mat3(lights[i].right.xyz, lights[i].up.xyz, lights[i].forward.xyz); + vec3 local_L = rot_scale * L; + local_L /= abs(local_L.z); + float ellipse = inversesqrt(length_squared(local_L)); + vis *= smoothstep(0.0, 1.0, (ellipse - lights[i].spot_size) / lights[i].spot_blend); + /* Also mask +Z cone. */ + vis *= step(0.0, local_L.z); + } + /* Inverse square decay. Skip for suns. */ + float L_len_sqr = length_squared(L); + if (lights[i].color_type.w < GP_LIGHT_TYPE_SUN) { + vis /= L_len_sqr; + } + else { + L = lights[i].forward.xyz; + L_len_sqr = 1.0; + } + /* Lambertian falloff */ + if (lights[i].color_type.w != GP_LIGHT_TYPE_AMBIENT) { + L /= sqrt(L_len_sqr); + vis *= clamp(dot(gpNormal, L), 0.0, 1.0); + } + light_accum += vis * lights[i].color_type.rgb; + } + /* Clamp to avoid NaNs. */ + return clamp(light_accum, 0.0, 1e10); +} + +void main() +{ + vec4 col; + if (GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_USE)) { + bool premul = GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_PREMUL); + col = texture_read_as_linearrgb(gpStrokeTexture, premul, finalUvs); + } + else if (GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_USE)) { + bool use_clip = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_CLIP); + vec2 uvs = (use_clip) ? clamp(finalUvs, 0.0, 1.0) : finalUvs; + bool premul = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_PREMUL); + col = texture_read_as_linearrgb(gpFillTexture, premul, uvs); + } + else if (GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_USE)) { + bool radial = GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_RADIAL); + float fac = clamp(radial ? length(finalUvs * 2.0 - 1.0) : finalUvs.x, 0.0, 1.0); + int matid = matFlag >> GP_MATID_SHIFT; + col = mix(MATERIAL(matid).fill_color, MATERIAL(matid).fill_mix_color, fac); + } + else /* SOLID */ { + col = vec4(1.0); + } + col.rgb *= col.a; + + /* Composite all other colors on top of texture color. + * Everything is premult by col.a to have the stencil effect. */ + fragColor = col * finalColorMul + col.a * finalColorAdd; + + fragColor.rgb *= gpencil_lighting(); + + fragColor *= stroke_round_cap_mask(strokePt1, strokePt2, strokeThickness); + + /* For compatibility with colored alpha buffer. + * Note that we are limited to mono-chromatic alpha blending here + * because of the blend equation and the limit of 1 color target + * when using custom color blending. */ + revealColor = vec4(0.0, 0.0, 0.0, fragColor.a); + + if (fragColor.a < 0.001) { + discard; + } + + /* Manual depth test */ + vec2 uvs = gl_FragCoord.xy / vec2(textureSize(gpSceneDepthTexture, 0).xy); + float scene_depth = texture(gpSceneDepthTexture, uvs).r; + if (gl_FragCoord.z > scene_depth) { + discard; + } + + /* We override the fragment depth using the fragment shader to ensure a constant value. + * This has a cost as the depth test cannot happen early. + * We could do this in the vertex shader but then perspective interpolation of uvs and + * fragment clipping gets really complicated. */ + if (depth >= 0.0) { + gl_FragDepth = depth; + } + else { + gl_FragDepth = gl_FragCoord.z; + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl new file mode 100644 index 00000000000..a43f69bee6a --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl @@ -0,0 +1,27 @@ + +uniform sampler2D colorBuf; +uniform sampler2D revealBuf; +uniform int blendMode; +uniform float blendOpacity; + +in vec4 uvcoordsvar; + +/* Reminder: This is considered SRC color in blend equations. + * Same operation on all buffers. */ +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 fragRevealage; + +void main() +{ + vec4 color; + + /* Remember, this is associated alpha (aka. premult). */ + color.rgb = textureLod(colorBuf, uvcoordsvar.xy, 0).rgb; + /* Stroke only render mono-chromatic revealage. We convert to alpha. */ + color.a = 1.0 - textureLod(revealBuf, uvcoordsvar.xy, 0).r; + + fragColor = vec4(1.0, 0.0, 1.0, 1.0); + fragRevealage = vec4(1.0, 0.0, 1.0, 1.0); + + blend_mode_output(blendMode, color, blendOpacity, fragColor, fragRevealage); +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_layer_mask_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_mask_frag.glsl new file mode 100644 index 00000000000..64899b147dc --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_mask_frag.glsl @@ -0,0 +1,37 @@ + +uniform sampler2D colorBuf; +uniform sampler2D revealBuf; +uniform sampler2D maskBuf; +uniform float maskOpacity; +uniform bool maskInvert; +uniform bool isFirstPass; + +in vec4 uvcoordsvar; + +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 fragRevealage; + +void main() +{ + vec3 masked_color = texture(colorBuf, uvcoordsvar.xy).rgb; + vec3 masked_reveal = texture(revealBuf, uvcoordsvar.xy).rgb; + float mask = texture(maskBuf, uvcoordsvar.xy).r; + + if (maskInvert) { + mask = 1.0 - mask; + } + + mask = 1.0 - mask * maskOpacity; + + if (isFirstPass) { + /* Blend mode is multiply. */ + fragColor.rgb = fragRevealage.rgb = mix(vec3(1.0), masked_reveal, mask); + fragColor.a = fragRevealage.a = 1.0; + } + else { + /* Blend mode is additive. */ + fragRevealage = vec4(0.0); + fragColor.rgb = mix(vec3(0.0), masked_color, mask); + fragColor.a = 0.0; + } +} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl deleted file mode 100644 index 1d1cd6349dc..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl +++ /dev/null @@ -1,9 +0,0 @@ -uniform vec3 color; -uniform float opacity; - -out vec4 FragColor; - -void main() -{ - FragColor = vec4(color, 1.0 - 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 deleted file mode 100644 index d79b8fb4d8a..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl +++ /dev/null @@ -1,126 +0,0 @@ -uniform int color_type; -uniform int mode; -uniform sampler2D myTexture; -uniform bool myTexturePremultiplied; - -uniform float gradient_f; -uniform vec2 gradient_s; - -uniform vec4 colormix; -uniform float mix_stroke_factor; -uniform int shading_type[2]; - -in vec4 mColor; -in vec2 mTexCoord; -out vec4 fragColor; - -uniform int fade_layer; -uniform float fade_layer_factor; -uniform bool fade_ob; -uniform vec3 fade_color; -uniform float fade_ob_factor; - -#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 - -#define OB_SOLID 3 -#define V3D_SHADING_TEXTURE_COLOR 3 - -bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR); - -/* Function to check the point inside ellipse */ -float check_ellipse_point(vec2 pt, vec2 radius) -{ - float p = (pow(pt.x, 2) / pow(radius.x, 2)) + (pow(pt.y, 2) / pow(radius.y, 2)); - - return p; -} - -/* Function to check the point inside box */ -vec2 check_box_point(vec2 pt, vec2 radius) -{ - vec2 rtn; - rtn.x = abs(pt.x) / radius.x; - rtn.y = abs(pt.y) / radius.y; - - return rtn; -} - -void main() -{ - vec2 centered = mTexCoord - vec2(0.5); - float ellip = check_ellipse_point(centered, vec2(gradient_s / 2.0)); - vec2 box; - - if (mode != GPENCIL_MODE_BOX) { - if (ellip > 1.0) { - discard; - } - } - else { - box = check_box_point(centered, vec2(gradient_s / 2.0)); - if ((box.x > 1.0) || (box.y > 1.0)) { - discard; - } - } - - /* Solid */ - if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) { - fragColor = mColor; - } - /* texture */ - if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) { - vec4 text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord); - if (mix_stroke_factor > 0.0) { - fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor); - fragColor.a = text_color.a; - } - else { - fragColor = text_color; - } - - /* 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) && (!no_texture)) { - vec4 text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, 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); - } - - if (gradient_f < 1.0) { - float dist = length(centered) * 2.0; - float decay = dist * (1.0 - gradient_f) * fragColor.a; - fragColor.a = clamp(fragColor.a - decay, 0.0, 1.0); - if (mode == GPENCIL_MODE_DOTS) { - fragColor.a = fragColor.a * (1.0 - ellip); - } - } - - if (fragColor.a < 0.0035) { - discard; - } - - /* Apply paper opacity */ - if (fade_layer == 1) { - /* Layer is below, mix with background. */ - fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor); - } - else if (fade_layer == 2) { - /* Layer is above, change opacity. */ - fragColor.a *= fade_layer_factor; - } - else if (fade_ob == true) { - fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor); - } -} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl deleted file mode 100644 index a2f4c1f9b15..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl +++ /dev/null @@ -1,142 +0,0 @@ -uniform vec2 Viewport; -uniform int xraymode; -uniform int alignment_mode; - -layout(points) in; -layout(triangle_strip, max_vertices = 4) out; - -in vec4 finalColor[1]; -in float finalThickness[1]; -in vec2 finaluvdata[1]; -in vec4 finalprev_pos[1]; - -out vec4 mColor; -out vec2 mTexCoord; - -#define GP_XRAY_FRONT 0 -#define GP_XRAY_3DSPACE 1 - -#define M_PI 3.14159265358979323846 /* pi */ -#define M_2PI 6.28318530717958647692 /* 2*pi */ -#define FALSE 0 - -/* keep this definition equals to GP_STYLE_FOLLOW_FIXED value */ -#define FIXED 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 min(-0.05, (point.z / point.w)); - } - if (xraymode == GP_XRAY_3DSPACE) { - return (point.z / point.w); - } - - /* in front by default */ - return 0.000001; -} - -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); -} - -vec2 rotatePoint(vec2 center, vec2 point, float angle) -{ - /* translate center of rotation to the center */ - vec2 new_point = point - center; - vec2 rot_point; - rot_point.x = new_point.x * cos(angle) - new_point.y * sin(angle); - rot_point.y = new_point.y * cos(angle) + new_point.x * sin(angle); - return rot_point + center; -} - -/* Calculate angle of the stroke using previous point as reference. - * The angle is calculated using the x axis (1, 0) as 0 degrees */ -float getAngle(vec2 pt0, vec2 pt1) -{ - /* do not rotate one point only (no reference to rotate) */ - if (pt0 == pt1) { - return 0.0; - } - - if (alignment_mode == FIXED) { - return 0.0; - } - - /* default horizontal line (x-axis) in screen space */ - vec2 v0 = vec2(1.0, 0.0); - - /* vector of direction */ - vec2 vn = vec2(normalize(pt1 - pt0)); - - /* angle signed (function ported from angle_signed_v2v2) */ - float perp_dot = (v0[1] * vn[0]) - (v0[0] * vn[1]); - float angle = atan(perp_dot, dot(v0, vn)); - - /* get full circle rotation */ - if (angle > 0.0) { - angle = M_PI + (M_PI - angle); - } - else { - angle *= -1.0; - } - - return angle; -} - -void main(void) -{ - /* receive points */ - vec4 P0 = gl_in[0].gl_Position; - vec2 sp0 = toScreenSpace(P0); - - vec4 P1 = finalprev_pos[0]; - vec2 sp1 = toScreenSpace(P1); - vec2 point; - - float size = finalThickness[0]; - vec2 center = vec2(sp0.x, sp0.y); - - /* get angle of stroke to rotate texture */ - float angle = getAngle(sp0, sp1); - - /* generate the triangle strip */ - mTexCoord = rotateUV(vec2(0, 1), finaluvdata[0].y); - mColor = finalColor[0]; - point = rotatePoint(center, vec2(sp0.x - size, sp0.y + size), angle); - gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0); - EmitVertex(); - - mTexCoord = rotateUV(vec2(0, 0), finaluvdata[0].y); - mColor = finalColor[0]; - point = rotatePoint(center, vec2(sp0.x - size, sp0.y - size), angle); - gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0); - EmitVertex(); - - mTexCoord = rotateUV(vec2(1, 1), finaluvdata[0].y); - mColor = finalColor[0]; - point = rotatePoint(center, vec2(sp0.x + size, sp0.y + size), angle); - gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0); - EmitVertex(); - - mTexCoord = rotateUV(vec2(1, 0), finaluvdata[0].y); - mColor = finalColor[0]; - point = rotatePoint(center, vec2(sp0.x + size, sp0.y - size), angle); - gl_Position = vec4(point / 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 deleted file mode 100644 index 33d7d714231..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl +++ /dev/null @@ -1,66 +0,0 @@ - -uniform float pixsize; /* rv3d->pixsize */ -uniform int keep_size; -uniform float objscale; -uniform float pixfactor; -uniform int viewport_xray; -uniform int shading_type[2]; -uniform vec4 wire_color; -uniform mat4 gpModelMatrix; - -in vec3 pos; -in vec4 color; -in float thickness; -in vec2 uvdata; -in vec3 prev_pos; - -out vec4 finalColor; -out float finalThickness; -out vec2 finaluvdata; -out vec4 finalprev_pos; - -#define TRUE 1 - -#define OB_WIRE 2 -#define OB_SOLID 3 - -#define V3D_SHADING_MATERIAL_COLOR 0 -#define V3D_SHADING_TEXTURE_COLOR 3 -#define V3D_SHADING_VERTEX_COLOR 5 - -float defaultpixsize = pixsize * (1000.0 / pixfactor); - -void main() -{ - gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); - finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz); - 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, 0.5); /* set a minimum size */ - } - - /* for wireframe override size and color */ - if (shading_type[0] == OB_WIRE) { - finalThickness = 2.0; - finalColor = wire_color; - } - /* for solid override color */ - if (shading_type[0] == OB_SOLID) { - if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) && - (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) && - (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) { - finalColor = wire_color; - } - if (viewport_xray == 1) { - finalColor.a *= 0.5; - } - } - - 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 deleted file mode 100644 index 2f4429a858f..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index 5e3cc105081..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl +++ /dev/null @@ -1,107 +0,0 @@ -uniform int color_type; -uniform sampler2D myTexture; -uniform bool myTexturePremultiplied; - -uniform float gradient_f; - -uniform vec4 colormix; -uniform float mix_stroke_factor; -uniform int shading_type[2]; - -uniform int fade_layer; -uniform float fade_layer_factor; -uniform bool fade_ob; -uniform vec3 fade_color; -uniform float fade_ob_factor; - -in vec4 mColor; -in vec2 mTexCoord; -in vec2 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 - -#define ENDCAP 1.0 - -#define OB_SOLID 3 -#define V3D_SHADING_TEXTURE_COLOR 3 - -bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR); - -void main() -{ - - vec4 tColor = vec4(mColor); - /* if uvfac[1] == 1, then encap */ - if (uvfac[1] == ENDCAP) { - vec2 center = vec2(uvfac[0], 0.5); - float dist = length(mTexCoord - center); - if (dist > 0.50) { - discard; - } - } - - if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) { - fragColor = tColor; - } - - /* texture for endcaps */ - vec4 text_color; - if (uvfac[1] == ENDCAP) { - text_color = texture_read_as_srgb( - myTexture, myTexturePremultiplied, vec2(mTexCoord.x, mTexCoord.y)); - } - else { - text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord); - } - - /* texture */ - if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) { - if (mix_stroke_factor > 0.0) { - fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor); - fragColor.a = text_color.a; - } - else { - fragColor = text_color; - } - - /* mult both alpha factor to use strength factor */ - fragColor.a = min(fragColor.a * tColor.a, fragColor.a); - } - /* pattern */ - if ((color_type == GPENCIL_COLOR_PATTERN) && (!no_texture)) { - fragColor = tColor; - /* mult both alpha factor to use strength factor with color alpha limit */ - fragColor.a = min(text_color.a * tColor.a, tColor.a); - } - - /* gradient */ - if (gradient_f < 1.0) { - float dist = abs(mTexCoord.y - 0.5) * 2.0; - float decay = dist * (1.0 - gradient_f) * fragColor.a; - fragColor.a = clamp(fragColor.a - decay, 0.0, 1.0); - } - - if (fragColor.a < 0.0035) { - discard; - } - - /* Apply paper opacity */ - if (fade_layer == 1) { - /* Layer is below, mix with background. */ - fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor); - } - else if (fade_layer == 2) { - /* Layer is above, change opacity. */ - fragColor.a *= fade_layer_factor; - } - else if (fade_ob == true) { - fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor); - } -} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl deleted file mode 100644 index 3300514dd13..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl +++ /dev/null @@ -1,264 +0,0 @@ -uniform vec2 Viewport; -uniform int xraymode; -uniform int color_type; -uniform int caps_mode[2]; - -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 vec2 uvfac; - -#define GP_XRAY_FRONT 0 -#define GP_XRAY_3DSPACE 1 - -/* 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 - -#define GPENCIL_FLATCAP 1 - -/* 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 min(-0.05, (point.z / point.w)); - } - if (xraymode == GP_XRAY_3DSPACE) { - return (point.z / point.w); - } - - /* in front by default */ - return 0.000001; -} - -/* check equality but with a small tolerance */ -bool is_equal(vec4 p1, vec4 p2) -{ - float limit = 0.0001; - float x = abs(p1.x - p2.x); - float y = abs(p1.y - p2.y); - float z = abs(p1.z - p2.z); - - if ((x < limit) && (y < limit) && (z < limit)) { - return true; - } - - return false; -} - -void main(void) -{ - float MiterLimit = 0.75; - uvfac = vec2(0.0, 0.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; - } - - /* culling behind camera */ - if (P1.w < 0 || P2.w < 0) { - 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 */ - if ((caps_mode[0] != GPENCIL_FLATCAP) && is_equal(P0, P2)) { - vec4 cap_color = finalColor[1]; - - mTexCoord = vec2(2.0, 0.5); - mColor = cap_color; - vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0; - uvfac = vec2(0.0, 1.0); - gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0); - EmitVertex(); - - mTexCoord = vec2(0.0, -0.5); - mColor = cap_color; - uvfac = vec2(0.0, 1.0); - gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); - EmitVertex(); - - mTexCoord = vec2(0.0, 1.5); - mColor = cap_color; - uvfac = vec2(0.0, 1.0); - gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0); - EmitVertex(); - } - - float y_a = 0.0; - float y_b = 1.0; - - /* invert uv (vertical) */ - if (finaluvdata[2].x > 1.0) { - if ((finaluvdata[1].y != 0.0) && (finaluvdata[2].y != 0.0)) { - float d = ceil(finaluvdata[2].x) - 1.0; - if (floor(d / 2.0) == (d / 2.0)) { - y_a = 1.0; - y_b = 0.0; - } - } - } - /* generate the triangle strip */ - uvfac = vec2(0.0, 0.0); - mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 0) : vec2(finaluvdata[1].x, y_a); - 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, y_b); - 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, y_a); - 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, y_b); - mColor = finalColor[2]; - gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0); - EmitVertex(); - - /* generate the end endcap */ - if ((caps_mode[1] != GPENCIL_FLATCAP) && is_equal(P1, P3) && (finaluvdata[2].x > 0)) { - vec4 cap_color = finalColor[2]; - - mTexCoord = vec2(finaluvdata[2].x, 1.5); - mColor = cap_color; - uvfac = vec2(finaluvdata[2].x, 1.0); - gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); - EmitVertex(); - - mTexCoord = vec2(finaluvdata[2].x, -0.5); - mColor = cap_color; - uvfac = vec2(finaluvdata[2].x, 1.0); - gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); - EmitVertex(); - - mTexCoord = vec2(finaluvdata[2].x + 2, 0.5); - mColor = cap_color; - uvfac = vec2(finaluvdata[2].x, 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/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl deleted file mode 100644 index 8df08f0bf68..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl +++ /dev/null @@ -1,63 +0,0 @@ - -uniform float pixsize; /* rv3d->pixsize */ -uniform int keep_size; -uniform float objscale; -uniform float pixfactor; -uniform int viewport_xray; -uniform int shading_type[2]; -uniform vec4 wire_color; -uniform mat4 gpModelMatrix; - -in vec3 pos; -in vec4 color; -in float thickness; -in vec2 uvdata; - -out vec4 finalColor; -out float finalThickness; -out vec2 finaluvdata; - -#define TRUE 1 - -#define OB_WIRE 2 -#define OB_SOLID 3 - -#define V3D_SHADING_MATERIAL_COLOR 0 -#define V3D_SHADING_TEXTURE_COLOR 3 -#define V3D_SHADING_VERTEX_COLOR 5 - -float defaultpixsize = pixsize * (1000.0 / pixfactor); - -void main(void) -{ - gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz); - 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); - } - - /* for wireframe override size and color */ - if (shading_type[0] == OB_WIRE) { - finalThickness = 1.0; - finalColor = wire_color; - } - /* for solid override color */ - if (shading_type[0] == OB_SOLID) { - if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) && - (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) && - (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) { - finalColor = wire_color; - } - if (viewport_xray == 1) { - finalColor.a *= 0.5; - } - } - - finaluvdata = uvdata; -} diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl new file mode 100644 index 00000000000..c6cfee5ef2d --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl @@ -0,0 +1,5 @@ + +void main() +{ + gpencil_vertex(); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl new file mode 100644 index 00000000000..860dae08dde --- /dev/null +++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl @@ -0,0 +1,339 @@ + +uniform sampler2D colorBuf; +uniform sampler2D revealBuf; + +in vec4 uvcoordsvar; + +/* Reminder: This is considered SRC color in blend equations. + * Same operation on all buffers. */ +layout(location = 0) out vec4 fragColor; +layout(location = 1) out vec4 fragRevealage; + +float gaussian_weight(float x) +{ + return exp(-x * x / (2.0 * 0.35 * 0.35)); +} + +#if defined(COMPOSITE) + +uniform bool isFirstPass; + +void main() +{ + if (isFirstPass) { + /* Blend mode is multiply. */ + fragColor.rgb = fragRevealage.rgb = texture(revealBuf, uvcoordsvar.xy).rgb; + fragColor.a = fragRevealage.a = 1.0; + } + else { + /* Blend mode is additive. */ + fragRevealage = vec4(0.0); + fragColor.rgb = texture(colorBuf, uvcoordsvar.xy).rgb; + fragColor.a = 0.0; + } +} + +#elif defined(COLORIZE) + +uniform vec3 lowColor; +uniform vec3 highColor; +uniform float factor; +uniform int mode; + +const mat3 sepia_mat = mat3( + vec3(0.393, 0.349, 0.272), vec3(0.769, 0.686, 0.534), vec3(0.189, 0.168, 0.131)); + +# define MODE_GRAYSCALE 0 +# define MODE_SEPIA 1 +# define MODE_DUOTONE 2 +# define MODE_CUSTOM 3 +# define MODE_TRANSPARENT 4 + +void main() +{ + fragColor = texture(colorBuf, uvcoordsvar.xy); + fragRevealage = texture(revealBuf, uvcoordsvar.xy); + + float luma = dot(fragColor.rgb, vec3(0.2126, 0.7152, 0.723)); + + /* No blending. */ + switch (mode) { + case MODE_GRAYSCALE: + fragColor.rgb = mix(fragColor.rgb, vec3(luma), factor); + break; + case MODE_SEPIA: + fragColor.rgb = mix(fragColor.rgb, sepia_mat * fragColor.rgb, factor); + break; + case MODE_DUOTONE: + fragColor.rgb = luma * ((luma <= factor) ? lowColor : highColor); + break; + case MODE_CUSTOM: + fragColor.rgb = mix(fragColor.rgb, luma * lowColor, factor); + break; + case MODE_TRANSPARENT: + default: + fragColor.rgb *= factor; + fragRevealage.rgb = mix(vec3(1.0), fragRevealage.rgb, factor); + break; + } +} + +#elif defined(BLUR) + +uniform vec2 offset; +uniform int sampCount; + +void main() +{ + vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy); + vec2 ofs = offset * pixel_size; + + fragColor = vec4(0.0); + fragRevealage = vec4(0.0); + + /* No blending. */ + float weight_accum = 0.0; + for (int i = -sampCount; i <= sampCount; i++) { + float x = float(i) / float(sampCount); + float weight = gaussian_weight(x); + weight_accum += weight; + vec2 uv = uvcoordsvar.xy + ofs * x; + fragColor.rgb += texture(colorBuf, uv).rgb * weight; + fragRevealage.rgb += texture(revealBuf, uv).rgb * weight; + } + + fragColor /= weight_accum; + fragRevealage /= weight_accum; +} + +#elif defined(TRANSFORM) + +uniform vec2 axisFlip = vec2(1.0); +uniform vec2 waveDir = vec2(0.0); +uniform vec2 waveOffset = vec2(0.0); +uniform float wavePhase = 0.0; +uniform vec2 swirlCenter = vec2(0.0); +uniform float swirlAngle = 0.0; +uniform float swirlRadius = 0.0; + +void main() +{ + vec2 uv = (uvcoordsvar.xy - 0.5) * axisFlip + 0.5; + + /* Wave deform. */ + float wave_time = dot(uv, waveDir.xy); + uv += sin(wave_time + wavePhase) * waveOffset; + /* Swirl deform. */ + if (swirlRadius > 0.0) { + vec2 tex_size = vec2(textureSize(colorBuf, 0).xy); + vec2 pix_coord = uv * tex_size - swirlCenter; + float dist = length(pix_coord); + float percent = clamp((swirlRadius - dist) / swirlRadius, 0.0, 1.0); + float theta = percent * percent * swirlAngle; + float s = sin(theta); + float c = cos(theta); + mat2 rot = mat2(vec2(c, -s), vec2(s, c)); + uv = (rot * pix_coord + swirlCenter) / tex_size; + } + + fragColor = texture(colorBuf, uv); + fragRevealage = texture(revealBuf, uv); +} + +#elif defined(GLOW) + +uniform vec3 glowColor; +uniform vec2 offset; +uniform int sampCount; +uniform vec3 threshold; +uniform bool useAlphaMode; + +void main() +{ + vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy); + vec2 ofs = offset * pixel_size; + + fragColor = vec4(0.0); + + /* In first pass we copy the reveal buffer. This let us do the alpha under if needed. */ + fragRevealage = texture(revealBuf, uvcoordsvar.xy); + + float weight_accum = 0.0; + for (int i = -sampCount; i <= sampCount; i++) { + float x = float(i) / float(sampCount); + float weight = gaussian_weight(x); + weight_accum += weight; + vec2 uv = uvcoordsvar.xy + ofs * x; + vec3 col = texture(colorBuf, uv).rgb; + if (threshold.x > -1.0) { + if (threshold.y > -1.0) { + if (all(lessThan(abs(col - threshold), vec3(0.05)))) { + weight = 0.0; + } + } + else { + if (dot(col, vec3(1.0 / 3.0)) < threshold.x) { + weight = 0.0; + } + } + } + fragColor.rgb += col * weight; + } + + fragColor *= glowColor.rgbb / weight_accum; + + if (useAlphaMode) { + /* Equivalent to alpha under. */ + fragColor *= fragRevealage; + } + + if (threshold.x == -1.0) { + /* Blend Mode is additive in 2nd pass. Don't modify revealage. */ + fragRevealage = vec4(0.0); + } +} + +#elif defined(RIM) + +uniform vec2 blurDir; +uniform vec2 uvOffset; +uniform vec3 rimColor; +uniform vec3 maskColor; +uniform int sampCount; +uniform int blendMode; +uniform bool isFirstPass; + +void main() +{ + /* Blur revealage buffer. */ + fragRevealage = vec4(0.0); + float weight_accum = 0.0; + for (int i = -sampCount; i <= sampCount; i++) { + float x = float(i) / float(sampCount); + float weight = gaussian_weight(x); + weight_accum += weight; + vec2 uv = uvcoordsvar.xy + blurDir * x + uvOffset; + vec3 col = texture(revealBuf, uv).rgb; + if (any(not(equal(vec2(0.0), floor(uv))))) { + col = vec3(0.0); + } + fragRevealage.rgb += col * weight; + } + fragRevealage /= weight_accum; + + if (isFirstPass) { + /* In first pass we copy the reveal buffer. This let us do alpha masking in second pass. */ + fragColor = texture(revealBuf, uvcoordsvar.xy); + /* Also add the masked color to the reveal buffer. */ + vec3 col = texture(colorBuf, uvcoordsvar.xy).rgb; + if (all(lessThan(abs(col - maskColor), vec3(0.05)))) { + fragColor = vec4(1.0); + } + } + else { + /* Premult by foreground alpha (alpha mask). */ + float mask = 1.0 - clamp(dot(vec3(0.333334), texture(colorBuf, uvcoordsvar.xy).rgb), 0.0, 1.0); + + /* fragRevealage is blurred shadow. */ + float rim = clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0); + + vec4 color = vec4(rimColor, 1.0); + + blend_mode_output(blendMode, color, rim * mask, fragColor, fragRevealage); + } +} + +#elif defined(SHADOW) + +uniform vec4 shadowColor; +uniform vec2 uvRotX; +uniform vec2 uvRotY; +uniform vec2 uvOffset; +uniform vec2 blurDir; +uniform vec2 waveDir; +uniform vec2 waveOffset; +uniform float wavePhase; +uniform int sampCount; +uniform bool isFirstPass; + +vec2 compute_uvs(float x) +{ + vec2 uv = uvcoordsvar.xy; + /* Tranform UV (loc, rot, scale) */ + uv = uv.x * uvRotX + uv.y * uvRotY + uvOffset; + uv += blurDir * x; + /* Wave deform. */ + float wave_time = dot(uv, waveDir.xy); + uv += sin(wave_time + wavePhase) * waveOffset; + return uv; +} + +void main() +{ + /* Blur revealage buffer. */ + fragRevealage = vec4(0.0); + float weight_accum = 0.0; + for (int i = -sampCount; i <= sampCount; i++) { + float x = float(i) / float(sampCount); + float weight = gaussian_weight(x); + weight_accum += weight; + vec2 uv = compute_uvs(x); + vec3 col = texture(revealBuf, uv).rgb; + if (any(not(equal(vec2(0.0), floor(uv))))) { + col = vec3(1.0); + } + fragRevealage.rgb += col * weight; + } + fragRevealage /= weight_accum; + + /* No blending in first pass, alpha over premult in second pass. */ + if (isFirstPass) { + /* In first pass we copy the reveal buffer. This let us do alpha under in second pass. */ + fragColor = texture(revealBuf, uvcoordsvar.xy); + } + else { + /* fragRevealage is blurred shadow. */ + float shadow_fac = 1.0 - clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0); + /* Premult by foreground revealage (alpha under). */ + vec3 original_revealage = texture(colorBuf, uvcoordsvar.xy).rgb; + shadow_fac *= clamp(dot(vec3(0.333334), original_revealage), 0.0, 1.0); + /* Modulate by opacity */ + shadow_fac *= shadowColor.a; + /* Apply shadow color. */ + fragColor.rgb = mix(vec3(0.0), shadowColor.rgb, shadow_fac); + /* Alpha over (mask behind the shadow). */ + fragColor.a = shadow_fac; + + fragRevealage.rgb = original_revealage * (1.0 - shadow_fac); + /* Replace the whole revealage buffer. */ + fragRevealage.a = 1.0; + } +} + +#elif defined(PIXELIZE) + +uniform vec2 targetPixelSize; +uniform vec2 targetPixelOffset; +uniform vec2 accumOffset; +uniform int sampCount; + +void main() +{ + vec2 pixel = floor((uvcoordsvar.xy - targetPixelOffset) / targetPixelSize); + vec2 uv = (pixel + 0.5) * targetPixelSize + targetPixelOffset; + + fragColor = vec4(0.0); + fragRevealage = vec4(0.0); + + for (int i = -sampCount; i <= sampCount; i++) { + float x = float(i) / float(sampCount + 1); + vec2 uv_ofs = uv + accumOffset * 0.5 * x; + fragColor += texture(colorBuf, uv_ofs); + fragRevealage += texture(revealBuf, uv_ofs); + } + + fragColor /= float(sampCount) * 2.0 + 1.0; + fragRevealage /= float(sampCount) * 2.0 + 1.0; +} + +#endif
\ No newline at end of file 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 deleted file mode 100644 index be645548402..00000000000 --- a/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl +++ /dev/null @@ -1,74 +0,0 @@ -in vec4 uvcoordsvar; - -out vec4 FragColor; - -uniform sampler2D strokeColor; -uniform sampler2D strokeDepth; -uniform int tonemapping; -uniform vec4 select_color; -uniform int do_select; - -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; - } -} - -bool check_borders(ivec2 uv, int size) -{ - for (int x = -size; x <= size; x++) { - for (int y = -size; y <= size; y++) { - vec4 stroke_color = texelFetch(strokeColor, ivec2(uv.x + x, uv.y + y), 0).rgba; - if (stroke_color.a > 0) { - return true; - } - } - } - - return false; -} - -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 = clamp(stroke_color, 0.0, 1.0); - gl_FragDepth = clamp(stroke_depth, 0.0, 1.0); - - if (do_select == 1) { - if (stroke_color.a == 0) { - if (check_borders(uv, 2)) { - FragColor = select_color; - gl_FragDepth = 0.000001; - } - } - } -} diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index fb3efd710ba..9f84978deb6 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -25,6 +25,8 @@ #include "DRW_engine.h" #include "DRW_render.h" +#include "DEG_depsgraph_query.h" + #include "ED_view3d.h" #include "BKE_object.h" @@ -78,6 +80,7 @@ static void OVERLAY_engine_init(void *vedata) pd->xray_enabled = XRAY_ACTIVE(v3d); pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE; pd->clear_in_front = (v3d->shading.type != OB_SOLID); + pd->cfra = DEG_get_ctime(draw_ctx->depsgraph); OVERLAY_antialiasing_init(vedata); @@ -132,12 +135,14 @@ static void OVERLAY_cache_init(void *vedata) case CTX_MODE_SCULPT: OVERLAY_sculpt_cache_init(vedata); break; - case CTX_MODE_OBJECT: - case CTX_MODE_PAINT_GPENCIL: case CTX_MODE_EDIT_GPENCIL: + case CTX_MODE_PAINT_GPENCIL: case CTX_MODE_SCULPT_GPENCIL: - case CTX_MODE_WEIGHT_GPENCIL: case CTX_MODE_VERTEX_GPENCIL: + case CTX_MODE_WEIGHT_GPENCIL: + OVERLAY_edit_gpencil_cache_init(vedata); + break; + case CTX_MODE_OBJECT: break; default: BLI_assert(!"Draw mode invalid"); @@ -147,6 +152,7 @@ static void OVERLAY_cache_init(void *vedata) OVERLAY_armature_cache_init(vedata); OVERLAY_extra_cache_init(vedata); OVERLAY_facing_cache_init(vedata); + OVERLAY_gpencil_cache_init(vedata); OVERLAY_grid_cache_init(vedata); OVERLAY_image_cache_init(vedata); OVERLAY_metaball_cache_init(vedata); @@ -215,8 +221,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) const bool in_paint_mode = (ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT); const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL); - const bool has_surface = ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT); - const bool draw_surface = !((ob->dt < OB_WIRE) || (!renderable && (ob->dt != OB_WIRE))); + const bool has_surface = ELEM( + ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT, OB_GPENCIL); + const bool draw_surface = (ob->dt >= OB_WIRE) && (renderable || (ob->dt == OB_WIRE)); const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION); const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0; const bool draw_wires = draw_surface && has_surface && @@ -413,6 +420,7 @@ static void OVERLAY_draw_scene(void *vedata) OVERLAY_armature_draw(vedata); OVERLAY_particle_draw(vedata); OVERLAY_metaball_draw(vedata); + OVERLAY_gpencil_draw(vedata); OVERLAY_extra_draw(vedata); if (DRW_state_is_fbo()) { @@ -474,6 +482,13 @@ static void OVERLAY_draw_scene(void *vedata) case CTX_MODE_SCULPT: OVERLAY_sculpt_draw(vedata); break; + case CTX_MODE_EDIT_GPENCIL: + case CTX_MODE_PAINT_GPENCIL: + case CTX_MODE_SCULPT_GPENCIL: + case CTX_MODE_VERTEX_GPENCIL: + case CTX_MODE_WEIGHT_GPENCIL: + OVERLAY_edit_gpencil_draw(vedata); + break; default: break; } diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c index 688ecaf3946..489667a6c8f 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.c +++ b/source/blender/draw/engines/overlay/overlay_extra.c @@ -38,7 +38,7 @@ #include "DNA_camera_types.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_curve_types.h" #include "DNA_lightprobe_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" @@ -1328,87 +1328,6 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb, /** \} */ /* -------------------------------------------------------------------- */ -/** \name GPencil. - * \{ */ - -static void OVERLAY_gpencil_color_names(Object *ob) -{ - if (ob->mode != OB_MODE_EDIT_GPENCIL) { - return; - } - - bGPdata *gpd = (bGPdata *)ob->data; - if (gpd == NULL) { - return; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - ViewLayer *view_layer = draw_ctx->view_layer; - int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); - uchar color[4]; - UI_GetThemeColor4ubv(theme_id, color); - struct DRWTextStore *dt = DRW_text_cache_ensure(); - - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->flag & GP_LAYER_HIDE) { - continue; - } - bGPDframe *gpf = gpl->actframe; - if (gpf == NULL) { - continue; - } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1); - if (ma == NULL) { - continue; - } - - MaterialGPencilStyle *gp_style = ma->gp_style; - /* skip stroke if it doesn't have any valid data */ - if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) { - continue; - } - /* check if the color is visible */ - if (gp_style->flag & GP_STYLE_COLOR_HIDE) { - continue; - } - - /* only if selected */ - if (gps->flag & GP_STROKE_SELECT) { - float fpt[3]; - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - if (pt->flag & GP_SPOINT_SELECT) { - mul_v3_m4v3(fpt, ob->obmat, &pt->x); - DRW_text_cache_add(dt, - fpt, - ma->id.name + 2, - strlen(ma->id.name + 2), - 10, - 0, - DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, - color); - break; - } - } - } - } - } -} - -void OVERLAY_gpencil_cache_populate(OVERLAY_Data *UNUSED(vedata), Object *ob) -{ - /* don't show object extras in set's */ - if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { - if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) { - OVERLAY_gpencil_color_names(ob); - } - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Volumetric / Smoke sim * \{ */ diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c new file mode 100644 index 00000000000..c96c448c63b --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_gpencil.c @@ -0,0 +1,391 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BKE_gpencil.h" + +#include "UI_resources.h" + +#include "DNA_gpencil_types.h" + +#include "DEG_depsgraph_query.h" + +#include "ED_view3d.h" + +#include "overlay_private.h" + +#include "draw_common.h" +#include "draw_manager_text.h" + +void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = vedata->stl->pd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + /* Default: Display nothing. */ + pd->edit_gpencil_points_grp = NULL; + pd->edit_gpencil_wires_grp = NULL; + psl->edit_gpencil_ps = NULL; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + + if (gpd == NULL || ob->type != OB_GPENCIL) { + return; + } + + /* For sculpt show only if mask mode, and only points if not stroke mode. */ + const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) && + GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt)); + const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) && + (ts->gpencil_selectmode_sculpt & + (GP_SCULPT_MASK_SELECTMODE_POINT | + GP_SCULPT_MASK_SELECTMODE_SEGMENT))); + + /* For vertex paint show only if mask mode, and only points if not stroke mode. */ + bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) && + GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)); + const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) && + (ts->gpencil_selectmode_vertex & + (GP_VERTEX_MASK_SELECTMODE_POINT | + GP_VERTEX_MASK_SELECTMODE_SEGMENT))); + + /* If Sculpt or Vertex mode and the mask is disabled, the select must be hidden. */ + const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) || + (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask)); + + const bool do_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + const bool show_multi_edit_lines = (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0; + + const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) || show_multi_edit_lines; + + const bool hide_lines = !GPENCIL_EDIT_MODE(gpd) && !GPENCIL_WEIGHT_MODE(gpd) && + !use_sculpt_mask && !use_vertex_mask && !show_lines; + + /* Special case when vertex paint and multiedit lines. */ + if (do_multiedit && show_multi_edit_lines && GPENCIL_VERTEX_MODE(gpd)) { + use_vertex_mask = true; + } + + const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); + + /* Show Edit points if: + * Edit mode: Not in Stroke selection mode + * Sculpt mode: If use Mask and not Stroke mode + * Weight mode: Always + * Vertex mode: If use Mask and not Stroke mode + */ + const bool show_points = show_sculpt_points || is_weight_paint || show_vertex_points || + (GPENCIL_EDIT_MODE(gpd) && + (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE)); + + if ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state); + + if (show_lines && !hide_lines) { + sh = OVERLAY_shader_edit_gpencil_wire(); + pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines); + DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); + DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select); + DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); + } + + if (show_points && !hide_select) { + sh = OVERLAY_shader_edit_gpencil_point(); + pd->edit_gpencil_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", do_multiedit); + DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint); + DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity); + DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp); + } + } + + /* control points for primitives and speed guide */ + const bool is_cppoint = (gpd->runtime.tot_cp_points > 0); + const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide && + (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL)); + const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) && + ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0)); + + if ((is_cppoint || is_speed_guide) && (is_show_gizmo)) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->edit_gpencil_gizmos_ps, state); + + sh = OVERLAY_shader_edit_gpencil_guide_point(); + grp = DRW_shgroup_create(sh, psl->edit_gpencil_gizmos_ps); + + if (gpd->runtime.cp_points != NULL) { + for (int i = 0; i < gpd->runtime.tot_cp_points; i++) { + bGPDcontrolpoint *cp = &gpd->runtime.cp_points[i]; + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", &cp->x); + DRW_shgroup_uniform_float_copy(grp, "pSize", cp->size * 0.8f * G_draw.block.sizePixel); + DRW_shgroup_uniform_vec4_copy(grp, "pColor", cp->color); + DRW_shgroup_call_procedural_points(grp, NULL, 1); + } + } + + if (ts->gp_sculpt.guide.use_guide) { + float color[4]; + if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) { + UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.location); + } + else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT && + ts->gp_sculpt.guide.reference_object != NULL) { + UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.reference_object->loc); + } + else { + UI_GetThemeColor4fv(TH_REDALERT, color); + DRW_shgroup_uniform_vec3_copy(grp, "pPosition", scene->cursor.location); + } + DRW_shgroup_uniform_vec4_copy(grp, "pColor", color); + DRW_shgroup_uniform_float_copy(grp, "pSize", 8.0f * G_draw.block.sizePixel); + DRW_shgroup_call_procedural_points(grp, NULL, 1); + } + } +} + +void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + struct GPUShader *sh; + DRWShadingGroup *grp; + + /* Default: Display nothing. */ + psl->gpencil_canvas_ps = NULL; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + Object *ob = draw_ctx->obact; + bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL; + Scene *scene = draw_ctx->scene; + ToolSettings *ts = scene->toolsettings; + const View3DCursor *cursor = &scene->cursor; + + if (gpd == NULL || ob->type != OB_GPENCIL) { + return; + } + + const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; + const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0; + + if (show_grid && show_overlays) { + const char *grid_unit = NULL; + float mat[4][4]; + float col_grid[4]; + float size[2]; + + /* set color */ + copy_v3_v3(col_grid, gpd->grid.color); + col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f); + + copy_m4_m4(mat, ob->obmat); + + float viewinv[4][4]; + /* Set the grid in the selected axis */ + switch (ts->gp_sculpt.lock_axis) { + case GP_LOCKAXIS_X: + swap_v4_v4(mat[0], mat[2]); + break; + case GP_LOCKAXIS_Y: + swap_v4_v4(mat[1], mat[2]); + break; + case GP_LOCKAXIS_Z: + /* Default. */ + break; + case GP_LOCKAXIS_CURSOR: + loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, (float[3]){1, 1, 1}); + break; + case GP_LOCKAXIS_VIEW: + /* view aligned */ + DRW_view_viewmat_get(NULL, viewinv, true); + copy_v3_v3(mat[0], viewinv[0]); + copy_v3_v3(mat[1], viewinv[1]); + break; + } + + translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f); + mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit)); + rescale_m4(mat, (float[3]){size[0], size[1], 0.0f}); + + const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines; + int line_ct = gridlines * 4 + 2; + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA; + DRW_PASS_CREATE(psl->gpencil_canvas_ps, state); + + sh = OVERLAY_shader_gpencil_canvas(); + grp = DRW_shgroup_create(sh, psl->gpencil_canvas_ps); + DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_vec4_copy(grp, "color", col_grid); + DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]); + DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]); + DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]); + DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2); + DRW_shgroup_call_procedural_lines(grp, NULL, line_ct); + } +} + +static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_PrivateData *pd = vedata->stl->pd; + bGPdata *gpd = (bGPdata *)ob->data; + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + + if (pd->edit_gpencil_wires_grp) { + DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp); + DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color); + + struct GPUBatch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra); + DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob); + } + + if (pd->edit_gpencil_points_grp) { + const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0; + + DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp); + DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction); + + struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra); + DRW_shgroup_call_no_cull(grp, geom, ob); + } +} + +static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + Object *ob = (Object *)thunk; + Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1); + if (ma == NULL) { + return; + } + MaterialGPencilStyle *gp_style = ma->gp_style; + /* skip stroke if it doesn't have any valid data */ + if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) { + return; + } + /* check if the color is visible */ + if (gp_style->flag & GP_MATERIAL_HIDE) { + return; + } + /* only if selected */ + if (gps->flag & GP_STROKE_SELECT) { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + /* Draw name at the first selected point. */ + if (pt->flag & GP_SPOINT_SELECT) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + uchar color[4]; + UI_GetThemeColor4ubv(theme_id, color); + + float fpt[3]; + mul_v3_m4v3(fpt, ob->obmat, &pt->x); + + struct DRWTextStore *dt = DRW_text_cache_ensure(); + DRW_text_cache_add(dt, + fpt, + ma->id.name + 2, + strlen(ma->id.name + 2), + 10, + 0, + DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR, + color); + break; + } + } + } +} + +static void OVERLAY_gpencil_color_names(Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + int cfra = DEG_get_ctime(draw_ctx->depsgraph); + + BKE_gpencil_visible_stroke_iter( + ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra); +} + +void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + View3D *v3d = draw_ctx->v3d; + + bGPdata *gpd = (bGPdata *)ob->data; + if (gpd == NULL) { + return; + } + + if (GPENCIL_ANY_MODE(gpd)) { + OVERLAY_edit_gpencil_cache_populate(vedata, ob); + } + + /* don't show object extras in set's */ + if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) { + if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL) && + DRW_state_show_text()) { + OVERLAY_gpencil_color_names(ob); + } + } +} + +void OVERLAY_gpencil_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->gpencil_canvas_ps) { + DRW_draw_pass(psl->gpencil_canvas_ps); + } +} + +void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + + if (psl->edit_gpencil_gizmos_ps) { + DRW_draw_pass(psl->edit_gpencil_gizmos_ps); + } + + if (psl->edit_gpencil_ps) { + DRW_draw_pass(psl->edit_gpencil_ps); + } +} diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c index a532618d472..f9c7df75e9a 100644 --- a/source/blender/draw/engines/overlay/overlay_motion_path.c +++ b/source/blender/draw/engines/overlay/overlay_motion_path.c @@ -155,7 +155,7 @@ static void motion_path_cache(OVERLAY_Data *vedata, DRW_shgroup_uniform_bool_copy(grp, "selected", selected); DRW_shgroup_uniform_vec3_copy(grp, "customColor", color); /* Only draw the required range. */ - DRW_shgroup_call_range(grp, mpath_batch_line_get(mpath), start_index, len); + DRW_shgroup_call_range(grp, NULL, mpath_batch_line_get(mpath), start_index, len); } /* Draw points. */ @@ -167,7 +167,7 @@ static void motion_path_cache(OVERLAY_Data *vedata, DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes); DRW_shgroup_uniform_vec3_copy(grp, "customColor", color); /* Only draw the required range. */ - DRW_shgroup_call_range(grp, mpath_batch_points_get(mpath), start_index, len); + DRW_shgroup_call_range(grp, NULL, mpath_batch_points_get(mpath), start_index, len); } /* Draw frame numbers at each frame-step value. */ diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index 63738b3c214..e77a0a143a9 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -23,13 +23,67 @@ #include "DRW_render.h" #include "BKE_global.h" +#include "BKE_gpencil.h" -#include "DNA_lightprobe_types.h" +#include "BKE_object.h" + +#include "DNA_gpencil_types.h" #include "UI_resources.h" #include "overlay_private.h" +/* Returns the normal plane in ndc space. */ +static void gpencil_depth_plane(Object *ob, float r_plane[4]) +{ + /* TODO put that into private data. */ + float viewinv[4][4]; + DRW_view_viewmat_get(NULL, viewinv, true); + float *camera_z_axis = viewinv[2]; + float *camera_pos = viewinv[3]; + + /* Find the normal most likely to represent the gpObject. */ + /* TODO: This does not work quite well if you use + * strokes not aligned with the object axes. Maybe we could try to + * compute the minimum axis of all strokes. But this would be more + * computationaly heavy and should go into the GPData evaluation. */ + BoundBox *bbox = BKE_object_boundbox_get(ob); + /* Convert bbox to matrix */ + float mat[4][4], size[3], center[3]; + BKE_boundbox_calc_size_aabb(bbox, size); + BKE_boundbox_calc_center_aabb(bbox, center); + unit_m4(mat); + copy_v3_v3(mat[3], center); + /* Avoid division by 0.0 later. */ + add_v3_fl(size, 1e-8f); + rescale_m4(mat, size); + /* BBox space to World. */ + mul_m4_m4m4(mat, ob->obmat, mat); + /* BBox center in world space. */ + copy_v3_v3(center, mat[3]); + /* View Vector. */ + if (DRW_view_is_persp_get(NULL)) { + /* BBox center to camera vector. */ + sub_v3_v3v3(r_plane, camera_pos, mat[3]); + } + else { + copy_v3_v3(r_plane, camera_z_axis); + } + /* World to BBox space. */ + invert_m4(mat); + /* Normalize the vector in BBox space. */ + mul_mat3_m4_v3(mat, r_plane); + normalize_v3(r_plane); + + transpose_m4(mat); + /* mat is now a "normal" matrix which will transform + * BBox space normal to world space. */ + mul_mat3_m4_v3(mat, r_plane); + normalize_v3(r_plane); + + plane_from_point_normal_v3(r_plane, center, r_plane); +} + void OVERLAY_outline_init(OVERLAY_Data *vedata) { OVERLAY_FramebufferList *fbl = vedata->fbl; @@ -79,6 +133,11 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps); DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); + + GPUShader *sh_gpencil = OVERLAY_shader_outline_prepass_gpencil(); + + pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps); + DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); } /* outlines_prepass_ps is still needed for selection of probes. */ @@ -107,6 +166,98 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata) } } +typedef struct iterData { + Object *ob; + DRWShadingGroup *stroke_grp; + DRWShadingGroup *fill_grp; + int cfra; + float plane[4]; +} iterData; + +static void gp_layer_cache_populate(bGPDlayer *gpl, + bGPDframe *UNUSED(gpf), + bGPDstroke *UNUSED(gps), + void *thunk) +{ + iterData *iter = (iterData *)thunk; + bGPdata *gpd = (bGPdata *)iter->ob->data; + + const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0; + const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D); + + float object_scale = mat4_to_scale(iter->ob->obmat); + /* Negate thickness sign to tag that strokes are in screen space. + * Convert to world units (by default, 1 meter = 2000 px). */ + float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f); + + DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp); + DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", is_stroke_order_3d); + DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get()); + DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get()); + DRW_shgroup_uniform_float_copy(grp, "thicknessScale", object_scale); + DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change); + DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale); + DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane); +} + +static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + iterData *iter = (iterData *)thunk; + + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1); + + bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0; + bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0; + // TODO: What about simplify Fill? + bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0; + + if (hide_material) { + return; + } + + if (show_fill) { + struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra); + int vfirst = gps->runtime.fill_start * 3; + int vcount = gps->tot_triangles * 3; + DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount); + } + + if (show_stroke) { + struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra); + /* Start one vert before to have gl_InstanceID > 0 (see shader). */ + int vfirst = gps->runtime.stroke_start - 1; + /* Include "potential" cyclic vertex and start adj vertex (see shader). */ + int vcount = gps->totpoints + 1 + 1; + DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount); + } +} + +static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob) +{ + /* No outlines in edit mode. */ + bGPdata *gpd = (bGPdata *)ob->data; + if (gpd && GPENCIL_ANY_MODE(gpd)) { + return; + } + + iterData iter = { + .ob = ob, + .stroke_grp = pd->outlines_gpencil_grp, + .fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp), + .cfra = pd->cfra, + }; + + if (gpd->draw_mode == GP_DRAWMODE_2D) { + gpencil_depth_plane(ob, iter.plane); + } + + BKE_gpencil_visible_stroke_iter( + ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra); +} + void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, Object *ob, OVERLAY_DupliData *dupli, @@ -123,6 +274,11 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, return; } + if (ob->type == OB_GPENCIL) { + OVERLAY_outline_gpencil(pd, ob); + return; + } + if (dupli && !init_dupli) { geom = dupli->outline_geom; shgroup = dupli->outline_shgrp; diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index f8eeeed42ef..55b59e24a5b 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -57,6 +57,8 @@ typedef struct OVERLAY_PassList { DRWPass *armature_transp_ps; DRWPass *edit_curve_wire_ps[2]; DRWPass *edit_curve_handle_ps; + DRWPass *edit_gpencil_ps; + DRWPass *edit_gpencil_gizmos_ps; DRWPass *edit_lattice_ps; DRWPass *edit_mesh_depth_ps[2]; DRWPass *edit_mesh_verts_ps[2]; @@ -73,6 +75,7 @@ typedef struct OVERLAY_PassList { DRWPass *extra_blend_ps; DRWPass *extra_centers_ps; DRWPass *extra_grid_ps; + DRWPass *gpencil_canvas_ps; DRWPass *facing_ps; DRWPass *grid_ps; DRWPass *image_background_under_ps; @@ -216,6 +219,8 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *edit_curve_points_grp; DRWShadingGroup *edit_lattice_points_grp; DRWShadingGroup *edit_lattice_wires_grp; + DRWShadingGroup *edit_gpencil_points_grp; + DRWShadingGroup *edit_gpencil_wires_grp; DRWShadingGroup *edit_mesh_depth_grp[2]; DRWShadingGroup *edit_mesh_faces_grp[2]; DRWShadingGroup *edit_mesh_faces_cage_grp[2]; @@ -235,6 +240,7 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *motion_path_lines_grp; DRWShadingGroup *motion_path_points_grp; DRWShadingGroup *outlines_grp; + DRWShadingGroup *outlines_gpencil_grp; DRWShadingGroup *paint_surf_grp; DRWShadingGroup *paint_wire_grp; DRWShadingGroup *paint_wire_selected_grp; @@ -273,6 +279,7 @@ typedef struct OVERLAY_PrivateData { bool xray_enabled_and_not_wire; short v3d_flag; /* TODO move to View3DOverlay */ short v3d_gridflag; /* TODO move to View3DOverlay */ + int cfra; DRWState clipping_state; OVERLAY_ShadingData shdata; @@ -411,6 +418,12 @@ void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata); +void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata); +void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata); +void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_gpencil_draw(OVERLAY_Data *vedata); +void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata); + void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata); void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob); @@ -438,7 +451,6 @@ void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata); void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob); -void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob); @@ -536,6 +548,9 @@ GPUShader *OVERLAY_shader_depth_only(void); GPUShader *OVERLAY_shader_edit_curve_handle(void); GPUShader *OVERLAY_shader_edit_curve_point(void); GPUShader *OVERLAY_shader_edit_curve_wire(void); +GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void); +GPUShader *OVERLAY_shader_edit_gpencil_point(void); +GPUShader *OVERLAY_shader_edit_gpencil_wire(void); GPUShader *OVERLAY_shader_edit_lattice_point(void); GPUShader *OVERLAY_shader_edit_lattice_wire(void); GPUShader *OVERLAY_shader_edit_mesh_analysis(void); @@ -553,12 +568,14 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object); GPUShader *OVERLAY_shader_extra_loose_point(void); GPUShader *OVERLAY_shader_extra_point(void); GPUShader *OVERLAY_shader_facing(void); +GPUShader *OVERLAY_shader_gpencil_canvas(void); GPUShader *OVERLAY_shader_grid(void); GPUShader *OVERLAY_shader_image(void); GPUShader *OVERLAY_shader_motion_path_line(void); GPUShader *OVERLAY_shader_motion_path_vert(void); GPUShader *OVERLAY_shader_uniform_color(void); GPUShader *OVERLAY_shader_outline_prepass(bool use_wire); +GPUShader *OVERLAY_shader_outline_prepass_gpencil(void); GPUShader *OVERLAY_shader_extra_grid(void); GPUShader *OVERLAY_shader_outline_detect(void); GPUShader *OVERLAY_shader_paint_face(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index 7bd3cf4a067..450fbc5d8bb 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -52,6 +52,9 @@ extern char datatoc_edit_curve_handle_geom_glsl[]; extern char datatoc_edit_curve_handle_vert_glsl[]; extern char datatoc_edit_curve_point_vert_glsl[]; extern char datatoc_edit_curve_wire_vert_glsl[]; +extern char datatoc_edit_gpencil_canvas_vert_glsl[]; +extern char datatoc_edit_gpencil_guide_vert_glsl[]; +extern char datatoc_edit_gpencil_vert_glsl[]; extern char datatoc_edit_lattice_point_vert_glsl[]; extern char datatoc_edit_lattice_wire_vert_glsl[]; extern char datatoc_edit_mesh_common_lib_glsl[]; @@ -110,6 +113,8 @@ extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[]; extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; +extern char datatoc_gpencil_common_lib_glsl[]; + extern char datatoc_common_colormanagement_lib_glsl[]; extern char datatoc_common_fullscreen_vert_glsl[]; extern char datatoc_common_fxaa_lib_glsl[]; @@ -133,6 +138,9 @@ typedef struct OVERLAY_Shaders { GPUShader *edit_curve_handle; GPUShader *edit_curve_point; GPUShader *edit_curve_wire; + GPUShader *edit_gpencil_guide_point; + GPUShader *edit_gpencil_point; + GPUShader *edit_gpencil_wire; GPUShader *edit_lattice_point; GPUShader *edit_lattice_wire; GPUShader *edit_mesh_vert; @@ -154,11 +162,13 @@ typedef struct OVERLAY_Shaders { GPUShader *extra_lightprobe_grid; GPUShader *extra_loose_point; GPUShader *facing; + GPUShader *gpencil_canvas; GPUShader *grid; GPUShader *image; GPUShader *motion_path_line; GPUShader *motion_path_vert; GPUShader *outline_prepass; + GPUShader *outline_prepass_gpencil; GPUShader *outline_prepass_wire; GPUShader *outline_detect; GPUShader *paint_face; @@ -526,6 +536,58 @@ GPUShader *OVERLAY_shader_edit_curve_wire(void) return sh_data->edit_curve_wire; } +GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_gpencil_guide_point) { + sh_data->edit_gpencil_guide_point = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_guide_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL}, + }); + } + return sh_data->edit_gpencil_guide_point; +} + +GPUShader *OVERLAY_shader_edit_gpencil_point(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->edit_gpencil_point) { + sh_data->edit_gpencil_point = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define USE_POINTS\n", NULL}, + }); + } + return sh_data->edit_gpencil_point; +} + +GPUShader *OVERLAY_shader_edit_gpencil_wire(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->edit_gpencil_wire) { + sh_data->edit_gpencil_wire = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); + } + return sh_data->edit_gpencil_wire; +} + GPUShader *OVERLAY_shader_edit_lattice_point(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -852,6 +914,21 @@ GPUShader *OVERLAY_shader_facing(void) return sh_data->facing; } +GPUShader *OVERLAY_shader_gpencil_canvas(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->gpencil_canvas) { + sh_data->gpencil_canvas = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_globals_lib_glsl, + datatoc_common_view_lib_glsl, + datatoc_edit_gpencil_canvas_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL}, + }); + } + return sh_data->gpencil_canvas; +} + GPUShader *OVERLAY_shader_grid(void) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; @@ -967,6 +1044,32 @@ GPUShader *OVERLAY_shader_outline_prepass(bool use_wire) return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass; } +GPUShader *OVERLAY_shader_outline_prepass_gpencil(void) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; + OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; + if (!sh_data->outline_prepass_gpencil) { + sh_data->outline_prepass_gpencil = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_gpencil_common_lib_glsl, + datatoc_gpu_shader_common_obinfos_lib_glsl, + datatoc_outline_prepass_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_gpencil_common_lib_glsl, + datatoc_outline_prepass_frag_glsl, + NULL}, + .defs = (const char *[]){sh_cfg->def, + "#define USE_GPENCIL\n", + "#define UNIFORM_RESOURCE_ID\n", + NULL}, + }); + } + return sh_data->outline_prepass_gpencil; +} + GPUShader *OVERLAY_shader_outline_detect(void) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index e39f51aa606..6ae9f19dab6 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -186,7 +186,11 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, shgrp = pd->wires_grp[is_xray][use_coloring]; } - if (use_sculpt_pbvh) { + if (ob->type == OB_GPENCIL) { + /* TODO (fclem) Make GPencil objects have correct boundbox. */ + DRW_shgroup_call_no_cull(shgrp, geom, ob); + } + else if (use_sculpt_pbvh) { DRW_shgroup_call_sculpt(shgrp, ob, true, false, false); } else { diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl new file mode 100644 index 00000000000..5aa7fe78e4e --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl @@ -0,0 +1,35 @@ + +uniform vec4 color; +uniform vec3 xAxis; +uniform vec3 yAxis; +uniform vec3 origin; +uniform int halfLineCount; + +flat out vec4 finalColor; +flat out vec2 edgeStart; +noperspective out vec2 edgePos; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec2 pos; + pos.x = float(gl_VertexID % 2); + pos.y = float(gl_VertexID / 2) / float(halfLineCount - 1); + + if (pos.y > 1.0) { + pos.xy = pos.yx; + pos.x -= 1.0 + 1.0 / float(halfLineCount - 1); + } + + pos -= 0.5; + + vec3 world_pos = xAxis * pos.x + yAxis * pos.y + origin; + + gl_Position = point_world_to_ndc(world_pos); + + finalColor = color; + + /* Convert to screen position [0..sizeVp]. */ + edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl new file mode 100644 index 00000000000..ef68b0f4e6f --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl @@ -0,0 +1,14 @@ +uniform vec4 pColor; +uniform float pSize; +uniform vec3 pPosition; + +out vec4 finalColor; + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + gl_Position = point_world_to_ndc(pPosition); + finalColor = pColor; + gl_PointSize = pSize; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl new file mode 100644 index 00000000000..cb03ad44615 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl @@ -0,0 +1,103 @@ + +uniform float normalSize; +uniform bool doMultiframe; +uniform bool doStrokeEndpoints; +uniform bool hideSelect; +uniform bool doWeightColor; +uniform float gpEditOpacity; +uniform vec4 gpEditColor; +uniform sampler1D weightTex; + +in vec3 pos; +in float ma; +in uint vflag; +in float weight; + +out vec4 finalColor; + +void discard_vert() +{ + /* We set the vertex at the camera origin to generate 0 fragments. */ + gl_Position = vec4(0.0, 0.0, -3e36, 0.0); +} + +#define GP_EDIT_POINT_SELECTED (1u << 0u) +#define GP_EDIT_STROKE_SELECTED (1u << 1u) +#define GP_EDIT_MULTIFRAME (1u << 2u) +#define GP_EDIT_STROKE_START (1u << 3u) +#define GP_EDIT_STROKE_END (1u << 4u) + +#ifdef USE_POINTS +# define colorUnselect colorGpencilVertex +# define colorSelect colorGpencilVertexSelect +#else +# define colorUnselect gpEditColor +# define colorSelect (hideSelect ? colorUnselect : colorGpencilVertexSelect) +#endif + +vec3 weight_to_rgb(float t) +{ + if (t < 0.0) { + /* No weight */ + return colorUnselect.rgb; + } + else if (t > 1.0) { + /* Error color */ + return vec3(1.0, 0.0, 1.0); + } + else { + return texture(weightTex, t).rgb; + } +} + +void main() +{ + GPU_INTEL_VERTEX_SHADER_WORKAROUND + + vec3 world_pos = point_object_to_world(pos); + gl_Position = point_world_to_ndc(world_pos); + + bool is_multiframe = (vflag & GP_EDIT_MULTIFRAME) != 0u; + bool is_stroke_sel = (vflag & GP_EDIT_STROKE_SELECTED) != 0u; + bool is_point_sel = (vflag & GP_EDIT_POINT_SELECTED) != 0u; + + if (doWeightColor) { + finalColor.rgb = weight_to_rgb(weight); + finalColor.a = gpEditOpacity; + } + else { + finalColor = (is_point_sel) ? colorSelect : colorUnselect; + finalColor.a *= gpEditOpacity; + } + +#ifdef USE_POINTS + gl_PointSize = sizeVertex * 2.0; + + if (doStrokeEndpoints && !doWeightColor) { + bool is_stroke_start = (vflag & GP_EDIT_STROKE_START) != 0u; + bool is_stroke_end = (vflag & GP_EDIT_STROKE_END) != 0u; + + if (is_stroke_start) { + gl_PointSize *= 2.0; + finalColor.rgb = vec3(0.0, 1.0, 0.0); + } + else if (is_stroke_end) { + gl_PointSize *= 1.5; + finalColor.rgb = vec3(1.0, 0.0, 0.0); + } + } + + if ((!is_stroke_sel && !doWeightColor) || (!doMultiframe && is_multiframe)) { + discard_vert(); + } +#endif + + /* Discard unwanted padding vertices. */ + if (ma == -1.0 || (is_multiframe && !doMultiframe)) { + discard_vert(); + } + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif +} diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl index f6e3724eb51..fdbce27b38d 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl @@ -1,10 +1,45 @@ +uniform vec4 gpDepthPlane; + flat in uint objectId; /* using uint because 16bit uint can contain more ids than int. */ out uint outId; +vec3 ray_plane_intersection(vec3 ray_ori, vec3 ray_dir, vec4 plane) +{ + float d = dot(plane.xyz, ray_dir); + vec3 plane_co = plane.xyz * (-plane.w / dot(plane.xyz, plane.xyz)); + vec3 h = ray_ori - plane_co; + float lambda = -dot(plane.xyz, h) / ((abs(d) < 1e-8) ? 1e-8 : d); + return ray_ori + ray_dir * lambda; +} + void main() { - outId = objectId; +#ifdef USE_GPENCIL + if (stroke_round_cap_mask(strokePt1, strokePt2, strokeThickness) < 0.001) { + discard; + } + + if (depth != -1.0) { + /* Stroke order 2D. */ + bool is_persp = ProjectionMatrix[3][3] == 0.0; + vec2 uvs = vec2(gl_FragCoord.xy) * sizeViewportInv; + vec3 pos_ndc = vec3(uvs, gl_FragCoord.z) * 2.0 - 1.0; + vec4 pos_world = ViewProjectionMatrixInverse * vec4(pos_ndc, 1.0); + vec3 pos = pos_world.xyz / pos_world.w; + + vec3 ray_ori = pos; + vec3 ray_dir = (is_persp) ? (ViewMatrixInverse[3].xyz - pos) : ViewMatrixInverse[2].xyz; + vec3 isect = ray_plane_intersection(ray_ori, ray_dir, gpDepthPlane); + vec4 ndc = point_world_to_ndc(isect); + gl_FragDepth = (ndc.z / ndc.w) * 0.5 + 0.5; + } + else { + gl_FragDepth = gl_FragCoord.z; + } +#endif + + outId = uint(objectId); } diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl index 984e55b0c46..a2021759196 100644 --- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl @@ -1,7 +1,9 @@ uniform bool isTransform; +#ifndef USE_GPENCIL in vec3 pos; +#endif #ifdef USE_GEOM out vec3 vPos; @@ -47,11 +49,19 @@ uint outline_colorid_get(void) void main() { +#ifdef USE_GPENCIL + gpencil_vertex(); +# ifdef USE_WORLD_CLIP_PLANES + vec3 world_pos = point_object_to_world(pos1.xyz); +# endif + +#else vec3 world_pos = point_object_to_world(pos); -#ifdef USE_GEOM + gl_Position = point_world_to_ndc(world_pos); +# ifdef USE_GEOM vPos = point_world_to_view(world_pos); +# endif #endif - gl_Position = point_world_to_ndc(world_pos); /* Small bias to always be on top of the geom. */ gl_Position.z -= 1e-3; diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl index 4d705a4ee2b..3acaa1fbcbc 100644 --- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl @@ -101,8 +101,10 @@ void wire_object_color_get(out vec3 rim_col, out vec3 wire_col) void main() { + bool no_attrib = all(equal(nor, vec3(0))); + vec3 wnor = no_attrib ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor)); + vec3 wpos = point_object_to_world(pos); - vec3 wnor = normalize(normal_object_to_world(nor)); bool is_persp = (ProjectionMatrix[3][3] == 0.0); vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz; @@ -144,7 +146,7 @@ void main() #endif /* Cull flat edges below threshold. */ - if (get_edge_sharpness(wd) < 0.0) { + if (!no_attrib && (get_edge_sharpness(wd) < 0.0)) { edgeStart = vec2(-1.0); } diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 899fbdc9b71..26f37b764be 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -117,6 +117,60 @@ static bool workbench_render_framebuffers_init(void) return ok; } +static void workbench_render_result_z(struct RenderLayer *rl, + const char *viewname, + const rcti *rect) +{ + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + if ((view_layer->passflag & SCE_PASS_Z) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); + + GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_read_depth(dfbl->default_fb, + rect->xmin, + rect->ymin, + BLI_rcti_size_x(rect), + BLI_rcti_size_y(rect), + rp->rect); + + float winmat[4][4]; + DRW_view_winmat_get(NULL, winmat, false); + + int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); + + /* Convert ogl depth [0..1] to view Z [near..far] */ + if (DRW_view_is_persp_get(NULL)) { + for (int i = 0; i < pix_ct; i++) { + if (rp->rect[i] == 1.0f) { + rp->rect[i] = 1e10f; /* Background */ + } + else { + rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; + rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]); + } + } + } + else { + /* Keep in mind, near and far distance are negatives. */ + float near = DRW_view_near_distance_get(NULL); + float far = DRW_view_far_distance_get(NULL); + float range = fabsf(far - near); + + for (int i = 0; i < pix_ct; i++) { + if (rp->rect[i] == 1.0f) { + rp->rect[i] = 1e10f; /* Background */ + } + else { + rp->rect[i] = -rp->rect[i] * range + near; + } + } + } + } +} + static void workbench_render_framebuffers_finish(void) { } @@ -197,8 +251,8 @@ void workbench_render(WORKBENCH_Data *data, const char *viewname = RE_GetActiveRenderView(engine->re); RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); - GPU_framebuffer_bind(dfbl->color_only_fb); - GPU_framebuffer_read_color(dfbl->color_only_fb, + GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_read_color(dfbl->default_fb, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), @@ -207,6 +261,8 @@ void workbench_render(WORKBENCH_Data *data, 0, rp->rect); + workbench_render_result_z(render_layer, viewname, rect); + workbench_render_framebuffers_finish(); } diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index ddaf851324d..8e9a32c003b 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -305,8 +305,9 @@ typedef enum { DRW_STATE_BLEND_ALPHA_UNDER_PREMUL = (1 << 20), DRW_STATE_BLEND_OIT = (1 << 21), DRW_STATE_BLEND_MUL = (1 << 22), + DRW_STATE_BLEND_SUB = (1 << 23), /** Use dual source blending. WARNING: Only one color buffer allowed. */ - DRW_STATE_BLEND_CUSTOM = (1 << 23), + DRW_STATE_BLEND_CUSTOM = (1 << 24), DRW_STATE_IN_FRONT_SELECT = (1 << 25), DRW_STATE_LOGIC_INVERT = (1 << 26), @@ -387,10 +388,10 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, #define DRW_shgroup_call_no_cull(shgrp, geom, ob) \ DRW_shgroup_call_ex(shgrp, ob, NULL, geom, true, NULL) -void DRW_shgroup_call_range(DRWShadingGroup *shgroup, - struct GPUBatch *geom, - uint v_sta, - uint v_ct); +void DRW_shgroup_call_range( + DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct); +void DRW_shgroup_call_instance_range( + DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint v_sta, uint v_ct); void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_ct); void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_ct); @@ -427,6 +428,17 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state); + +/* Reminders: + * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) + * stencil_value being the value stored in the stencil buffer. + * - (writemask & reference) is what gets written if the test condition is fullfiled. + **/ +void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, + uint write_mask, + uint reference, + uint comp_mask); +/* TODO remove this function. Obsolete version. mask is actually reference value. */ void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask); /* Issue a clear command. */ diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 22fd22e4818..f21651dcfeb 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -136,6 +136,7 @@ static struct DRWShapeCache { GPUBatch *drw_particle_cross; GPUBatch *drw_particle_circle; GPUBatch *drw_particle_axis; + GPUBatch *drw_gpencil_dummy_quad; } SHC = {NULL}; void DRW_shape_cache_free(void) @@ -737,6 +738,29 @@ GPUBatch *DRW_cache_normal_arrow_get(void) } /* -------------------------------------------------------------------- */ +/** \name Dummy vbos + * + * We need a dummy vbo containing the vertex count to draw instances ranges. + * + * \{ */ + +GPUBatch *DRW_gpencil_dummy_buffer_get(void) +{ + if (SHC.drw_gpencil_dummy_quad == NULL) { + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U8, 1, GPU_FETCH_INT); + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, 4); + + SHC.drw_gpencil_dummy_quad = GPU_batch_create_ex( + GPU_PRIM_TRI_FAN, vbo, NULL, GPU_BATCH_OWNS_VBO); + } + return SHC.drw_gpencil_dummy_quad; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Common Object API * \{ */ @@ -783,6 +807,9 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob) return DRW_cache_text_face_wireframe_get(ob); case OB_MBALL: return DRW_cache_mball_face_wireframe_get(ob); + case OB_GPENCIL: { + return DRW_cache_gpencil_face_wireframe_get(ob); + } default: return NULL; } diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 508a6f2c46d..5ad8d840fbf 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -29,6 +29,7 @@ struct ModifierData; struct Object; struct PTCacheEdit; struct ParticleSystem; +struct bGPDstroke; void DRW_shape_cache_free(void); void DRW_shape_cache_reset(void); @@ -47,6 +48,9 @@ struct GPUBatch *DRW_cache_sphere_get(void); struct GPUBatch *DRW_cache_screenspace_circle_get(void); struct GPUBatch *DRW_cache_normal_arrow_get(void); +/* Dummy VBOs */ +struct GPUBatch *DRW_gpencil_dummy_buffer_get(void); + /* Common Object */ struct GPUBatch *DRW_cache_object_all_edges_get(struct Object *ob); struct GPUBatch *DRW_cache_object_edge_detection_get(struct Object *ob, bool *r_is_manifold); @@ -197,4 +201,17 @@ struct GPUBatch **DRW_cache_mball_surface_shaded_get(struct Object *ob, struct GPUBatch *DRW_cache_mball_face_wireframe_get(struct Object *ob); struct GPUBatch *DRW_cache_mball_edge_detection_get(struct Object *ob, bool *r_is_manifold); +/* GPencil */ +struct GPUBatch *DRW_cache_gpencil_strokes_get(struct Object *ob, int cfra); +struct GPUBatch *DRW_cache_gpencil_fills_get(struct Object *ob, int cfra); +struct GPUBatch *DRW_cache_gpencil_edit_lines_get(struct Object *ob, int cfra); +struct GPUBatch *DRW_cache_gpencil_edit_points_get(struct Object *ob, int cfra); +struct GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(struct Object *ob); +struct GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(struct Object *ob); + +struct GPUBatch *DRW_cache_gpencil_face_wireframe_get(struct Object *ob); + +struct bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(struct Object *ob); +void DRW_cache_gpencil_sbuffer_clear(struct Object *ob); + #endif /* __DRAW_CACHE_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c new file mode 100644 index 00000000000..e77026e850a --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -0,0 +1,747 @@ +/* + * 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) 2020, Blender Foundation + * This is a new part of Blender + */ + +/** \file + * \ingroup draw + */ + +#include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_screen_types.h" + +#include "BKE_deform.h" +#include "BKE_gpencil.h" + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "GPU_batch.h" +#include "ED_gpencil.h" + +#include "DEG_depsgraph_query.h" + +#include "BLI_polyfill_2d.h" +#include "BLI_hash.h" + +#include "draw_cache.h" +#include "draw_cache_impl.h" + +/* ---------------------------------------------------------------------- */ +typedef struct GpencilBatchCache { + /** Instancing Data */ + GPUVertBuf *vbo; + GPUVertBuf *vbo_col; + /** Fill Topology */ + GPUIndexBuf *ibo; + /** Instancing Batches */ + GPUBatch *stroke_batch; + GPUBatch *fill_batch; + GPUBatch *lines_batch; + + /** Edit Mode */ + GPUVertBuf *edit_vbo; + GPUBatch *edit_lines_batch; + GPUBatch *edit_points_batch; + + /** Cache is dirty */ + bool is_dirty; + /** Edit mode flag */ + bool is_editmode; + /** Last cache frame */ + int cache_frame; +} GpencilBatchCache; + +static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra) +{ + bool valid = true; + if (cache == NULL) { + return false; + } + + cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); + if (cfra != cache->cache_frame) { + valid = false; + } + else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) { + valid = false; + } + else if (gpd->flag & GP_DATA_PYTHON_UPDATED) { + gpd->flag &= ~GP_DATA_PYTHON_UPDATED; + valid = false; + } + else if (cache->is_dirty) { + /* TODO, maybe get rid of the other dirty flags. */ + valid = false; + } + + return valid; +} + +static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) +{ + bGPdata *gpd = (bGPdata *)ob->data; + + GpencilBatchCache *cache = gpd->runtime.gpencil_cache; + + if (!cache) { + cache = gpd->runtime.gpencil_cache = MEM_callocN(sizeof(*cache), __func__); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); + cache->is_dirty = true; + cache->cache_frame = cfra; + return cache; +} + +static void gpencil_batch_cache_clear(GpencilBatchCache *cache) +{ + if (!cache) { + return; + } + + GPU_BATCH_DISCARD_SAFE(cache->lines_batch); + GPU_BATCH_DISCARD_SAFE(cache->fill_batch); + GPU_BATCH_DISCARD_SAFE(cache->stroke_batch); + GPU_VERTBUF_DISCARD_SAFE(cache->vbo); + GPU_VERTBUF_DISCARD_SAFE(cache->vbo_col); + GPU_INDEXBUF_DISCARD_SAFE(cache->ibo); + + GPU_BATCH_DISCARD_SAFE(cache->edit_lines_batch); + GPU_BATCH_DISCARD_SAFE(cache->edit_points_batch); + GPU_VERTBUF_DISCARD_SAFE(cache->edit_vbo); + + cache->is_dirty = true; +} + +static GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra) +{ + bGPdata *gpd = (bGPdata *)ob->data; + + GpencilBatchCache *cache = gpd->runtime.gpencil_cache; + if (!gpencil_batch_cache_valid(cache, gpd, cfra)) { + gpencil_batch_cache_clear(cache); + return gpencil_batch_cache_init(ob, cfra); + } + else { + return cache; + } +} + +void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd) +{ + gpd->flag |= GP_DATA_CACHE_IS_DIRTY; +} + +void DRW_gpencil_batch_cache_free(bGPdata *gpd) +{ + gpencil_batch_cache_clear(gpd->runtime.gpencil_cache); + MEM_SAFE_FREE(gpd->runtime.gpencil_cache); + gpd->flag |= GP_DATA_CACHE_IS_DIRTY; + return; +} + +void DRW_gpencil_freecache(struct Object *ob) +{ + if ((ob) && (ob->type == OB_GPENCIL)) { + bGPdata *gpd = (bGPdata *)ob->data; + if (gpd) { + DRW_gpencil_batch_cache_free(gpd); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Formats. + * \{ */ + +/* MUST match the format below. */ +typedef struct gpStrokeVert { + /** Mat is float because we need to pack other float attribs with it. */ + float mat, strength, stroke_id, point_id; + /** Position and thickness packed in the same attribute. */ + float pos[3], thickness; + float uv_fill[2], u_stroke, v_rot; +} gpStrokeVert; + +static GPUVertFormat *gpencil_stroke_format(void) +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "ma", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "uv", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + /* IMPORTANT: This means having only 4 attributes to fit into GPU module limit of 16 attrib. */ + GPU_vertformat_multiload_enable(&format, 4); + } + return &format; +} + +/* MUST match the format below. */ +typedef struct gpEditVert { + uint vflag; + float weight; +} gpEditVert; + +static GPUVertFormat *gpencil_edit_stroke_format(void) +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "vflag", GPU_COMP_U32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + return &format; +} + +/* MUST match the format below. */ +typedef struct gpColorVert { + float vcol[4]; /* Vertex color */ + float fcol[4]; /* Fill color */ +} gpColorVert; + +static GPUVertFormat *gpencil_color_format(void) +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "col", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "fcol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + /* IMPORTANT: This means having only 4 attributes to fit into GPU module limit of 16 attrib. */ + GPU_vertformat_multiload_enable(&format, 4); + } + return &format; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Vertex Buffers. + * \{ */ + +typedef struct gpIterData { + bGPdata *gpd; + gpStrokeVert *verts; + gpColorVert *cols; + GPUIndexBufBuilder ibo; + int vert_len; + int tri_len; +} gpIterData; + +static GPUVertBuf *gpencil_dummy_buffer_get(void) +{ + GPUBatch *batch = DRW_gpencil_dummy_buffer_get(); + return batch->verts[0]; +} + +static int gpencil_stroke_is_cyclic(const bGPDstroke *gps) +{ + return ((gps->flag & GP_STROKE_CYCLIC) != 0) && (gps->totpoints > 2); +} + +static void gpencil_buffer_add_point(gpStrokeVert *verts, + gpColorVert *cols, + const bGPDstroke *gps, + const bGPDspoint *pt, + int v, + bool is_endpoint) +{ + /* Note: we use the sign of stength and thickness to pass cap flag. */ + const bool round_cap0 = (gps->caps[0] == GP_STROKE_CAP_ROUND); + const bool round_cap1 = (gps->caps[1] == GP_STROKE_CAP_ROUND); + gpStrokeVert *vert = &verts[v]; + gpColorVert *col = &cols[v]; + copy_v3_v3(vert->pos, &pt->x); + copy_v2_v2(vert->uv_fill, pt->uv_fill); + copy_v4_v4(col->vcol, pt->vert_color); + copy_v4_v4(col->fcol, gps->vert_color_fill); + + /* Encode fill opacity defined by opacity modifier in vertex color alpha. If + * no opacity modifier, the value will be always 1.0f. The opacity factor can be any + * value between 0.0f and 2.0f */ + col->fcol[3] = (((int)(col->fcol[3] * 10000.0f)) * 10.0f) + gps->fill_opacity_fac; + + vert->strength = (round_cap0) ? pt->strength : -pt->strength; + vert->u_stroke = pt->uv_fac; + vert->stroke_id = gps->runtime.stroke_start; + vert->point_id = v; + /* Rotation are in [-90°..90°] range, so we can encode the sign of the angle + the cosine + * because the cosine will always be positive. */ + vert->v_rot = cosf(pt->uv_rot) * signf(pt->uv_rot); + vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0 : -1.0); + /* Tag endpoint material to -1 so they get discarded by vertex shader. */ + vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GP_MATERIAL_BUFFER_LEN); +} + +static void gpencil_buffer_add_stroke(gpStrokeVert *verts, + gpColorVert *cols, + const bGPDstroke *gps) +{ + const bGPDspoint *pts = gps->points; + int pts_len = gps->totpoints; + bool is_cyclic = gpencil_stroke_is_cyclic(gps); + int v = gps->runtime.stroke_start; + + /* First point for adjacency (not drawn). */ + int adj_idx = (is_cyclic) ? (pts_len - 1) : min_ii(pts_len - 1, 1); + gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true); + + for (int i = 0; i < pts_len; i++) { + gpencil_buffer_add_point(verts, cols, gps, &pts[i], v++, false); + } + /* Draw line to first point to complete the loop for cyclic strokes. */ + if (is_cyclic) { + gpencil_buffer_add_point(verts, cols, gps, &pts[0], v++, false); + } + /* Last adjacency point (not drawn). */ + adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2); + gpencil_buffer_add_point(verts, cols, gps, &pts[adj_idx], v++, true); +} + +static void gpencil_buffer_add_fill(GPUIndexBufBuilder *ibo, const bGPDstroke *gps) +{ + int tri_len = gps->tot_triangles; + int v = gps->runtime.stroke_start; + for (int i = 0; i < tri_len; i++) { + uint *tri = gps->triangles[i].verts; + GPU_indexbuf_add_tri_verts(ibo, v + tri[0], v + tri[1], v + tri[2]); + } +} + +static void gpencil_stroke_iter_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + gpIterData *iter = (gpIterData *)thunk; + gpencil_buffer_add_stroke(iter->verts, iter->cols, gps); + if (gps->tot_triangles > 0) { + gpencil_buffer_add_fill(&iter->ibo, gps); + } +} + +static void gp_object_verts_count_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + gpIterData *iter = (gpIterData *)thunk; + + /* Store first index offset */ + gps->runtime.stroke_start = iter->vert_len; + gps->runtime.fill_start = iter->tri_len; + iter->vert_len += gps->totpoints + 2 + gpencil_stroke_is_cyclic(gps); + iter->tri_len += gps->tot_triangles; +} + +static void gpencil_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra) +{ + bGPdata *gpd = (bGPdata *)ob->data; + + if (cache->vbo == NULL) { + /* Should be discarded together. */ + BLI_assert(cache->vbo == NULL && cache->ibo == NULL); + BLI_assert(cache->stroke_batch == NULL && cache->stroke_batch == NULL); + /* TODO/PERF: Could be changed to only do it if needed. + * For now it's simpler to assume we always need it + * since multiple viewport could or could not need it. + * Ideally we should have a dedicated onion skin geom batch. */ + /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */ + bool do_onion = true; + + /* First count how many vertices and triangles are needed for the whole object. */ + gpIterData iter = { + .gpd = gpd, + .verts = NULL, + .ibo = {0}, + .vert_len = 1, /* Start at 1 for the gl_InstanceID trick to work (see vert shader). */ + .tri_len = 0, + }; + BKE_gpencil_visible_stroke_iter(ob, NULL, gp_object_verts_count_cb, &iter, do_onion, cfra); + + /* Create VBOs. */ + GPUVertFormat *format = gpencil_stroke_format(); + GPUVertFormat *format_col = gpencil_color_format(); + cache->vbo = GPU_vertbuf_create_with_format(format); + cache->vbo_col = GPU_vertbuf_create_with_format(format_col); + /* Add extra space at the end of the buffer because of quad load. */ + GPU_vertbuf_data_alloc(cache->vbo, iter.vert_len + 2); + GPU_vertbuf_data_alloc(cache->vbo_col, iter.vert_len + 2); + iter.verts = (gpStrokeVert *)cache->vbo->data; + iter.cols = (gpColorVert *)cache->vbo_col->data; + /* Create IBO. */ + GPU_indexbuf_init(&iter.ibo, GPU_PRIM_TRIS, iter.tri_len, iter.vert_len); + + /* Fill buffers with data. */ + BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_stroke_iter_cb, &iter, do_onion, cfra); + + /* Mark last 2 verts as invalid. */ + for (int i = 0; i < 2; i++) { + iter.verts[iter.vert_len + i].mat = -1; + } + + /* Finish the IBO. */ + cache->ibo = GPU_indexbuf_build(&iter.ibo); + + /* Create the batches */ + cache->fill_batch = GPU_batch_create(GPU_PRIM_TRIS, cache->vbo, cache->ibo); + GPU_batch_vertbuf_add(cache->fill_batch, cache->vbo_col); + cache->stroke_batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL); + GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo, 0); + GPU_batch_instbuf_add_ex(cache->stroke_batch, cache->vbo_col, 0); + + gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; + cache->is_dirty = false; + } +} + +GPUBatch *DRW_cache_gpencil_strokes_get(Object *ob, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); + gpencil_batches_ensure(ob, cache, cfra); + + return cache->stroke_batch; +} + +GPUBatch *DRW_cache_gpencil_fills_get(Object *ob, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); + gpencil_batches_ensure(ob, cache, cfra); + + return cache->fill_batch; +} + +static void gp_lines_indices_cb(bGPDlayer *UNUSED(gpl), + bGPDframe *UNUSED(gpf), + bGPDstroke *gps, + void *thunk) +{ + gpIterData *iter = (gpIterData *)thunk; + int pts_len = gps->totpoints + gpencil_stroke_is_cyclic(gps); + + int start = gps->runtime.stroke_start + 1; + int end = start + pts_len; + for (int i = start; i < end; i++) { + GPU_indexbuf_add_generic_vert(&iter->ibo, i); + } + GPU_indexbuf_add_primitive_restart(&iter->ibo); +} + +GPUBatch *DRW_cache_gpencil_face_wireframe_get(Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + int cfra = DEG_get_ctime(draw_ctx->depsgraph); + + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); + gpencil_batches_ensure(ob, cache, cfra); + + if (cache->lines_batch == NULL) { + GPUVertBuf *vbo = cache->vbo; + + gpIterData iter = { + .gpd = ob->data, + .ibo = {0}, + }; + + GPU_indexbuf_init_ex(&iter.ibo, GPU_PRIM_LINE_STRIP, vbo->vertex_len, vbo->vertex_len); + + /* IMPORTANT: Keep in sync with gpencil_edit_batches_ensure() */ + bool do_onion = true; + BKE_gpencil_visible_stroke_iter(ob, NULL, gp_lines_indices_cb, &iter, do_onion, cfra); + + GPUIndexBuf *ibo = GPU_indexbuf_build(&iter.ibo); + + cache->lines_batch = GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, ibo, GPU_BATCH_OWNS_INDEX); + } + return cache->lines_batch; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Sbuffer stroke batches. + * \{ */ + +bGPDstroke *DRW_cache_gpencil_sbuffer_stroke_data_get(Object *ob) +{ + bGPdata *gpd = (bGPdata *)ob->data; + /* Convert the sbuffer to a bGPDstroke. */ + if (gpd->runtime.sbuffer_gps == NULL) { + bGPDstroke *gps = MEM_callocN(sizeof(*gps), "bGPDstroke sbuffer"); + gps->totpoints = gpd->runtime.sbuffer_used; + gps->mat_nr = max_ii(0, gpd->runtime.matid - 1); + gps->flag = gpd->runtime.sbuffer_sflag; + gps->thickness = gpd->runtime.brush_size; + /* Reduce slightly the opacity of fill to make easy fill areas while drawing. */ + gps->fill_opacity_fac = 0.8f; + + gps->tot_triangles = max_ii(0, gpd->runtime.sbuffer_used - 2); + gps->caps[0] = gps->caps[1] = GP_STROKE_CAP_ROUND; + gps->runtime.stroke_start = 1; /* Add one for the adjacency index. */ + copy_v4_v4(gps->vert_color_fill, gpd->runtime.vert_color_fill); + gpd->runtime.sbuffer_gps = gps; + } + return gpd->runtime.sbuffer_gps; +} + +/* gpd is original ID. */ +static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_fill) +{ + tGPspoint *tpoints = gpd->runtime.sbuffer; + bGPDstroke *gps = gpd->runtime.sbuffer_gps; + int vert_len = gpd->runtime.sbuffer_used; + + /* DRW_cache_gpencil_sbuffer_stroke_data_get need to have been called previously. */ + BLI_assert(gps != NULL); + + if (do_stroke && (gpd->runtime.sbuffer_stroke_batch == NULL)) { + gps->points = MEM_mallocN(vert_len * sizeof(*gps->points), __func__); + + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + ARegion *ar = draw_ctx->ar; + Object *ob = draw_ctx->obact; + + BLI_assert(ob && (ob->type == OB_GPENCIL)); + + /* Get origin to reproject points. */ + float origin[3]; + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); + ToolSettings *ts = scene->toolsettings; + ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, origin); + + for (int i = 0; i < vert_len; i++) { + ED_gpencil_tpoint_to_point(ar, origin, &tpoints[i], &gps->points[i]); + mul_m4_v3(ob->imat, &gps->points[i].x); + bGPDspoint *pt = &gps->points[i]; + copy_v4_v4(pt->vert_color, gpd->runtime.vert_color); + } + /* Calc uv data along the stroke. */ + BKE_gpencil_stroke_uv_update(gps); + + /* Create VBO. */ + GPUVertFormat *format = gpencil_stroke_format(); + GPUVertFormat *format_color = gpencil_color_format(); + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(format); + GPUVertBuf *vbo_col = GPU_vertbuf_create_with_format(format_color); + /* Add extra space at the end (and start) of the buffer because of quad load and cyclic. */ + GPU_vertbuf_data_alloc(vbo, 1 + vert_len + 1 + 2); + GPU_vertbuf_data_alloc(vbo_col, 1 + vert_len + 1 + 2); + gpStrokeVert *verts = (gpStrokeVert *)vbo->data; + gpColorVert *cols = (gpColorVert *)vbo_col->data; + + /* Fill buffers with data. */ + gpencil_buffer_add_stroke(verts, cols, gps); + + GPUBatch *batch = GPU_batch_create(GPU_PRIM_TRI_STRIP, gpencil_dummy_buffer_get(), NULL); + GPU_batch_instbuf_add_ex(batch, vbo, true); + GPU_batch_instbuf_add_ex(batch, vbo_col, true); + + gpd->runtime.sbuffer_stroke_batch = batch; + + MEM_freeN(gps->points); + } + + if (do_fill && (gpd->runtime.sbuffer_fill_batch == NULL)) { + /* Create IBO. */ + GPUIndexBufBuilder ibo_builder; + GPU_indexbuf_init(&ibo_builder, GPU_PRIM_TRIS, gps->tot_triangles, vert_len); + + if (gps->tot_triangles > 0) { + float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__); + /* Triangulate in 2D. */ + for (int i = 0; i < vert_len; i++) { + copy_v2_v2(tpoints2d[i], &tpoints[i].x); + } + /* Compute directly inside the IBO data buffer. */ + /* OPTI: This is a bottleneck if the stroke is very long. */ + BLI_polyfill_calc(tpoints2d, (uint)vert_len, 0, (uint(*)[3])ibo_builder.data); + /* Add stroke start offset. */ + for (int i = 0; i < gps->tot_triangles * 3; i++) { + ibo_builder.data[i] += gps->runtime.stroke_start; + } + /* HACK since we didn't use the builder API to avoid another malloc and copy, + * we need to set the number of indices manually. */ + ibo_builder.index_len = gps->tot_triangles * 3; + + MEM_freeN(tpoints2d); + } + + GPUIndexBuf *ibo = GPU_indexbuf_build(&ibo_builder); + GPUVertBuf *vbo = gpd->runtime.sbuffer_stroke_batch->inst[0]; + GPUVertBuf *vbo_col = gpd->runtime.sbuffer_stroke_batch->inst[1]; + + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, ibo, GPU_BATCH_OWNS_INDEX); + GPU_batch_vertbuf_add(batch, vbo_col); + + gpd->runtime.sbuffer_fill_batch = batch; + } +} + +GPUBatch *DRW_cache_gpencil_sbuffer_stroke_get(Object *ob) +{ + bGPdata *gpd = (bGPdata *)ob->data; + gpencil_sbuffer_stroke_ensure(gpd, true, false); + + return gpd->runtime.sbuffer_stroke_batch; +} + +GPUBatch *DRW_cache_gpencil_sbuffer_fill_get(Object *ob) +{ + bGPdata *gpd = (bGPdata *)ob->data; + /* Fill batch also need stroke batch to be created (vbo is shared). */ + gpencil_sbuffer_stroke_ensure(gpd, true, true); + + return gpd->runtime.sbuffer_fill_batch; +} + +/* Sbuffer batches are temporary. We need to clear it after drawing */ +void DRW_cache_gpencil_sbuffer_clear(Object *ob) +{ + bGPdata *gpd = (bGPdata *)ob->data; + MEM_SAFE_FREE(gpd->runtime.sbuffer_gps); + GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_fill_batch); + GPU_BATCH_DISCARD_SAFE(gpd->runtime.sbuffer_stroke_batch); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/* Edit GPencil Batches */ + +#define GP_EDIT_POINT_SELECTED (1 << 0) +#define GP_EDIT_STROKE_SELECTED (1 << 1) +#define GP_EDIT_MULTIFRAME (1 << 2) +#define GP_EDIT_STROKE_START (1 << 3) +#define GP_EDIT_STROKE_END (1 << 4) + +typedef struct gpEditIterData { + gpEditVert *verts; + int vgindex; +} gpEditIterData; + +static uint32_t gpencil_point_edit_flag(const bGPDspoint *pt, int v, int v_len) +{ + uint32_t sflag = 0; + SET_FLAG_FROM_TEST(sflag, pt->flag & GP_SPOINT_SELECT, GP_EDIT_POINT_SELECTED); + SET_FLAG_FROM_TEST(sflag, v == 0, GP_EDIT_STROKE_START); + SET_FLAG_FROM_TEST(sflag, v == (v_len - 1), GP_EDIT_STROKE_END); + return sflag; +} + +static float gpencil_point_edit_weight(const MDeformVert *dvert, int v, int vgindex) +{ + return (dvert && dvert[v].dw) ? defvert_find_weight(&dvert[v], vgindex) : -1.0f; +} + +static void gpencil_edit_stroke_iter_cb(bGPDlayer *gpl, + bGPDframe *gpf, + bGPDstroke *gps, + void *thunk) +{ + /* Cancel if layer is locked. */ + if (gpl->flag & GP_LAYER_LOCKED) { + return; + } + + gpEditIterData *iter = (gpEditIterData *)thunk; + const int v_len = gps->totpoints; + const int v = gps->runtime.stroke_start + 1; + MDeformVert *dvert = ((iter->vgindex > -1) && gps->dvert) ? gps->dvert : NULL; + gpEditVert *vert_ptr = iter->verts + v; + + uint32_t sflag = 0; + SET_FLAG_FROM_TEST(sflag, gps->flag & GP_STROKE_SELECT, GP_EDIT_STROKE_SELECTED); + SET_FLAG_FROM_TEST(sflag, gpf->runtime.onion_id != 0.0f, GP_EDIT_MULTIFRAME); + + for (int i = 0; i < v_len; i++) { + vert_ptr->vflag = sflag | gpencil_point_edit_flag(&gps->points[i], i, v_len); + vert_ptr->weight = gpencil_point_edit_weight(dvert, i, iter->vgindex); + vert_ptr++; + } + /* Draw line to first point to complete the loop for cyclic strokes. */ + vert_ptr->vflag = sflag | gpencil_point_edit_flag(&gps->points[0], 0, v_len); + vert_ptr->weight = gpencil_point_edit_weight(dvert, 0, iter->vgindex); +} + +static void gpencil_edit_batches_ensure(Object *ob, GpencilBatchCache *cache, int cfra) +{ + bGPdata *gpd = (bGPdata *)ob->data; + + if (cache->edit_vbo == NULL) { + /* TODO/PERF: Could be changed to only do it if needed. + * For now it's simpler to assume we always need it + * since multiple viewport could or could not need it. + * Ideally we should have a dedicated onion skin geom batch. */ + /* IMPORTANT: Keep in sync with gpencil_batches_ensure() */ + bool do_onion = true; + + /* Vertex counting has already been done for cache->vbo. */ + BLI_assert(cache->vbo); + int vert_len = cache->vbo->vertex_len; + + gpEditIterData iter; + iter.vgindex = ob->actdef - 1; + if (!BLI_findlink(&ob->defbase, iter.vgindex)) { + iter.vgindex = -1; + } + + /* Create VBO. */ + GPUVertFormat *format = gpencil_edit_stroke_format(); + cache->edit_vbo = GPU_vertbuf_create_with_format(format); + /* Add extra space at the end of the buffer because of quad load. */ + GPU_vertbuf_data_alloc(cache->edit_vbo, vert_len); + iter.verts = (gpEditVert *)cache->edit_vbo->data; + + /* Fill buffers with data. */ + BKE_gpencil_visible_stroke_iter(ob, NULL, gpencil_edit_stroke_iter_cb, &iter, do_onion, cfra); + + /* Create the batches */ + cache->edit_points_batch = GPU_batch_create(GPU_PRIM_POINTS, cache->vbo, NULL); + GPU_batch_vertbuf_add(cache->edit_points_batch, cache->edit_vbo); + + cache->edit_lines_batch = GPU_batch_create(GPU_PRIM_LINE_STRIP, cache->vbo, NULL); + GPU_batch_vertbuf_add(cache->edit_lines_batch, cache->edit_vbo); + + gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; + cache->is_dirty = false; + } +} + +GPUBatch *DRW_cache_gpencil_edit_lines_get(Object *ob, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); + gpencil_batches_ensure(ob, cache, cfra); + gpencil_edit_batches_ensure(ob, cache, cfra); + + return cache->edit_lines_batch; +} + +GPUBatch *DRW_cache_gpencil_edit_points_get(Object *ob, int cfra) +{ + GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra); + gpencil_batches_ensure(ob, cache, cfra); + gpencil_edit_batches_ensure(ob, cache, cfra); + + return cache->edit_points_batch; +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 65365ef7119..561edfae513 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -72,6 +72,8 @@ void DRW_globals_update(void) UI_COLOR_RGBA_FROM_U8(0xB0, 0x00, 0xB0, 0xFF, gb->colorVertexMissingData); UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, gb->colorEditMeshActive); UI_GetThemeColor4fv(TH_EDGE_SELECT, gb->colorEdgeSelect); + UI_GetThemeColor4fv(TH_GP_VERTEX, gb->colorGpencilVertex); + UI_GetThemeColor4fv(TH_GP_VERTEX_SELECT, gb->colorGpencilVertexSelect); UI_GetThemeColor4fv(TH_EDGE_SEAM, gb->colorEdgeSeam); UI_GetThemeColor4fv(TH_EDGE_SHARP, gb->colorEdgeSharp); diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 97afb5e6aa4..6507dd28903 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -68,6 +68,8 @@ typedef struct GlobalsUboStorage { float colorFace[4]; float colorFaceSelect[4]; float colorFaceFreestyle[4]; + float colorGpencilVertex[4]; + float colorGpencilVertexSelect[4]; float colorNormal[4]; float colorVNormal[4]; float colorLNormal[4]; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 3dc775f92c4..deec62a2a8b 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1390,7 +1390,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer), const bool use_xray = XRAY_ENABLED(v3d); drw_engines_enable_from_engine(engine_type, drawtype, use_xray); - if (gpencil_engine_needed) { + if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) { use_drw_engine(&draw_engine_gpencil_type); } drw_engines_enable_overlays(); @@ -2370,13 +2370,6 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, } } - /* TODO: GPXX Workaround for grease pencil selection while draw manager support a callback from - * scene finish */ - void *data = GPU_viewport_engine_data_get(DST.viewport, &draw_engine_gpencil_type); - if (data != NULL) { - DRW_gpencil_free_runtime_data(data); - } - DRW_state_lock(0); DRW_draw_callbacks_post_scene(); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index f040afc794c..7e919b9e2df 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -181,7 +181,8 @@ typedef enum { DRW_CMD_DRAW = 0, /* Only sortable type. Must be 0. */ DRW_CMD_DRAW_RANGE = 1, DRW_CMD_DRAW_INSTANCE = 2, - DRW_CMD_DRAW_PROCEDURAL = 3, + DRW_CMD_DRAW_INSTANCE_RANGE = 3, + DRW_CMD_DRAW_PROCEDURAL = 4, /* Other Commands */ DRW_CMD_CLEAR = 12, DRW_CMD_DRWSTATE = 13, @@ -200,6 +201,7 @@ typedef struct DRWCommandDraw { /* Assume DRWResourceHandle to be 0. */ typedef struct DRWCommandDrawRange { GPUBatch *batch; + DRWResourceHandle handle; uint vert_first; uint vert_count; } DRWCommandDrawRange; @@ -211,6 +213,13 @@ typedef struct DRWCommandDrawInstance { uint use_attribs; /* bool */ } DRWCommandDrawInstance; +typedef struct DRWCommandDrawInstanceRange { + GPUBatch *batch; + DRWResourceHandle handle; + uint inst_first; + uint inst_count; +} DRWCommandDrawInstanceRange; + typedef struct DRWCommandDrawProcedural { GPUBatch *batch; DRWResourceHandle handle; @@ -224,7 +233,9 @@ typedef struct DRWCommandSetMutableState { } DRWCommandSetMutableState; typedef struct DRWCommandSetStencil { - uint mask; + uint write_mask; + uint comp_mask; + uint ref; } DRWCommandSetStencil; typedef struct DRWCommandSetSelectID { @@ -243,6 +254,7 @@ typedef union DRWCommand { DRWCommandDraw draw; DRWCommandDrawRange range; DRWCommandDrawInstance instance; + DRWCommandDrawInstanceRange instance_range; DRWCommandDrawProcedural procedural; DRWCommandSetMutableState state; DRWCommandSetStencil stencil; @@ -273,6 +285,7 @@ typedef enum { DRW_UNIFORM_BLOCK_OBMATS, DRW_UNIFORM_BLOCK_OBINFOS, DRW_UNIFORM_RESOURCE_CHUNK, + DRW_UNIFORM_RESOURCE_ID, /** Legacy / Fallback */ DRW_UNIFORM_BASE_INSTANCE, DRW_UNIFORM_MODEL_MATRIX, @@ -467,7 +480,6 @@ typedef struct DRWManager { /* Managed by `DRW_state_set`, `DRW_state_reset` */ DRWState state; DRWState state_lock; - uint stencil_mask; /* Per viewport */ GPUViewport *viewport; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index f9a6b663900..2612d02691d 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -636,13 +636,12 @@ static void drw_command_draw(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResou cmd->handle = handle; } -static void drw_command_draw_range(DRWShadingGroup *shgroup, - GPUBatch *batch, - uint start, - uint count) +static void drw_command_draw_range( + DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint start, uint count) { DRWCommandDrawRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_RANGE); cmd->batch = batch; + cmd->handle = handle; cmd->vert_first = start; cmd->vert_count = count; } @@ -660,6 +659,16 @@ static void drw_command_draw_instance(DRWShadingGroup *shgroup, cmd->use_attribs = use_attrib; } +static void drw_command_draw_intance_range( + DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, uint start, uint count) +{ + DRWCommandDrawInstanceRange *cmd = drw_command_create(shgroup, DRW_CMD_DRAW_INSTANCE_RANGE); + cmd->batch = batch; + cmd->handle = handle; + cmd->inst_first = start; + cmd->inst_count = count; +} + static void drw_command_draw_procedural(DRWShadingGroup *shgroup, GPUBatch *batch, DRWResourceHandle handle, @@ -680,11 +689,18 @@ static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, cmd->select_id = select_id; } -static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint mask) +static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, + uint write_mask, + uint reference, + uint comp_mask) { - BLI_assert(mask <= 0xFF); + BLI_assert(write_mask <= 0xFF); + BLI_assert(reference <= 0xFF); + BLI_assert(comp_mask <= 0xFF); DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL); - cmd->mask = mask; + cmd->write_mask = write_mask; + cmd->comp_mask = comp_mask; + cmd->ref = reference; } static void drw_command_clear(DRWShadingGroup *shgroup, @@ -745,13 +761,27 @@ void DRW_shgroup_call_ex(DRWShadingGroup *shgroup, } } -void DRW_shgroup_call_range(DRWShadingGroup *shgroup, struct GPUBatch *geom, uint v_sta, uint v_ct) +void DRW_shgroup_call_range( + DRWShadingGroup *shgroup, struct Object *ob, GPUBatch *geom, uint v_sta, uint v_ct) +{ + BLI_assert(geom != NULL); + if (G.f & G_FLAG_PICKSEL) { + drw_command_set_select_id(shgroup, NULL, DST.select_id); + } + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct); +} + +void DRW_shgroup_call_instance_range( + DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct) { + BLI_assert(i_ct > 0); BLI_assert(geom != NULL); if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, NULL, DST.select_id); } - drw_command_draw_range(shgroup, geom, v_sta, v_ct); + DRWResourceHandle handle = drw_resource_handle(shgroup, ob ? ob->obmat : NULL, ob); + drw_command_draw_intance_range(shgroup, geom, handle, i_sta, i_ct); } static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup, @@ -1104,12 +1134,18 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) int info_ubo_location = GPU_shader_get_uniform_block(shader, "infoBlock"); int baseinst_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_BASE_INSTANCE); int chunkid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_CHUNK); + int resourceid_location = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_RESOURCE_ID); if (chunkid_location != -1) { drw_shgroup_uniform_create_ex( shgroup, chunkid_location, DRW_UNIFORM_RESOURCE_CHUNK, NULL, 0, 1); } + if (resourceid_location != -1) { + drw_shgroup_uniform_create_ex( + shgroup, resourceid_location, DRW_UNIFORM_RESOURCE_ID, NULL, 0, 1); + } + if (baseinst_location != -1) { drw_shgroup_uniform_create_ex( shgroup, baseinst_location, DRW_UNIFORM_BASE_INSTANCE, NULL, 0, 1); @@ -1308,9 +1344,18 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) drw_command_set_mutable_state(shgroup, 0x0, state); } +void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, + uint write_mask, + uint reference, + uint comp_mask) +{ + drw_command_set_stencil_mask(shgroup, write_mask, reference, comp_mask); +} + +/* TODO remove this function. */ void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask) { - drw_command_set_stencil_mask(shgroup, mask); + drw_command_set_stencil_mask(shgroup, 0xFF, mask, 0xFF); } void DRW_shgroup_clear_framebuffer(DRWShadingGroup *shgroup, diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 75d5a5c73b9..7bcb0b0f86d 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -50,6 +50,7 @@ void DRW_select_load_id(uint id) typedef struct DRWCommandsState { GPUBatch *batch; int resource_chunk; + int resource_id; int base_inst; int inst_count; int v_first; @@ -60,6 +61,7 @@ typedef struct DRWCommandsState { int obinfos_loc; int baseinst_loc; int chunkid_loc; + int resourceid_loc; /* Legacy matrix support. */ int obmat_loc; int obinv_loc; @@ -221,7 +223,6 @@ void drw_state_set(DRWState state) { int test; if (CHANGED_ANY_STORE_VAR(DRW_STATE_STENCIL_TEST_ENABLED, test)) { - DST.stencil_mask = STENCIL_UNDEFINED; if (test) { glEnable(GL_STENCIL_TEST); } @@ -234,11 +235,11 @@ void drw_state_set(DRWState state) /* Blending (all buffer) */ { int test; - if (CHANGED_ANY_STORE_VAR(DRW_STATE_BLEND_ALPHA | DRW_STATE_BLEND_ALPHA_PREMUL | - DRW_STATE_BLEND_ADD | DRW_STATE_BLEND_MUL | - DRW_STATE_BLEND_ADD_FULL | DRW_STATE_BLEND_OIT | - DRW_STATE_BLEND_ALPHA_UNDER_PREMUL | DRW_STATE_BLEND_CUSTOM, - test)) { + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_BLEND_ALPHA | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_BLEND_ADD | + DRW_STATE_BLEND_MUL | DRW_STATE_BLEND_ADD_FULL | DRW_STATE_BLEND_OIT | + DRW_STATE_BLEND_ALPHA_UNDER_PREMUL | DRW_STATE_BLEND_CUSTOM | DRW_STATE_BLEND_SUB, + test)) { if (test) { glEnable(GL_BLEND); @@ -274,6 +275,9 @@ void drw_state_set(DRWState state) /* Let alpha accumulate. */ glBlendFunc(GL_ONE, GL_ONE); } + else if ((state & DRW_STATE_BLEND_SUB) != 0) { + glBlendFunc(GL_ONE, GL_ONE); + } else if ((state & DRW_STATE_BLEND_CUSTOM) != 0) { /* Custom blend parameters using dual source blending. * Can only be used with one Draw Buffer. */ @@ -282,6 +286,13 @@ void drw_state_set(DRWState state) else { BLI_assert(0); } + + if ((state & DRW_STATE_BLEND_SUB) != 0) { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + } + else { + glBlendEquation(GL_FUNC_ADD); + } } else { glDisable(GL_BLEND); @@ -389,19 +400,23 @@ void drw_state_set(DRWState state) DST.state = state; } -static void drw_stencil_set(uint mask) +static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_mask) { - if (DST.stencil_mask != mask) { - DST.stencil_mask = mask; - if ((DST.state & DRW_STATE_STENCIL_ALWAYS) != 0) { - glStencilFunc(GL_ALWAYS, mask, 0xFF); - } - else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) { - glStencilFunc(GL_EQUAL, mask, 0xFF); - } - else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) { - glStencilFunc(GL_NOTEQUAL, mask, 0xFF); - } + /* Reminders: + * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) + * stencil_value being the value stored in the stencil buffer. + * - (writemask & reference) is what gets written if the test condition is fullfiled. + **/ + glStencilMask(write_mask); + + if ((DST.state & DRW_STATE_STENCIL_ALWAYS) != 0) { + glStencilFunc(GL_ALWAYS, reference, compare_mask); + } + else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) { + glStencilFunc(GL_EQUAL, reference, compare_mask); + } + else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) { + glStencilFunc(GL_NOTEQUAL, reference, compare_mask); } } @@ -982,6 +997,9 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup, state->chunkid_loc = uni->location; GPU_shader_uniform_int(shgroup->shader, uni->location, 0); break; + case DRW_UNIFORM_RESOURCE_ID: + state->resourceid_loc = uni->location; + break; case DRW_UNIFORM_TFEEDBACK_TARGET: BLI_assert(data && (*use_tfeedback == false)); *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader, @@ -1095,6 +1113,14 @@ static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHa } state->resource_chunk = chunk; } + + if (state->resourceid_loc != -1) { + int id = DRW_handle_id_get(handle); + if (state->resource_id != id) { + GPU_shader_uniform_int(NULL, state->resourceid_loc, id); + state->resource_id = id; + } + } } static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state) @@ -1113,6 +1139,7 @@ static void draw_call_single_do(DRWShadingGroup *shgroup, DRWResourceHandle handle, int vert_first, int vert_count, + int inst_first, int inst_count, bool do_base_instance) { @@ -1141,7 +1168,7 @@ static void draw_call_single_do(DRWShadingGroup *shgroup, batch, vert_first, vert_count, - do_base_instance ? DRW_handle_id_get(&handle) : 0, + do_base_instance ? DRW_handle_id_get(&handle) : inst_first, inst_count, state->baseinst_loc); } @@ -1150,6 +1177,7 @@ static void draw_call_batching_start(DRWCommandsState *state) { state->neg_scale = false; state->resource_chunk = 0; + state->resource_id = -1; state->base_inst = 0; state->inst_count = 0; state->v_first = 0; @@ -1226,6 +1254,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) .obinfos_loc = -1, .baseinst_loc = -1, .chunkid_loc = -1, + .resourceid_loc = -1, .obmat_loc = -1, .obinv_loc = -1, .mvp_loc = -1, @@ -1306,7 +1335,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled); break; case DRW_CMD_STENCIL: - drw_stencil_set(cmd->stencil.mask); + drw_stencil_state_set(cmd->stencil.write_mask, cmd->stencil.ref, cmd->stencil.comp_mask); break; case DRW_CMD_SELECTID: state.select_id = cmd->select_id.select_id; @@ -1314,8 +1343,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) break; case DRW_CMD_DRAW: if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) || - cmd->draw.batch->inst[0]) { - draw_call_single_do(shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0, true); + cmd->draw.batch->inst) { + draw_call_single_do( + shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0, 0, true); } else { draw_call_batching_do(shgroup, &state, &cmd->draw); @@ -1328,6 +1358,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) cmd->procedural.handle, 0, cmd->procedural.vert_count, + 0, 1, true); break; @@ -1338,6 +1369,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) cmd->instance.handle, 0, 0, + 0, cmd->instance.inst_count, cmd->instance.use_attribs == 0); break; @@ -1345,12 +1377,24 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) draw_call_single_do(shgroup, &state, cmd->range.batch, - (DRWResourceHandle)0, + cmd->range.handle, cmd->range.vert_first, cmd->range.vert_count, + 0, 1, true); break; + case DRW_CMD_DRAW_INSTANCE_RANGE: + draw_call_single_do(shgroup, + &state, + cmd->instance_range.batch, + cmd->instance_range.handle, + 0, + 0, + cmd->instance_range.inst_first, + cmd->instance_range.inst_count, + false); + break; } } diff --git a/source/blender/draw/intern/shaders/common_globals_lib.glsl b/source/blender/draw/intern/shaders/common_globals_lib.glsl index 676492f227d..6ee0fe05721 100644 --- a/source/blender/draw/intern/shaders/common_globals_lib.glsl +++ b/source/blender/draw/intern/shaders/common_globals_lib.glsl @@ -32,6 +32,8 @@ layout(std140) uniform globalsBlock vec4 colorFace; vec4 colorFaceSelect; vec4 colorFaceFreestyle; + vec4 colorGpencilVertex; + vec4 colorGpencilVertexSelect; vec4 colorNormal; vec4 colorVNormal; vec4 colorLNormal; diff --git a/source/blender/draw/intern/shaders/common_smaa_lib.glsl b/source/blender/draw/intern/shaders/common_smaa_lib.glsl index 09b573d4bb5..45d9f54d943 100644 --- a/source/blender/draw/intern/shaders/common_smaa_lib.glsl +++ b/source/blender/draw/intern/shaders/common_smaa_lib.glsl @@ -692,6 +692,10 @@ void SMAANeighborhoodBlendingVS(float2 texcoord, out float4 offset) //----------------------------------------------------------------------------- // Edge Detection Pixel Shaders (First Pass) +# ifndef SMAA_LUMA_WEIGHT +# define SMAA_LUMA_WEIGHT float4(0.2126, 0.7152, 0.0722, 0.0) +# endif + /** * Luma Edge Detection * @@ -716,7 +720,8 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord, # endif // Calculate lumas: - float4 weights = float4(0.2126 * 0.5, 0.7152 * 0.5, 0.0722 * 0.5, 0.5); + // float4 weights = float4(0.2126, 0.7152, 0.0722, 0.0); + float4 weights = SMAA_LUMA_WEIGHT; float L = dot(SMAASamplePoint(colorTex, texcoord).rgba, weights); float Lleft = dot(SMAASamplePoint(colorTex, offset[0].xy).rgba, weights); @@ -727,9 +732,11 @@ float2 SMAALumaEdgeDetectionPS(float2 texcoord, delta.xy = abs(L - float2(Lleft, Ltop)); float2 edges = step(threshold, delta.xy); +# ifndef SMAA_NO_DISCARD // Then discard if there is no edge: if (dot(edges, float2(1.0, 1.0)) == 0.0) discard; +# endif // Calculate right and bottom deltas: float Lright = dot(SMAASamplePoint(colorTex, offset[1].xy).rgba, weights); @@ -793,9 +800,11 @@ float2 SMAAColorEdgeDetectionPS(float2 texcoord, // We do the usual threshold: float2 edges = step(threshold, delta.xy); +# ifndef SMAA_NO_DISCARD // Then discard if there is no edge: if (dot(edges, float2(1.0, 1.0)) == 0.0) discard; +# endif // Calculate right and bottom deltas: float3 Cright = SMAASamplePoint(colorTex, offset[1].xy).rgb; diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index 6605e1165d4..3faefd485bf 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -60,11 +60,11 @@ vec4 pack_line_data(vec2 frag_co, vec2 edge_start, vec2 edge_pos) vec2 perp = vec2(-edge.y, edge.x); float dist = dot(perp, frag_co - edge_start); /* Add 0.1 to diffenrentiate with cleared pixels. */ - return vec4(perp * 0.5 + 0.5, dist * 0.25 + 0.5 + 0.1, 0.0); + return vec4(perp * 0.5 + 0.5, dist * 0.25 + 0.5 + 0.1, 1.0); } else { /* Default line if the origin is perfectly aligned with a pixel. */ - return vec4(1.0, 0.0, 0.5 + 0.1, 0.0); + return vec4(1.0, 0.0, 0.5 + 0.1, 1.0); } } @@ -89,7 +89,14 @@ uniform int baseInstance; # define instanceId gl_InstanceID # endif -# define resource_id (baseInstance + instanceId) +# ifdef UNIFORM_RESOURCE_ID +/* This is in the case we want to do a special instance drawcall but still want to have the + * right resourceId and all the correct ubo datas. */ +uniform int resourceId; +# define resource_id resourceId +# else +# define resource_id (baseInstance + instanceId) +# endif /* Use this to declare and pass the value if * the fragment shader uses the resource_id. */ diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index 2ec1634fa38..f5c0548eaa1 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -5089,24 +5089,32 @@ void ANIM_channel_draw_widgets(const bContext *C, } MEM_freeN(gp_rna_path); - /* Mask Layer. */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); - prop = RNA_struct_find_property(&ptr, "mask_layer"); - gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop); - if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) { - icon = (gpl->flag & GP_LAYER_USE_MASK) ? ICON_MOD_MASK : ICON_LAYER_ACTIVE; - uiDefAutoButR(block, - &ptr, - prop, - array_index, - "", - icon, - offset + (width * 3), - ymid, - width, - channel_height); + /* Mask Layer. */ + UI_block_emboss_set(block, UI_EMBOSS_NONE); + prop = RNA_struct_find_property(&ptr, "mask_layer"); + gp_rna_path = RNA_path_from_ID_to_property(&ptr, prop); + if (RNA_path_resolve_property(&id_ptr, gp_rna_path, &ptr, &prop)) { + icon = ICON_LAYER_ACTIVE; + if (gpl->flag & GP_LAYER_USE_MASK) { + if (gpl->flag & GP_LAYER_MASK_INVERT) { + icon = ICON_HOLDOUT_ON; + } + else { + icon = ICON_MOD_MASK; + } } - MEM_freeN(gp_rna_path); + uiDefAutoButR(block, + &ptr, + prop, + array_index, + "", + icon, + offset + (width * 3), + ymid, + width, + channel_height); + } + MEM_freeN(gp_rna_path); /* Layer onion skinning switch. */ prop = RNA_struct_find_property(&ptr, "use_onion_skinning"); diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index e90289de963..ede32b5d08e 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3135,7 +3135,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, if (gpl->flag & GP_LAYER_SELECT) { ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER); /* update other layer status */ - BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_active_set(gpd, gpl); BKE_gpencil_layer_autolock_set(gpd, false); DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); } diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 4162e92cfea..c9e3335d142 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -299,7 +299,7 @@ void ED_armature_bone_rename(Main *bmain, if (ob->type == OB_GPENCIL) { bGPdata *gpd = (bGPdata *)ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if ((gpl->parent != NULL) && (gpl->parent->data == arm)) { if (STREQ(gpl->parsubstr, oldname)) { BLI_strncpy(gpl->parsubstr, newname, MAXBONENAME); diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index 6e91be862a9..4368a6256bb 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -33,6 +33,7 @@ #include "BLI_sys_types.h" #include "BLI_math.h" +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLF_api.h" @@ -562,7 +563,7 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd), { GPU_program_point_size(true); - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* check if stroke can be drawn */ if (annotation_can_draw_stroke(gps, dflag) == false) { continue; @@ -625,7 +626,7 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd), } /* Draw selected verts for strokes being edited */ -static void annotation_draw_strokes_edit(bGPdata *gpd, +static void annotation_draw_strokes_edit(bGPdata *UNUSED(gpd), bGPDlayer *gpl, const bGPDframe *gpf, int offsx, @@ -660,7 +661,7 @@ static void annotation_draw_strokes_edit(bGPdata *gpd, GPU_program_point_size(true); /* draw stroke verts */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* check if stroke can be drawn */ if (annotation_can_draw_stroke(gps, dflag) == false) { continue; @@ -689,6 +690,9 @@ static void annotation_draw_strokes_edit(bGPdata *gpd, vsize = bsize + 2; } + /* Why? */ + UNUSED_VARS(vsize); + float selectColor[4]; UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); selectColor[3] = alpha; @@ -709,31 +713,12 @@ static void annotation_draw_strokes_edit(bGPdata *gpd, 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 */ - immAttr3f(color, 0.0f, 1.0f, 0.0f); - immAttr1f(size, vsize + 4); - } - else if (show_direction_hint && (i == gps->totpoints - 1)) { - /* end point in red smaller */ - immAttr3f(color, 1.0f, 0.0f, 0.0f); - immAttr1f(size, vsize + 1); - } - else if (pt->flag & GP_SPOINT_SELECT) { - immAttr3fv(color, selectColor); - immAttr1f(size, vsize); - } - else { - immAttr3fv(color, gpl->color); - immAttr1f(size, bsize); - } + immAttr3fv(color, gpl->color); + immAttr1f(size, bsize); /* then position */ if (gps->flag & GP_STROKE_3DSPACE) { @@ -857,7 +842,7 @@ static void annotation_draw_data_layers( { float ink[4]; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* verify never thickness is less than 1 */ CLAMP_MIN(gpl->thickness, 1.0f); short lthick = gpl->thickness; @@ -872,7 +857,7 @@ static void annotation_draw_data_layers( } /* get frame to draw */ - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, cfra, GP_GETFRAME_USE_PREV); if (gpf == NULL) { continue; } diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 875bdfddcc8..1d654703064 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -534,9 +534,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure pts->pressure = pt->pressure; pts->strength = pt->strength; pts->time = pt->time; - - /* force fill recalc */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; + gps->tot_triangles = 0; } /* increment counters */ @@ -601,15 +599,14 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* copy appropriate settings for stroke */ gps->totpoints = totelem; gps->thickness = gpl->thickness; + gps->fill_opacity_fac = 1.0f; gps->gradient_f = 1.0f; gps->gradient_s[0] = 1.0f; gps->gradient_s[1] = 1.0f; gps->uv_scale = 1.0f; 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_GEOMETRY; + gps->tot_triangles = 0; /* allocate enough memory for a continuous array for storage points */ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); @@ -1205,7 +1202,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps ToolSettings *ts = scene->toolsettings; /* get active layer (or add a new one if non-existent) */ - p->gpl = BKE_gpencil_layer_getactive(p->gpd); + p->gpl = BKE_gpencil_layer_active_get(p->gpd); if (p->gpl == NULL) { /* tag for annotations */ p->gpd->flag |= GP_DATA_ANNOTATIONS; @@ -1233,7 +1230,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps */ bool has_layer_to_erase = false; - if (gpencil_layer_is_editable(p->gpl)) { + if (BKE_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; @@ -1261,7 +1258,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps add_frame_mode = GP_GETFRAME_ADD_NEW; } - p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode); + p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode); if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index fe89ea7321f..888d78e4434 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -283,78 +283,8 @@ static void gp_calc_stroke_text_coordinates(const float (*points2d)[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) -{ - 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 */ - BKE_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 */ - 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; - /* 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(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 { - /* 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_GEOMETRY) { - gps->flag &= ~GP_STROKE_RECALC_GEOMETRY; - } - - /* clear memory */ - MEM_SAFE_FREE(tmp_triangles); - MEM_SAFE_FREE(points2d); - MEM_SAFE_FREE(uv); -} - /* 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, @@ -375,8 +305,8 @@ static void gp_add_filldata_tobuffer(const bGPDspoint *pt, fpt[2] = 0.0f; /* 2d always is z=0.0f */ } - immAttr2f(texcoord, uv[0], uv[1]); /* texture coordinates */ - immVertex3fv(pos, fpt); /* position */ + immAttr2f(texcoord, pt->uv_fill[0], pt->uv_fill[1]); /* texture coordinates */ + immVertex3fv(pos, fpt); /* position */ } /* draw fills for shapes */ @@ -390,18 +320,12 @@ static void gp_draw_stroke_fill(bGPdata *gpd, const float color[4]) { BLI_assert(gps->totpoints >= 3); + BLI_assert(gps->tot_triangles >= 1); const bool use_mat = (gpd->mat != NULL); Material *ma = (use_mat) ? gpd->mat[gps->mat_nr] : BKE_material_default_gpencil(); MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL; - /* Calculate triangles cache for filling area (must be done only after changes) */ - if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (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); @@ -414,7 +338,6 @@ static void gp_draw_stroke_fill(bGPdata *gpd, 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); @@ -422,8 +345,8 @@ static void gp_draw_stroke_fill(bGPdata *gpd, 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_FILL_TEX_MIX) != 0); - immUniform1i("t_flip", (gp_style->flag & GP_STYLE_COLOR_FLIP_FILL) != 0); + immUniform1i("t_mix", (gp_style->flag & GP_MATERIAL_FILL_TEX_MIX) != 0); + immUniform1i("t_flip", (gp_style->flag & GP_MATERIAL_FLIP_FILL) != 0); /* Draw all triangles for filling the polygon (cache must be calculated before) */ immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3); @@ -433,7 +356,6 @@ static void gp_draw_stroke_fill(bGPdata *gpd, 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, @@ -843,15 +765,15 @@ static void gp_draw_strokes(tGPDdraw *tgpw) Material *ma = (use_mat) ? tgpw->gpd->mat[gps->mat_nr] : BKE_material_default_gpencil(); MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL; - if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE) || + if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE) || /* if onion and ghost flag do not draw*/ - (tgpw->onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) { + (tgpw->onion && (gp_style->flag & GP_MATERIAL_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) && (gp_style->flag & GP_STYLE_FILL_SHOW)) { + ((gps->flag & GP_STROKE_NOFILL) == 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW)) { continue; } @@ -936,7 +858,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) } } - if (gp_style->mode == GP_STYLE_MODE_DOTS) { + if (gp_style->mode == GP_MATERIAL_MODE_DOT) { /* volumetric stroke drawing */ if (tgpw->disable_fill != 1) { gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, sthickness, ink); @@ -1017,7 +939,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) copy_v4_v4(ink, tcolor); } } - if (gp_style->mode == GP_STYLE_MODE_DOTS) { + if (gp_style->mode == GP_MATERIAL_MODE_DOT) { /* blob/disk-based "volumetric" drawing */ gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, @@ -1072,113 +994,8 @@ static void gp_draw_strokes(tGPDdraw *tgpw) /* ----- General Drawing ------ */ -/* draw interpolate strokes (used only while operator is running) */ -void ED_gp_draw_interpolation(const bContext *C, tGPDinterpolate *tgpi, const int type) -{ - tGPDdraw tgpw; - ARegion *ar = CTX_wm_region(C); - RegionView3D *rv3d = ar->regiondata; - tGPDinterpolate_layer *tgpil; - Object *obact = CTX_data_active_object(C); - /* Drawing code is expected to run with fully evaluated depsgraph. */ - Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C); - - float color[4]; - - 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); - } - - 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(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; - tgpw.gps = NULL; - - tgpw.lthick = tgpil->gpl->line_change; - tgpw.opacity = 1.0; - copy_v4_v4(tgpw.tintcolor, color); - tgpw.onion = true; - tgpw.custonion = true; - if (obact->totcol == 0) { - tgpw.gpd->mat = NULL; - } - - 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); } - -/* draw a short status message in the top-right corner */ -static void UNUSED_FUNCTION(gp_draw_status_text)(const bGPdata *gpd, ARegion *ar) -{ - - /* Cannot draw any status text when drawing OpenGL Renders */ - if (G.f & G_FLAG_RENDER_VIEWPORT) { - return; - } - - /* Get bounds of region - Necessary to avoid problems with region overlap. */ - const rcti *rect = ED_region_visible_rect(ar); - - /* 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); - } -} diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index f4636e81966..83165fd4930 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -58,15 +58,13 @@ /* Loops over the gp-frames for a gp-layer, and applies the given callback */ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *)) { - bGPDframe *gpf; - /* error checker */ if (gpl == NULL) { return false; } /* do loop */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* execute callback */ if (gpf_cb(gpf, scene)) { return true; @@ -83,7 +81,6 @@ bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPD /* make a listing all the gp-frames in a layer as cfraelems */ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) { - bGPDframe *gpf; CfraElem *ce; /* error checking */ @@ -92,7 +89,7 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) } /* loop through gp-frames, adding */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) { ce = MEM_callocN(sizeof(CfraElem), "CfraElem"); @@ -110,15 +107,13 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel) /* check if one of the frames in this layer is selected */ bool ED_gplayer_frame_select_check(bGPDlayer *gpl) { - bGPDframe *gpf; - /* error checking */ if (gpl == NULL) { return false; } /* stop at the first one found */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (gpf->flag & GP_FRAME_SELECT) { return true; } @@ -151,15 +146,13 @@ static void gpframe_select(bGPDframe *gpf, short select_mode) /* set all/none/invert select (like above, but with SELECT_* modes) */ void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode) { - bGPDframe *gpf; - /* error checking */ if (gpl == NULL) { return; } /* handle according to mode */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { gpframe_select(gpf, select_mode); } } @@ -185,7 +178,7 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode) return; } - gpf = BKE_gpencil_layer_find_frame(gpl, selx); + gpf = BKE_gpencil_layer_frame_find(gpl, selx); if (gpf) { gpframe_select(gpf, select_mode); @@ -195,14 +188,12 @@ void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode) /* select the frames in this layer that occur within the bounds specified */ void ED_gplayer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode) { - bGPDframe *gpf; - if (gpl == NULL) { return; } /* only select those frames which are in bounds */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (IN_RANGE(gpf->framenum, min, max)) { gpframe_select(gpf, select_mode); } @@ -215,14 +206,12 @@ void ED_gplayer_frames_select_region(KeyframeEditData *ked, short tool, short select_mode) { - bGPDframe *gpf; - if (gpl == NULL) { return; } /* only select frames which are within the region */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* construct a dummy point coordinate to do this testing with */ float pt[2] = {0}; @@ -264,7 +253,7 @@ bool ED_gplayer_frames_delete(bGPDlayer *gpl) gpfn = gpf->next; if (gpf->flag & GP_FRAME_SELECT) { - BKE_gpencil_layer_delframe(gpl, gpf); + BKE_gpencil_layer_frame_delete(gpl, gpf); changed = true; } } @@ -304,13 +293,11 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl) */ void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type) { - bGPDframe *gpf; - if (gpl == NULL) { return; } - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { if (gpf->flag & GP_FRAME_SELECT) { gpf->key_type = type; } @@ -370,10 +357,9 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac) for (ale = anim_data.first; ale; ale = ale->next) { ListBase copied_frames = {NULL, NULL}; bGPDlayer *gpl = (bGPDlayer *)ale->data; - bGPDframe *gpf; /* loop over frames, and copy only selected frames */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* if frame is selected, make duplicate it and its strokes */ if (gpf->flag & GP_FRAME_SELECT) { /* make a copy of this frame */ @@ -489,7 +475,7 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) gpfs->framenum += offset; /* get frame to copy data into (if no frame returned, then just ignore) */ - gpf = BKE_gpencil_layer_getframe(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW); + gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW); if (gpf) { bGPDstroke *gps, *gpsn; @@ -502,21 +488,15 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) */ for (gps = gpfs->strokes.first; gps; gps = gps->next) { /* make a copy of stroke, then of its points array */ - gpsn = MEM_dupallocN(gps); - gpsn->points = MEM_dupallocN(gps->points); - if (gps->dvert != NULL) { - gpsn->dvert = MEM_dupallocN(gps->dvert); - BKE_gpencil_stroke_weights_duplicate(gps, gpsn); - } - /* duplicate triangle information */ - gpsn->triangles = MEM_dupallocN(gps->triangles); + gpsn = BKE_gpencil_stroke_duplicate(gps, true); + /* append stroke to frame */ BLI_addtail(&gpf->strokes, gpsn); } /* if no strokes (i.e. new frame) added, free gpf */ if (BLI_listbase_is_empty(&gpf->strokes)) { - BKE_gpencil_layer_delframe(gpld, gpf); + BKE_gpencil_layer_frame_delete(gpld, gpf); } } diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index 7dc3aa1273f..2d481bed971 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -66,17 +66,20 @@ static int gpencil_monkey_color( ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx); copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); + srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba); + copy_v4_v4(ma->gp_style->fill_rgba, pct->fill); + srgb_to_linearrgb_v4(ma->gp_style->fill_rgba, ma->gp_style->fill_rgba); if (!stroke) { - ma->gp_style->flag &= ~GP_STYLE_STROKE_SHOW; + ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; } if (!fill) { - ma->gp_style->flag &= ~GP_STYLE_FILL_SHOW; + ma->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; } else { - ma->gp_style->flag |= GP_STYLE_FILL_SHOW; + ma->gp_style->flag |= GP_MATERIAL_FILL_SHOW; } return idx; @@ -855,89 +858,117 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4]) bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, CFRA); /* generate strokes */ - gps = BKE_gpencil_add_stroke(frameFills, color_Skin, 270, 75); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false); BKE_gpencil_stroke_add_points(gps, data0, 270, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data1, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 60, false); BKE_gpencil_stroke_add_points(gps, data2, 18, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false); BKE_gpencil_stroke_add_points(gps, data3, 64, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data4, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 64, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 64, 60, false); BKE_gpencil_stroke_add_points(gps, data5, 64, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 33, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data6, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Light, 18, 40); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Light, 18, 40, false); BKE_gpencil_stroke_add_points(gps, data7, 18, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false); BKE_gpencil_stroke_add_points(gps, data8, 49, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 33, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data9, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Eyes, 49, 60); + gps = BKE_gpencil_stroke_add(frameFills, color_Eyes, 49, 60, false); BKE_gpencil_stroke_add_points(gps, data10, 49, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false); BKE_gpencil_stroke_add_points(gps, data11, 18, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameFills, color_Skin_Shadow, 18, 40); + gps = BKE_gpencil_stroke_add(frameFills, color_Skin_Shadow, 18, 40, false); BKE_gpencil_stroke_add_points(gps, data12, 18, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data13, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data14, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 65, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 65, 60, false); BKE_gpencil_stroke_add_points(gps, data15, 65, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 60, false); BKE_gpencil_stroke_add_points(gps, data16, 34, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data17, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 40); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 40, false); BKE_gpencil_stroke_add_points(gps, data18, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 34, 40); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 34, 40, false); BKE_gpencil_stroke_add_points(gps, data19, 34, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data20, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 64, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 64, 60, false); BKE_gpencil_stroke_add_points(gps, data21, 64, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false); BKE_gpencil_stroke_add_points(gps, data22, 26, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Pupils, 26, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Pupils, 26, 60, false); BKE_gpencil_stroke_add_points(gps, data23, 26, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data24, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false); BKE_gpencil_stroke_add_points(gps, data25, 18, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 18, 40); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 18, 40, false); BKE_gpencil_stroke_add_points(gps, data26, 18, mat); + BKE_gpencil_stroke_geometry_update(gps); - gps = BKE_gpencil_add_stroke(frameLines, color_Black, 33, 60); + gps = BKE_gpencil_stroke_add(frameLines, color_Black, 33, 60, false); BKE_gpencil_stroke_add_points(gps, data27, 33, mat); + BKE_gpencil_stroke_geometry_update(gps); /* update depsgraph */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index 539f80846fd..f1678e11eb0 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -65,10 +65,13 @@ static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct, ma = BKE_gpencil_object_material_new(bmain, ob, pct->name, &idx); copy_v4_v4(ma->gp_style->stroke_rgba, pct->line); + srgb_to_linearrgb_v4(ma->gp_style->stroke_rgba, ma->gp_style->stroke_rgba); + copy_v4_v4(ma->gp_style->fill_rgba, pct->fill); + srgb_to_linearrgb_v4(ma->gp_style->fill_rgba, ma->gp_style->fill_rgba); if (fill) { - ma->gp_style->flag |= GP_STYLE_FILL_SHOW; + ma->gp_style->flag |= GP_MATERIAL_FILL_SHOW; } return idx; @@ -240,8 +243,9 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4]) UNUSED_VARS(frame_color); /* generate stroke */ - gps = BKE_gpencil_add_stroke(frame_lines, color_black, 175, 75); + gps = BKE_gpencil_stroke_add(frame_lines, color_black, 175, 75, false); BKE_gpencil_stroke_add_points(gps, data0, 175, mat); + BKE_gpencil_stroke_geometry_update(gps); /* update depsgraph */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index 9e70be323eb..bbc9f486f80 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -357,7 +357,7 @@ static void gpencil_add_verts_to_dgroups( } /* loop all strokes */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe; bGPDspoint *pt = NULL; @@ -368,7 +368,7 @@ static void gpencil_add_verts_to_dgroups( continue; } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index d26d5a8a7d8..54f8b749199 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -174,7 +174,7 @@ static void gp_strokepoint_convertcoords(bContext *C, /* apply parent transform */ float fpt[3]; - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); mul_v3_m4v3(fpt, diff_mat, &source_pt->x); copy_v3_v3(&pt->x, fpt); @@ -1270,7 +1270,7 @@ static void gp_layer_to_curve(bContext *C, Collection *collection = CTX_data_collection(C); Scene *scene = CTX_data_scene(C); - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); bGPDstroke *gps, *prev_gps = NULL; Object *ob; Curve *cu; @@ -1410,7 +1410,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, GP_GETFRAME_USE_PREV)) || + if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) || !(gps = gpf->strokes.first)) { return false; } @@ -1476,8 +1476,8 @@ static bool gp_convert_poll(bContext *C) /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!), * and if we are not in edit mode! */ - return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_getactive(gpd)) && - (gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV)) && + return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) && + (gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) && (gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd))); } @@ -1487,7 +1487,7 @@ static int gp_convert_layer_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); bGPdata *gpd = (bGPdata *)ob->data; - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); Scene *scene = CTX_data_scene(C); const int mode = RNA_enum_get(op->ptr, "type"); const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights"); @@ -1785,7 +1785,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op) /* Create material slot. */ Material *ma = BKE_gpencil_object_material_new(bmain, ob, "Image Material", NULL); MaterialGPencilStyle *gp_style = ma->gp_style; - gp_style->mode = GP_STYLE_MODE_BOX; + gp_style->mode = GP_MATERIAL_MODE_SQUARE; /* Add layer and frame. */ bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index a8e7c40c031..b708039018f 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -292,7 +292,7 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op) bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) : ED_annotation_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); /* sanity checks */ if (ELEM(NULL, gpd, gpl)) { @@ -309,10 +309,10 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op) * - if this is the only layer, this naturally becomes NULL */ if (gpl->prev) { - BKE_gpencil_layer_setactive(gpd, gpl->prev); + BKE_gpencil_layer_active_set(gpd, gpl->prev); } else { - BKE_gpencil_layer_setactive(gpd, gpl->next); + BKE_gpencil_layer_active_set(gpd, gpl->next); } /* delete the layer now... */ @@ -342,7 +342,7 @@ void GPENCIL_OT_layer_remove(wmOperatorType *ot) static bool gp_active_layer_annotation_poll(bContext *C) { bGPdata *gpd = ED_annotation_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); return (gpl != NULL); } @@ -373,7 +373,7 @@ static int gp_layer_move_exec(bContext *C, wmOperator *op) bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) : ED_annotation_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); const int direction = RNA_enum_get(op->ptr, "type") * -1; @@ -441,7 +441,7 @@ void GPENCIL_OT_layer_annotation_move(wmOperatorType *ot) static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); bGPDlayer *new_layer; /* sanity checks */ @@ -460,7 +460,7 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op)) '.', offsetof(bGPDlayer, info), sizeof(new_layer->info)); - BKE_gpencil_layer_setactive(gpd, new_layer); + BKE_gpencil_layer_active_set(gpd, new_layer); /* notifiers */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -499,7 +499,7 @@ static bool gp_layer_duplicate_object_poll(bContext *C) } bGPdata *gpd = (bGPdata *)ob->data; - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); if (gpl == NULL) { return false; @@ -532,7 +532,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op) Object *ob_src = CTX_data_active_object(C); bGPdata *gpd_src = (bGPdata *)ob_src->data; - bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src); + bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd_src); /* Sanity checks. */ if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) { @@ -568,7 +568,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op) for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) { /* Make copy of source stroke. */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true); /* Check if material is in destination object, * otherwise add the slot with the material. */ @@ -630,7 +630,7 @@ enum { 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); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); Scene *scene = CTX_data_scene(C); int mode = RNA_enum_get(op->ptr, "mode"); @@ -644,7 +644,7 @@ static int gp_frame_duplicate_exec(bContext *C, wmOperator *op) BKE_gpencil_frame_addcopy(gpl, CFRA); } else { - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if ((gpl->flag & GP_LAYER_LOCKED) == 0) { BKE_gpencil_frame_addcopy(gpl, CFRA); } @@ -861,7 +861,7 @@ void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot) static int gp_hide_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *layer = BKE_gpencil_layer_active_get(gpd); bool unselected = RNA_boolean_get(op->ptr, "unselected"); /* sanity checks */ @@ -870,10 +870,8 @@ static int gp_hide_exec(bContext *C, wmOperator *op) } if (unselected) { - bGPDlayer *gpl; - /* hide unselected */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl != layer) { gpl->flag |= GP_LAYER_HIDE; } @@ -946,7 +944,6 @@ static void gp_reveal_select_frame(bContext *C, bGPDframe *frame, bool select) static int gp_reveal_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl; const bool select = RNA_boolean_get(op->ptr, "select"); /* sanity checks */ @@ -954,8 +951,7 @@ static int gp_reveal_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->flag & GP_LAYER_HIDE) { gpl->flag &= ~GP_LAYER_HIDE; @@ -1008,7 +1004,6 @@ void GPENCIL_OT_reveal(wmOperatorType *ot) static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl; /* sanity checks */ if (gpd == NULL) { @@ -1016,7 +1011,7 @@ static int gp_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) } /* make all layers non-editable */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpl->flag |= GP_LAYER_LOCKED; } @@ -1048,7 +1043,6 @@ void GPENCIL_OT_lock_all(wmOperatorType *ot) static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl; /* sanity checks */ if (gpd == NULL) { @@ -1056,7 +1050,7 @@ static int gp_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) } /* make all layers editable again */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpl->flag &= ~GP_LAYER_LOCKED; } @@ -1087,8 +1081,7 @@ void GPENCIL_OT_unlock_all(wmOperatorType *ot) static int gp_isolate_layer_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *layer = BKE_gpencil_layer_getactive(gpd); - bGPDlayer *gpl; + bGPDlayer *layer = BKE_gpencil_layer_active_get(gpd); int flags = GP_LAYER_LOCKED; bool isolate = false; @@ -1102,7 +1095,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op) } /* Test whether to isolate or clear all flags */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Skip if this is the active layer */ if (gpl == layer) { continue; @@ -1121,7 +1114,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op) /* TODO: Include onion-skinning on this list? */ if (isolate) { /* Set flags on all "other" layers */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl == layer) { continue; } @@ -1132,7 +1125,7 @@ static int gp_isolate_layer_exec(bContext *C, wmOperator *op) } else { /* Clear flags - Restore everything else */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { gpl->flag &= ~flags; } } @@ -1172,7 +1165,7 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot) static int gp_merge_layer_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl_next = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl_next = BKE_gpencil_layer_active_get(gpd); bGPDlayer *gpl_current = gpl_next->prev; if (ELEM(NULL, gpd, gpl_current, gpl_next)) { @@ -1191,7 +1184,7 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op) /* try to find frame in current layer */ bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum)); if (!frame) { - bGPDframe *actframe = BKE_gpencil_layer_getframe( + bGPDframe *actframe = BKE_gpencil_layer_frame_get( gpl_current, gpf->framenum, GP_GETFRAME_USE_PREV); frame = BKE_gpencil_frame_addnew(gpl_current, gpf->framenum); /* duplicate strokes of current active frame */ @@ -1268,7 +1261,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op) } /* Set active layer */ - BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_active_set(gpd, gpl); /* updates */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -1312,7 +1305,7 @@ 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_act = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl_act = BKE_gpencil_layer_active_get(gpd); /* sanity checks */ if (ELEM(NULL, gpd, gpl_act, gpl_act->actframe)) { @@ -1469,7 +1462,7 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *op) } } /* try to find slot */ - int idx = BKE_gpencil_object_material_get_index(ob, ma); + int idx = BKE_gpencil_object_material_index_get(ob, ma); if (idx < 0) { return OPERATOR_CANCELLED; } @@ -1494,7 +1487,7 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *op) continue; } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* only if selected */ if (gps->flag & GP_STROKE_SELECT) { /* skip strokes that are invalid for current view */ @@ -1562,15 +1555,15 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { Material *tmp_ma = BKE_object_material_get(ob, i + 1); if (tmp_ma) { - tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED; + tmp_ma->gp_style->flag |= GP_MATERIAL_LOCKED; DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE); } } /* loop all selected strokes and unlock any color */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_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) { @@ -1581,7 +1574,7 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) /* unlock color */ Material *tmp_ma = BKE_object_material_get(ob, gps->mat_nr + 1); if (tmp_ma) { - tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; + tmp_ma->gp_style->flag &= ~GP_MATERIAL_LOCKED; DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE); } } @@ -1631,25 +1624,33 @@ static int gp_brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) case CTX_MODE_PAINT_GPENCIL: { Paint *paint = &ts->gp_paint->paint; brush = paint->brush; - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + if (brush && brush->gpencil_settings) { + BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + } break; } case CTX_MODE_SCULPT_GPENCIL: { Paint *paint = &ts->gp_sculptpaint->paint; brush = paint->brush; - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + if (brush && brush->gpencil_settings) { + BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + } break; } case CTX_MODE_WEIGHT_GPENCIL: { Paint *paint = &ts->gp_weightpaint->paint; brush = paint->brush; - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + if (brush && brush->gpencil_settings) { + BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + } break; } case CTX_MODE_VERTEX_GPENCIL: { Paint *paint = &ts->gp_vertexpaint->paint; brush = paint->brush; - BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + if (brush && brush->gpencil_settings) { + BKE_gpencil_brush_preset_set(bmain, brush, brush->gpencil_settings->preset_type); + } break; } default: @@ -1677,7 +1678,7 @@ void GPENCIL_OT_brush_reset(wmOperatorType *ot) } static Brush *gp_brush_get_first_by_mode(Main *bmain, - Paint *paint, + Paint *UNUSED(paint), const enum eContextObjectMode mode, char tool) { @@ -1802,9 +1803,9 @@ static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op)) break; } + char tool = '0'; if (paint) { Brush *brush_active = paint->brush; - char tool = '0'; if (brush_active) { switch (mode) { case CTX_MODE_PAINT_GPENCIL: { @@ -1831,7 +1832,29 @@ static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op)) } gp_brush_delete_mode_brushes(bmain, paint, mode); - BKE_brush_gpencil_paint_presets(bmain, ts); + + switch (mode) { + case CTX_MODE_PAINT_GPENCIL: { + BKE_brush_gpencil_paint_presets(bmain, ts); + break; + } + case CTX_MODE_SCULPT_GPENCIL: { + BKE_brush_gpencil_sculpt_presets(bmain, ts); + break; + } + case CTX_MODE_WEIGHT_GPENCIL: { + BKE_brush_gpencil_weight_presets(bmain, ts); + break; + } + case CTX_MODE_VERTEX_GPENCIL: { + BKE_brush_gpencil_vertex_presets(bmain, ts); + break; + } + default: { + break; + } + } + BKE_paint_toolslots_brush_validate(bmain, paint); /* Set Again the first brush of the mode. */ @@ -2538,9 +2561,9 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) defgroup_unique_name(vgroup, ob_active); BLI_addtail(&ob_active->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) { + LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_src->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { MDeformVert *dvert; int i; for (i = 0, dvert = gps->dvert; i < gps->totpoints; i++, dvert++) { @@ -2587,12 +2610,12 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) float inverse_diff_mat[4][4]; /* recalculate all stroke points */ - ED_gpencil_parent_location(depsgraph, ob_iter, gpd_src, gpl_src, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, ob_iter, gpl_src, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); Material *ma_src = NULL; for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* Reassign material. Look old material and try to find in destination. */ ma_src = BKE_gpencil_material(ob_src, gps->mat_nr + 1); @@ -2707,16 +2730,16 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) ma = BKE_gpencil_material(ob, i + 1); if (ma) { gp_style = ma->gp_style; - gp_style->flag |= GP_STYLE_COLOR_LOCKED; - gp_style->flag |= GP_STYLE_COLOR_HIDE; + gp_style->flag |= GP_MATERIAL_LOCKED; + gp_style->flag |= GP_MATERIAL_HIDE; DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); } } /* loop all selected strokes and unlock any color used in active layer */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL) && (gpl->flag & GP_LAYER_ACTIVE)) { for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) { /* skip strokes that are invalid for current view */ @@ -2730,8 +2753,8 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) gp_style = ma->gp_style; /* unlock/unhide color if not unlocked before */ if (gp_style != NULL) { - gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; - gp_style->flag &= ~GP_STYLE_COLOR_HIDE; + gp_style->flag &= ~GP_MATERIAL_LOCKED; + gp_style->flag &= ~GP_MATERIAL_HIDE; } } } @@ -2771,11 +2794,11 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) MaterialGPencilStyle *active_color = BKE_gpencil_material_settings(ob, ob->actcol); MaterialGPencilStyle *gp_style; - int flags = GP_STYLE_COLOR_LOCKED; + int flags = GP_MATERIAL_LOCKED; bool isolate = false; if (RNA_boolean_get(op->ptr, "affect_visibility")) { - flags |= GP_STYLE_COLOR_HIDE; + flags |= GP_MATERIAL_HIDE; } if (ELEM(NULL, gpd, active_color)) { @@ -2893,7 +2916,7 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op) if (ma) { color = ma->gp_style; if (active_color != color) { - color->flag |= GP_STYLE_COLOR_HIDE; + color->flag |= GP_MATERIAL_HIDE; DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); } } @@ -2901,7 +2924,7 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op) } else { /* hide selected/active */ - active_color->flag |= GP_STYLE_COLOR_HIDE; + active_color->flag |= GP_MATERIAL_HIDE; } /* updates */ @@ -2955,7 +2978,7 @@ static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op)) ma = BKE_gpencil_material(ob, i + 1); if (ma) { gp_style = ma->gp_style; - gp_style->flag &= ~GP_STYLE_COLOR_HIDE; + gp_style->flag &= ~GP_MATERIAL_HIDE; DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); } } @@ -3008,7 +3031,7 @@ static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) ma = BKE_gpencil_material(ob, i + 1); if (ma) { gp_style = ma->gp_style; - gp_style->flag |= GP_STYLE_COLOR_LOCKED; + gp_style->flag |= GP_MATERIAL_LOCKED; DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); } } @@ -3061,7 +3084,7 @@ static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) ma = BKE_gpencil_material(ob, i + 1); if (ma) { gp_style = ma->gp_style; - gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; + gp_style->flag &= ~GP_MATERIAL_LOCKED; DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); } } @@ -3116,7 +3139,7 @@ static int gpencil_color_select_exec(bContext *C, wmOperator *op) if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { /* verify something to do */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 2b22d807f2a..781e431841c 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -775,23 +775,17 @@ static void gp_duplicate_points(const bGPDstroke *gps, else if (i == gps->totpoints - 1) { len = i - start_idx + 1; } - // printf("copying from %d to %d = %d\n", start_idx, i, len); /* make copies of the relevant data */ if (len) { bGPDstroke *gpsd; /* make a stupid copy first of the entire stroke (to get the flags too) */ - gpsd = MEM_dupallocN(gps); + gpsd = BKE_gpencil_stroke_duplicate((bGPDstroke *)gps, false); /* saves original layer name */ BLI_strncpy(gpsd->runtime.tmp_layerinfo, layername, sizeof(gpsd->runtime.tmp_layerinfo)); - /* initialize triangle memory - will be calculated on next redraw */ - gpsd->triangles = NULL; - gpsd->flag |= GP_STROKE_RECALC_GEOMETRY; - gpsd->tot_triangles = 0; - /* now, make a new points array, and copy of the relevant parts */ gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy"); memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len); @@ -811,8 +805,11 @@ static void gp_duplicate_points(const bGPDstroke *gps, } } + BKE_gpencil_stroke_geometry_update(gpsd); + /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; + BLI_addtail(new_strokes, gpsd); /* cleanup + reset for next */ @@ -862,17 +859,12 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op) bGPDstroke *gpsd; /* make direct copies of the stroke and its points */ - gpsd = MEM_dupallocN(gps); + gpsd = BKE_gpencil_stroke_duplicate(gps, true); + 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_GEOMETRY; - gpsd->triangles = NULL; + /* Initialize triangle information. */ + BKE_gpencil_stroke_geometry_update(gpsd); /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; @@ -943,7 +935,7 @@ static void copy_move_point(bGPDstroke *gps, pt_final->flag = pt->flag; pt_final->uv_fac = pt->uv_fac; pt_final->uv_rot = pt->uv_rot; - copy_v4_v4(pt_final->mix_color, pt->mix_color); + copy_v4_v4(pt_final->vert_color, pt->vert_color); if (gps->dvert != NULL) { MDeformVert *dvert = &temp_dverts[from_idx]; @@ -981,7 +973,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) pt = &gps->points[i]; if (pt->flag == GP_SPOINT_SELECT) { /* duplicate original stroke data */ - bGPDstroke *gps_new = MEM_dupallocN(gps); + bGPDstroke *gps_new = BKE_gpencil_stroke_duplicate(gps, false); gps_new->prev = gps_new->next = NULL; /* add new points array */ @@ -993,14 +985,15 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) gps_new->dvert = MEM_callocN(sizeof(MDeformVert), __func__); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps_new->triangles = NULL; - gps_new->tot_triangles = 0; BLI_insertlinkafter(&gpf->strokes, gps, gps_new); /* copy selected point data to new stroke */ copy_move_point(gps_new, gps->points, gps->dvert, i, 0, true); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + BKE_gpencil_stroke_geometry_update(gps_new); + /* deselect orinal point */ pt->flag &= ~GP_SPOINT_SELECT; } @@ -1043,7 +1036,6 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) copy_move_point(gps, temp_points, temp_dverts, i, i2, false); i2++; } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; /* If first point, add new point at the beginning. */ if (do_first) { @@ -1068,6 +1060,9 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) pt->flag |= GP_SPOINT_SELECT; } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + MEM_SAFE_FREE(temp_points); MEM_SAFE_FREE(temp_dverts); } @@ -1307,7 +1302,8 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) bGPDstroke *gpsd; /* make direct copies of the stroke and its points */ - gpsd = MEM_dupallocN(gps); + gpsd = BKE_gpencil_stroke_duplicate(gps, false); + /* saves original layer name */ BLI_strncpy(gpsd->runtime.tmp_layerinfo, gpl->info, sizeof(gpsd->runtime.tmp_layerinfo)); gpsd->points = MEM_dupallocN(gps->points); @@ -1316,10 +1312,8 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) BKE_gpencil_stroke_weights_duplicate(gps, gpsd); } - /* triangles cache - will be recalculated on next redraw */ - gpsd->flag |= GP_STROKE_RECALC_GEOMETRY; - gpsd->tot_triangles = 0; - gpsd->triangles = NULL; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gpsd); /* add to temp buffer */ gpsd->next = gpsd->prev = NULL; @@ -1429,7 +1423,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) /* no active layer - let's just create one */ gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true); } - else if ((gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_TO_ACTIVE)) { + else if ((BKE_gpencil_layer_is_editable(gpl) == false) && (type == GP_COPY_TO_ACTIVE)) { BKE_report( op->reports, RPT_ERROR, "Can not paste strokes when active layer is hidden or locked"); return OPERATOR_CANCELLED; @@ -1495,10 +1489,10 @@ 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, GP_GETFRAME_ADD_NEW); + gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); if (gpf) { /* Create new stroke */ - bGPDstroke *new_stroke = MEM_dupallocN(gps); + bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, false); new_stroke->runtime.tmp_layerinfo[0] = '\0'; new_stroke->points = MEM_dupallocN(gps->points); @@ -1506,15 +1500,15 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op) new_stroke->dvert = MEM_dupallocN(gps->dvert); BKE_gpencil_stroke_weights_duplicate(gps, new_stroke); } - new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY; - new_stroke->triangles = NULL; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(new_stroke); new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); /* Remap material */ Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr)); - new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma); + new_stroke->mat_nr = BKE_gpencil_object_material_index_get(ob, ma); CLAMP_MIN(new_stroke->mat_nr, 0); } } @@ -1625,7 +1619,7 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op) /* Paste them all in one go */ if (strokes.first) { - bGPDframe *gpf = BKE_gpencil_layer_getframe(target_layer, CFRA, GP_GETFRAME_ADD_NEW); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(target_layer, CFRA, GP_GETFRAME_ADD_NEW); BLI_movelisttolist(&gpf->strokes, &strokes); BLI_assert((strokes.first == strokes.last) && (strokes.first == NULL)); @@ -1665,32 +1659,13 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) /* ********************* Add Blank Frame *************************** */ -/* Basically the same as the drawing op */ -static bool UNUSED_FUNCTION(gp_blank_frame_add_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) { - return 1; - } - 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; -} - static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Scene *scene = CTX_data_scene(C); int cfra = CFRA; - bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *active_gpl = BKE_gpencil_layer_active_get(gpd); const bool all_layers = RNA_boolean_get(op->ptr, "all_layers"); @@ -1710,7 +1685,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_frame_find(gpl, cfra); if (gpf) { /* Shunt all frames after (and including) the existing one later by 1-frame */ for (; gpf; gpf = gpf->next) { @@ -1719,7 +1694,7 @@ 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_frame_get(gpl, cfra, GP_GETFRAME_ADD_NEW); } CTX_DATA_END; @@ -1761,7 +1736,7 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot) static bool gp_actframe_delete_poll(bContext *C) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); /* only if there's an active layer with an active frame */ return (gpl && gpl->actframe); @@ -1770,7 +1745,7 @@ static bool gp_actframe_delete_poll(bContext *C) static bool gp_annotation_actframe_delete_poll(bContext *C) { bGPdata *gpd = ED_annotation_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); /* only if there's an active layer with an active frame */ return (gpl && gpl->actframe); @@ -1784,11 +1759,11 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) bGPdata *gpd = (!is_annotation) ? ED_gpencil_data_get_active(C) : ED_annotation_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); Scene *scene = CTX_data_scene(C); - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); /* if there's no existing Grease-Pencil data there, add some */ if (gpd == NULL) { @@ -1801,7 +1776,7 @@ static int gp_actframe_delete_exec(bContext *C, wmOperator *op) } /* delete it... */ - BKE_gpencil_layer_delframe(gpl, gpf); + BKE_gpencil_layer_frame_delete(gpl, gpf); /* notifiers */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -1858,14 +1833,14 @@ static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) 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, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); if (gpf == NULL) { continue; } /* delete it... */ - BKE_gpencil_layer_delframe(gpl, gpf); + BKE_gpencil_layer_frame_delete(gpl, gpf); /* we successfully modified something */ success = true; @@ -2171,9 +2146,8 @@ static int gp_dissolve_selected_points(bContext *C, eGP_DissolveMode mode) gps->dvert = new_dvert; gps->totpoints = tot; - /* triangles cache needs to be recalculated */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); /* deselect the stroke, since none of its selected points will still be selected */ gps->flag &= ~GP_STROKE_SELECT; @@ -2215,7 +2189,7 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst const int totpoints = gps_first->totpoints + gps_last->totpoints; /* create new stroke */ - bGPDstroke *join_stroke = MEM_dupallocN(gps_first); + bGPDstroke *join_stroke = BKE_gpencil_stroke_duplicate(gps_first, false); join_stroke->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, __func__); join_stroke->totpoints = totpoints; @@ -2243,7 +2217,7 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst pt_final->strength = pt->strength; pt_final->time = delta; pt_final->flag = pt->flag; - copy_v4_v4(pt_final->mix_color, pt->mix_color); + copy_v4_v4(pt_final->vert_color, pt->vert_color); /* retiming with fixed time interval (we cannot determine real time) */ delta += 0.01f; @@ -2282,6 +2256,8 @@ static void gp_stroke_join_islands(bGPDframe *gpf, bGPDstroke *gps_first, bGPDst /* add new stroke at head */ BLI_addhead(&gpf->strokes, join_stroke); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(join_stroke); /* remove first stroke */ BLI_remlink(&gpf->strokes, gps_first); @@ -2358,18 +2334,14 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, /* Create each new stroke... */ for (idx = 0; idx < num_islands; idx++) { tGPDeleteIsland *island = &islands[idx]; - new_stroke = MEM_dupallocN(gps); + new_stroke = BKE_gpencil_stroke_duplicate(gps, false); /* if cyclic and first stroke, save to join later */ if ((is_cyclic) && (gps_first == NULL)) { gps_first = new_stroke; } - /* initialize triangle memory - to be calculated on next redraw */ - new_stroke->triangles = NULL; - new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY; new_stroke->flag &= ~GP_STROKE_CYCLIC; - new_stroke->tot_triangles = 0; /* Compute new buffer size (+ 1 needed as the endpoint index is "inclusive") */ new_stroke->totpoints = island->end_idx - island->start_idx + 1; @@ -2432,6 +2404,9 @@ void gp_stroke_delete_tagged_points(bGPDframe *gpf, BKE_gpencil_free_stroke(new_stroke); } else { + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(new_stroke); + if (next_stroke) { BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke); } @@ -2644,16 +2619,16 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) Object *obact = CTX_data_active_object(C); const float gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; /* calculate difference matrix object */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { bGPDspoint *pt; int i; @@ -2721,16 +2696,16 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op) const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); const float *cursor_global = scene->cursor.location; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { bGPDspoint *pt; int i; @@ -2819,16 +2794,16 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) INIT_MINMAX(min, max); /* calculate midpoints from selected points */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; float diff_mat[4][4]; /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { bGPDspoint *pt; int i; @@ -2895,7 +2870,7 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot) static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); /* sanity checks */ if (ELEM(NULL, gpd, gpl, gpl->frames.first)) { @@ -2903,8 +2878,8 @@ static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) } /* loop all strokes */ - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* Apply thickness */ if ((gps->thickness == 0) && (gpl->line_change == 0)) { gps->thickness = gpl->thickness; @@ -2978,8 +2953,8 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) continue; } /* skip hidden or locked colors */ - if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || - (gp_style->flag & GP_STYLE_COLOR_LOCKED)) { + if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) || + (gp_style->flag & GP_MATERIAL_LOCKED)) { continue; } @@ -3003,7 +2978,7 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op) /* Create new geometry. */ if ((gps->flag & GP_STROKE_CYCLIC) && (geometry)) { - BKE_gpencil_close_stroke(gps); + BKE_gpencil_stroke_close(gps); } } @@ -3092,8 +3067,8 @@ static int gp_stroke_caps_set_exec(bContext *C, wmOperator *op) continue; } /* skip hidden or locked colors */ - if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) || - (gp_style->flag & GP_STYLE_COLOR_LOCKED)) { + if (!gp_style || (gp_style->flag & GP_MATERIAL_HIDE) || + (gp_style->flag & GP_MATERIAL_LOCKED)) { continue; } @@ -3173,7 +3148,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) pt.pressure = point->pressure; pt.strength = point->strength; pt.time = point->time; - copy_v4_v4(pt.mix_color, point->mix_color); + copy_v4_v4(pt.vert_color, point->vert_color); /* replace first point with last point */ point2 = &gps->points[end]; @@ -3184,7 +3159,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) point->pressure = point2->pressure; point->strength = point2->strength; point->time = point2->time; - copy_v4_v4(point->mix_color, point2->mix_color); + copy_v4_v4(point->vert_color, point2->vert_color); /* replace last point with first saved before */ point = &gps->points[end]; @@ -3195,7 +3170,7 @@ static void gpencil_flip_stroke(bGPDstroke *gps) point->pressure = pt.pressure; point->strength = pt.strength; point->time = pt.time; - copy_v4_v4(point->mix_color, pt.mix_color); + copy_v4_v4(point->vert_color, pt.vert_color); end--; } @@ -3226,7 +3201,7 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, newpoint->pressure = pressure; newpoint->strength = strength; newpoint->time = point->time + deltatime; - copy_v4_v4(newpoint->mix_color, point->mix_color); + copy_v4_v4(newpoint->vert_color, point->vert_color); if (gps->dvert != NULL) { MDeformVert *dvert = &gps->dvert[idx]; @@ -3300,7 +3275,7 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, 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); + bGPDlayer *activegpl = BKE_gpencil_layer_active_get(gpd); bGPDstroke *gps, *gpsn; Object *ob = CTX_data_active_object(C); @@ -3357,15 +3332,7 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) /* create a new stroke if was not created before (only created if something to join) */ 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_GEOMETRY; + new_stroke = BKE_gpencil_stroke_duplicate(stroke_a, true); /* if new, set current color */ if (type == GP_STROKE_JOINCOPY) { @@ -3379,6 +3346,9 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) /* if join only, delete old strokes */ if (type == GP_STROKE_JOIN) { if (stroke_a) { + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(new_stroke); + BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke); BLI_remlink(&gpf->strokes, stroke_a); BKE_gpencil_free_stroke(stroke_a); @@ -3403,6 +3373,8 @@ static int gp_stroke_join_exec(bContext *C, wmOperator *op) if (activegpl->actframe == NULL) { activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(new_stroke); BLI_addtail(&activegpl->actframe->strokes, new_stroke); } @@ -3463,7 +3435,7 @@ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) continue; } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->flag & GP_STROKE_SELECT) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { @@ -3577,7 +3549,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) GP_REPROJECT_TOP, GP_REPROJECT_CURSOR)) { if (mode != GP_REPROJECT_CURSOR) { - ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin); + ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, origin); } else { copy_v3_v3(origin, scene->cursor.location); @@ -3745,19 +3717,19 @@ static void gp_smooth_stroke(bContext *C, wmOperator *op) /* perform smoothing */ if (smooth_position) { - BKE_gpencil_smooth_stroke(gps, i, factor); + BKE_gpencil_stroke_smooth(gps, i, factor); } if (smooth_strength) { - BKE_gpencil_smooth_stroke_strength(gps, i, factor); + BKE_gpencil_stroke_smooth_strength(gps, i, factor); } if (smooth_thickness) { /* thickness need to repeat process several times */ for (int r2 = 0; r2 < r * 20; r2++) { - BKE_gpencil_smooth_stroke_thickness(gps, i, factor); + BKE_gpencil_stroke_smooth_thickness(gps, i, factor); } } if (smooth_uv) { - BKE_gpencil_smooth_stroke_uv(gps, i, factor); + BKE_gpencil_stroke_smooth_uv(gps, i, factor); } } } @@ -3826,7 +3798,6 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) if (gps->dvert != NULL) { gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; /* loop and interpolate */ i2 = 0; @@ -3840,7 +3811,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) pt_final->strength = pt->strength; pt_final->time = pt->time; pt_final->flag = pt->flag; - copy_v4_v4(pt_final->mix_color, pt->mix_color); + copy_v4_v4(pt_final->vert_color, pt->vert_color); if (gps->dvert != NULL) { dvert = &temp_dverts[i]; @@ -3864,7 +3835,7 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) 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); - interp_v4_v4v4(pt_final->mix_color, pt->mix_color, next->mix_color, 0.5f); + interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f); pt_final->time = interpf(pt->time, next->time, 0.5f); pt_final->flag |= GP_SPOINT_SELECT; @@ -3898,9 +3869,8 @@ static int gp_stroke_subdivide_exec(bContext *C, wmOperator *op) MEM_SAFE_FREE(temp_dverts); } - /* triangles cache needs to be recalculated */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } } GP_EDITABLE_STROKES_END(gpstroke_iter); @@ -3968,7 +3938,7 @@ static int gp_stroke_simplify_exec(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { /* simplify stroke using Ramer-Douglas-Peucker algorithm */ - BKE_gpencil_simplify_stroke(gps, factor); + BKE_gpencil_stroke_simplify(gps, factor); } } GP_EDITABLE_STROKES_END(gpstroke_iter); @@ -4017,7 +3987,7 @@ static int gp_stroke_simplify_fixed_exec(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { for (int i = 0; i < steps; i++) { - BKE_gpencil_simplify_fixed(gps); + BKE_gpencil_stroke_simplify_fixed(gps); } } } @@ -4067,7 +4037,7 @@ static int gp_stroke_sample_exec(bContext *C, wmOperator *op) /* Go through each editable + selected stroke */ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { - BKE_gpencil_sample_stroke(gps, length, true); + BKE_gpencil_stroke_sample(gps, length, true); } } GP_EDITABLE_STROKES_END(gpstroke_iter); @@ -4134,7 +4104,7 @@ static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op)) } if (gps->flag & GP_STROKE_SELECT) { - BKE_gpencil_trim_stroke(gps); + BKE_gpencil_stroke_trim(gps); } } /* if not multiedit, exit loop*/ @@ -4254,7 +4224,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) /* add frame if not created before */ if (gpf_dst == NULL) { - gpf_dst = BKE_gpencil_layer_getframe(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW); + gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf->framenum, GP_GETFRAME_ADD_NEW); } /* add duplicate materials */ @@ -4267,7 +4237,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) /* selected points mode */ if (mode == GP_SEPARATE_POINT) { /* make copy of source stroke */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps); + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true); /* Reassign material. */ gps_dst->mat_nr = idx; @@ -4315,10 +4285,10 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) if (gpl) { /* try to set a new active layer in source datablock */ if (gpl->prev) { - BKE_gpencil_layer_setactive(gpd_src, gpl->prev); + BKE_gpencil_layer_active_set(gpd_src, gpl->prev); } else if (gpl->next) { - BKE_gpencil_layer_setactive(gpd_src, gpl->next); + BKE_gpencil_layer_active_set(gpd_src, gpl->next); } /* unlink from source datablock */ BLI_remlink(&gpd_src->layers, gpl); @@ -4327,8 +4297,8 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op) BLI_addtail(&gpd_dst->layers, gpl); /* add duplicate materials */ - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; @@ -4416,7 +4386,7 @@ static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op)) /* split selected strokes */ if (gps->flag & GP_STROKE_SELECT) { /* make copy of source stroke */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps); + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true); /* link to same frame */ BLI_addtail(&gpf->strokes, gps_dst); @@ -4675,7 +4645,7 @@ static int gpencil_cutter_lasso_select(bContext *C, /* dissolve selected points */ bGPDstroke *gpsn; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->flag & GP_LAYER_LOCKED) { continue; } @@ -4795,7 +4765,7 @@ static bool gp_merge_by_distance_poll(bContext *C) return false; } - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); return ((gpl != NULL) && (ob->mode == OB_MODE_EDIT_GPENCIL)); } @@ -4815,7 +4785,7 @@ static int gp_merge_by_distance_exec(bContext *C, wmOperator *op) /* Go through each editable selected stroke */ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { - BKE_gpencil_merge_distance_stroke(gpf_, gps, threshold, unselected); + BKE_gpencil_stroke_merge_distance(gpf_, gps, threshold, unselected); } } GP_EDITABLE_STROKES_END(gpstroke_iter); diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index fcbbef8cd52..8c8a9c5238f 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -247,9 +247,9 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) GPU_blend(true); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* calculate parent position */ - ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat); + BKE_gpencil_parent_matrix_get(tgpw.depsgraph, ob, gpl, tgpw.diff_mat); /* do not draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) { @@ -259,24 +259,24 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) /* if active layer and no keyframe, create a new one */ if (gpl == tgpf->gpl) { if ((gpl->actframe == NULL) || (gpl->actframe->framenum != tgpf->active_cfra)) { - BKE_gpencil_layer_getframe(gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); + BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); } } /* get frame to draw */ - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, tgpf->active_cfra, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_USE_PREV); if (gpf == NULL) { continue; } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* check if stroke can be drawn */ if ((gps->points == NULL) || (gps->totpoints < 2)) { continue; } /* check if the color is visible */ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) { + if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE)) { continue; } @@ -293,7 +293,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) tgpw.onion = true; tgpw.custonion = true; - bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE); + bool textured_stroke = (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE); /* normal strokes */ if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) || @@ -1081,7 +1081,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) } /* Get frame or create a new one. */ - tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); + tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); /* Set frame as selected. */ tgpf->gpf->flag |= GP_FRAME_SELECT; @@ -1089,15 +1089,13 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) /* create new stroke */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); gps->thickness = brush->size; + gps->fill_opacity_fac = 1.0f; gps->gradient_f = brush->gpencil_settings->gradient_f; copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s); gps->inittime = 0.0f; - /* Apply the mix color to fill. */ - if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) { - copy_v3_v3(gps->mix_color_fill, brush->rgb); - gps->mix_color_fill[3] = brush->gpencil_settings->vertex_factor; - } + /* Apply the vertex color to fill. */ + ED_gpencil_fill_vertex_color_set(ts, brush, gps); /* the polygon must be closed, so enabled cyclic */ gps->flag |= GP_STROKE_CYCLIC; @@ -1117,11 +1115,6 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) gps->totpoints = tgpf->sbuffer_used; gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_used, "gp_stroke_points"); - /* initialize triangle memory to dummy data */ - gps->tot_triangles = 0; - gps->triangles = NULL; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - /* add stroke to frame */ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) { BLI_addhead(&tgpf->gpf->strokes, gps); @@ -1156,11 +1149,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) pt->strength = 1.0f; pt->time = 0.0f; - /* Point mix color. */ - copy_v3_v3(pt->mix_color, brush->rgb); - pt->mix_color[3] = GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) ? - brush->gpencil_settings->vertex_factor : - 0.0f; + /* Apply the vertex color to point. */ + ED_gpencil_point_vertex_color_set(ts, brush, pt); if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) { MDeformWeight *dw = defvert_verify_index(dvert, def_nr); @@ -1184,7 +1174,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) 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); + BKE_gpencil_stroke_smooth(gps, i, smoothfac - reduce); } reduce += 0.25f; // reduce the factor } @@ -1193,7 +1183,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) { float origin[3]; - ED_gp_get_drawing_reference(tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin); + ED_gpencil_drawing_reference_get( + tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin); ED_gp_project_stroke_to_plane( tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1); } @@ -1211,8 +1202,11 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) /* simplify stroke */ for (int b = 0; b < tgpf->fill_simplylvl; b++) { - BKE_gpencil_simplify_fixed(gps); + BKE_gpencil_stroke_simplify_fixed(gps); } + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* ----------------------- */ @@ -1297,7 +1291,7 @@ static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op)) /* set GP datablock */ tgpf->gpd = gpd; - tgpf->gpl = BKE_gpencil_layer_getactive(gpd); + tgpf->gpl = BKE_gpencil_layer_active_get(gpd); if (tgpf->gpl == NULL) { tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true); } @@ -1406,7 +1400,7 @@ static int gpencil_fill_init(bContext *C, wmOperator *op) tGPDfill *tgpf; /* cannot paint in locked layer */ bGPdata *gpd = CTX_data_gpencil_data(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) { return 0; } diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 5c2885aa38f..4f6aedf8495 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -111,6 +111,8 @@ typedef struct tGPDinterpolate_layer { } tGPDinterpolate_layer; typedef struct tGPDinterpolate { + /** Current depsgraph from context */ + struct Depsgraph *depsgraph; /** current scene from context */ struct Scene *scene; /** area where painting originated */ @@ -138,10 +140,6 @@ typedef struct tGPDinterpolate { int flag; NumInput num; /* numeric input */ - /** handle for drawing strokes while operator is running 3d stuff */ - void *draw_handle_3d; - /** handle for drawing strokes while operator is running screen stuff */ - void *draw_handle_screen; } tGPDinterpolate; /* Temporary primitive operation data */ @@ -233,10 +231,6 @@ typedef struct tGPDprimitive { } tGPDprimitive; /* Modal Operator Drawing Callbacks ------------------------ */ - -void ED_gp_draw_interpolation(const struct bContext *C, - struct tGPDinterpolate *tgpi, - const int type); void ED_gp_draw_fill(struct tGPDdraw *tgpw); /* ***************************************************** */ @@ -636,7 +630,7 @@ struct GP_EditableStrokes_Iter { bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \ - ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \ + BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ /* loop over strokes */ \ bGPDstroke *gpsn_; \ @@ -677,26 +671,21 @@ struct GP_EditableStrokes_Iter { struct GP_EditableStrokes_Iter gpstroke_iter = {{{0}}}; \ Depsgraph *depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C); \ Object *obact_ = CTX_data_active_object(C); \ - Object *obeval_ = DEG_get_evaluated_object(depsgraph_, obact_); \ - bGPdata *gpd_ = CTX_data_gpencil_data(C); \ - const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \ - int idx_eval = 0; \ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { \ - if (gpencil_layer_is_editable(gpl)) { \ + Object *ob_eval_ = (Object *)DEG_get_evaluated_id(depsgraph_, &obact_->id); \ + bGPdata *gpd = (bGPdata *)ob_eval_->data; \ + const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); \ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { \ + if (BKE_gpencil_layer_is_editable(gpl)) { \ 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_)) { \ - ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \ + BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ - /* get evaluated frame with modifiers applied */ \ - bGPDframe *gpf_eval_ = (!is_multiedit_) ? \ - &obeval_->runtime.gpencil_evaluated_frames[idx_eval] : \ - gpf_; \ /* loop over strokes */ \ - for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->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; \ @@ -713,7 +702,6 @@ struct GP_EditableStrokes_Iter { } \ } \ } \ - idx_eval++; \ } \ } \ (void)0 diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 40c95e66cb2..05d5b8d6eee 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -119,20 +119,36 @@ static void gp_interpolate_update_points(const bGPDstroke *gps_from, } /* ****************** Interpolate Interactive *********************** */ +/* Helper: free all temp strokes for display. */ +static void gp_interpolate_free_temp_strokes(bGPDframe *gpf) +{ + if (gpf == NULL) { + return; + } + bGPDstroke *gps_next; + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps_next) { + gps_next = gps->next; + if (gps->flag & GP_STROKE_TAG) { + BLI_remlink(&gpf->strokes, gps); + BKE_gpencil_free_stroke(gps); + } + } +} /* 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; - for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - bGPDstroke *new_stroke; + LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) { const float factor = tgpil->factor + shift; - for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; - new_stroke = new_stroke->next) { + bGPDframe *gpf = tgpil->gpl->actframe; + /* Free temp strokes. */ + gp_interpolate_free_temp_strokes(gpf); + + LISTBASE_FOREACH (bGPDstroke *, new_stroke, &tgpil->interFrame->strokes) { bGPDstroke *gps_from, *gps_to; int stroke_idx; @@ -149,6 +165,13 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) /* update points position */ if ((gps_from) && (gps_to)) { gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); + + /* Add temp strokes. */ + if (gpf) { + bGPDstroke *gps_eval = BKE_gpencil_stroke_duplicate(new_stroke, true); + gps_eval->flag |= GP_STROKE_TAG; + BLI_addtail(&gpf->strokes, gps_eval); + } } } } @@ -165,19 +188,18 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag; /* get layers */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* all layers or only active */ if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) { continue; } /* only editable and visible layers are considered */ - if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { + if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } /* read strokes */ - for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; - gps_from = gps_from->next) { + LISTBASE_FOREACH (bGPDstroke *, gps_from, &gpl->actframe->strokes) { bGPDstroke *gps_to; int fFrame; @@ -225,7 +247,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpi->high_limit = 2.0f - tgpi->init_factor; /* set layers */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { tGPDinterpolate_layer *tgpil; /* all layers or only active */ @@ -233,7 +255,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) continue; } /* only editable and visible layers are considered */ - if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { + if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } @@ -255,8 +277,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1); /* create new strokes data with interpolated points reading original stroke */ - for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; - gps_from = gps_from->next) { + LISTBASE_FOREACH (bGPDstroke *, gps_from, &tgpil->prevFrame->strokes) { bGPDstroke *gps_to; int fFrame; @@ -286,7 +307,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) } /* create new stroke */ - new_stroke = BKE_gpencil_stroke_duplicate(gps_from); + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true); if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ @@ -298,8 +319,6 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) sizeof(*new_stroke->dvert) * gps_to->totpoints); } new_stroke->totpoints = gps_to->totpoints; - new_stroke->tot_triangles = 0; - new_stroke->flag |= GP_STROKE_RECALC_GEOMETRY; } /* update points position */ gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); @@ -311,12 +330,10 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) if (new_stroke->dvert != NULL) { 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_GEOMETRY; } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(new_stroke); /* add to strokes */ BLI_addtail(&tgpil->interFrame->strokes, new_stroke); } @@ -324,25 +341,6 @@ 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 *C, - ARegion *UNUSED(ar), - void *arg) -{ - tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; - 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 *C, ARegion *UNUSED(ar), void *arg) -{ - tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; - ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW); -} - -/* ----------------------- */ /* Helper: calculate shift based on position of mouse (we only use x-axis for now. * since this is more convenient for users to do), and store new shift value @@ -408,25 +406,23 @@ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpol 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) { - /* remove drawing handler */ - if (tgpi->draw_handle_screen) { - ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen); - } - if (tgpi->draw_handle_3d) { - ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); - } - /* clear status message area */ ED_area_status_text(tgpi->sa, NULL); ED_workspace_status_text(C, NULL); + /* Clear any temp stroke. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + gp_interpolate_free_temp_strokes(gpf); + } + } + /* finally, free memory used by temp data */ - for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { + LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) { BKE_gpencil_free_strokes(tgpil->interFrame); MEM_freeN(tgpil->interFrame); } @@ -448,6 +444,7 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte bGPdata *gpd = CTX_data_gpencil_data(C); /* set current scene and window */ + tgpi->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); tgpi->scene = CTX_data_scene(C); tgpi->sa = CTX_wm_area(C); tgpi->ar = CTX_wm_region(C); @@ -543,15 +540,6 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent tgpi = op->customdata; } - /* Enable custom drawing handlers - * It needs 2 handlers because strokes can in 3d space and screen space - * and each handler use different coord system - */ - tgpi->draw_handle_screen = ED_region_draw_cb_activate( - tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL); - tgpi->draw_handle_3d = ED_region_draw_cb_activate( - tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW); - /* set cursor to indicate modal */ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL); @@ -572,8 +560,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent tGPDinterpolate *tgpi = op->customdata; wmWindow *win = CTX_wm_window(C); bGPDframe *gpf_dst; - bGPDstroke *gps_src, *gps_dst; - tGPDinterpolate_layer *tgpil; + bGPDstroke *gps_dst; const bool has_numinput = hasNumInput(&tgpi->num); switch (event->type) { @@ -586,26 +573,22 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent WM_cursor_modal_restore(win); /* insert keyframes as required... */ - for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); + LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) { + gpf_dst = BKE_gpencil_layer_frame_get(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN; /* copy strokes */ BLI_listbase_clear(&gpf_dst->strokes); - for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) { + LISTBASE_FOREACH (bGPDstroke *, gps_src, &tgpil->interFrame->strokes) { if (gps_src->totpoints == 0) { continue; } /* 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); - if (gps_src->dvert != NULL) { - 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_GEOMETRY; + gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps_dst); + BLI_addtail(&gpf_dst->strokes, gps_dst); } } @@ -966,7 +949,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* loop all layer to check if need interpolation */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { bGPDframe *prevFrame, *nextFrame; bGPDstroke *gps_from, *gps_to; int cframe, fFrame; @@ -976,7 +959,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) continue; } /* only editable and visible layers are considered */ - if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { + if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } @@ -1035,12 +1018,12 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) /* create a new frame if needed */ if (interFrame == NULL) { - interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); + interFrame = BKE_gpencil_layer_frame_get(gpl, cframe, GP_GETFRAME_ADD_NEW); interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; } /* create new stroke */ - new_stroke = BKE_gpencil_stroke_duplicate(gps_from); + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true); /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { @@ -1057,14 +1040,14 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) 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_GEOMETRY; } /* update points position */ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(new_stroke); + /* add to strokes */ BLI_addtail(&interFrame->strokes, new_stroke); } diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index d085d791477..30496fe6bb1 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -61,7 +61,7 @@ typedef struct tGPencilPointCache { float x, y, z; float pressure; float strength; - float mix_color[4]; + float vert_color[4]; } tGPencilPointCache; /* helper function to sort points */ @@ -95,7 +95,7 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps, pt_dst->uv_fac = 1.0f; pt_dst->uv_rot = 0; pt_dst->flag |= GP_SPOINT_SELECT; - copy_v4_v4(pt_dst->mix_color, point_elem->mix_color); + copy_v4_v4(pt_dst->vert_color, point_elem->vert_color); } } @@ -128,7 +128,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo else { add_frame_mode = GP_GETFRAME_ADD_NEW; } - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode); /* stroke */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke"); @@ -143,10 +143,6 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo /* allocate memory for points */ gps->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, "gp_stroke_points"); - /* initialize triangle memory to dummy data */ - gps->tot_triangles = 0; - gps->triangles = NULL; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; if (cyclic) { gps->flag |= GP_STROKE_CYCLIC; @@ -227,7 +223,7 @@ static void gpencil_calc_points_factor(bContext *C, if (gpf == NULL) { continue; } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (gps->flag & GP_STROKE_SELECT) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (clear_stroke) { @@ -242,7 +238,7 @@ static void gpencil_calc_points_factor(bContext *C, copy_v3_v3(&pt2->x, &pt->x); pt2->pressure = pt->pressure; pt2->strength = pt->strength; - copy_v4_v4(pt2->mix_color, pt->mix_color); + copy_v4_v4(pt2->vert_color, pt->vert_color); pt->flag &= ~GP_SPOINT_SELECT; if (clear_point) { pt->flag |= GP_SPOINT_TAG; @@ -292,7 +288,7 @@ static void gpencil_calc_points_factor(bContext *C, copy_v3_v3(&sort_pt->x, &pt2->x); sort_pt->pressure = pt2->pressure; sort_pt->strength = pt2->strength; - copy_v4_v4(sort_pt->mix_color, pt2->mix_color); + copy_v4_v4(sort_pt->vert_color, pt2->vert_color); sort_pt->gps = gps_array[i]; @@ -341,7 +337,7 @@ static int gpencil_insert_to_array(tGPencilPointCache *src_array, dst_elem->pressure = src_elem->pressure; dst_elem->strength = src_elem->strength; dst_elem->factor = src_elem->factor; - copy_v4_v4(dst_elem->mix_color, src_elem->mix_color); + copy_v4_v4(dst_elem->vert_color, src_elem->vert_color); } return last; @@ -464,7 +460,7 @@ static bool gp_strokes_merge_poll(bContext *C) /* check hidden or locked materials */ MaterialGPencilStyle *gp_style = ma->gp_style; - if ((gp_style->flag & GP_STYLE_COLOR_HIDE) || (gp_style->flag & GP_STYLE_COLOR_LOCKED)) { + if ((gp_style->flag & GP_MATERIAL_HIDE) || (gp_style->flag & GP_MATERIAL_LOCKED)) { return false; } @@ -612,8 +608,8 @@ static int gp_stroke_merge_material_exec(bContext *C, wmOperator *op) /* Update stroke material index. */ if (changed) { CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index 3d56cb0fcb1..e5b9d902210 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -130,7 +130,6 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op) copy_v4_v4(gp_style->fill_rgba, palcolor->fill); /* set basic settings */ - 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); @@ -138,13 +137,13 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op) gp_style->texture_opacity = 1.0f; gp_style->texture_pixsize = 100.0f; - gp_style->flag |= GP_STYLE_STROKE_SHOW; - gp_style->flag |= GP_STYLE_FILL_SHOW; + gp_style->flag |= GP_MATERIAL_STROKE_SHOW; + gp_style->flag |= GP_MATERIAL_FILL_SHOW; /* 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) { gps->mat_nr = ob->totcol - 1; gps->colorname[0] = '\0'; @@ -174,7 +173,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op) for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) { /* fix layers */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* unlock/unhide layer */ gpl->flag &= ~GP_LAYER_LOCKED; gpl->flag &= ~GP_LAYER_HIDE; @@ -182,8 +181,8 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op) gpl->opacity = 1.0f; /* disable tint */ gpl->tintcolor[3] = 0.0f; - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if ((gps->colorname[0] != '\0') && (STREQ(gps->colorname, palcolor->info))) { /* copy color settings */ copy_v4_v4(gpl->color, palcolor->color); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 2270159d597..e31800f20e5 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -270,11 +270,6 @@ static void gp_update_cache(bGPdata *gpd) } } -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); @@ -353,7 +348,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3]) if (p->ownerPtr.type == &RNA_Object) { ob = (Object *)p->ownerPtr.data; } - ED_gp_get_drawing_reference(p->scene, ob, p->gpl, *p->align_flag, vec); + ED_gpencil_drawing_reference_get(p->scene, ob, p->gpl, *p->align_flag, vec); } /* Stroke Editing ---------------------------- */ @@ -482,48 +477,26 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[ } } -/* apply jitter to stroke */ -static void gp_brush_jitter(bGPdata *gpd, - Brush *brush, - tGPspoint *pt, - const float mval[2], - const float pressure, - float r_mval[2], - RNG *rng) +/* Apply jitter to stroke point. */ +static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude) { - float tmp_pressure = pressure; - if (brush->gpencil_settings->draw_jitter > 0.0f) { - tmp_pressure = BKE_curvemapping_evaluateF(brush->gpencil_settings->curve_jitter, 0, pressure); - } - /* exponential value */ - const float exfactor = (brush->gpencil_settings->draw_jitter + 2.0f) * - (brush->gpencil_settings->draw_jitter + 2.0f); - 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 */ + /* Jitter is applied perpendicular to the mouse movement vector (2D space). */ + float mvec[2]; + /* Mouse movement in ints -> floats. */ if (gpd->runtime.sbuffer_used > 1) { - mvec[0] = (mval[0] - (pt - 1)->x); - mvec[1] = (mval[1] - (pt - 1)->y); + tGPspoint *pt_prev = pt - 1; + sub_v2_v2v2(mvec, &pt->x, &pt_prev->x); normalize_v2(mvec); } else { mvec[0] = 0.0f; mvec[1] = 0.0f; } - /* rotate mvec by 90 degrees... */ - svec[0] = -mvec[1]; - svec[1] = mvec[0]; - /* scale the displacement by the random, and apply */ - if (BLI_rng_get_float(rng) > 0.5f) { - mul_v2_fl(svec, -fac); - } - else { - mul_v2_fl(svec, fac); - } - - r_mval[0] = mval[0] + svec[0]; - r_mval[1] = mval[1] + svec[1]; + /* Rotate mvec by 90 degrees... */ + SWAP(float, mvec[0], mvec[1]); + mvec[0] -= mvec[0]; + /* Scale by displacement amount, and apply. */ + madd_v2_v2fl(&pt->x, mvec, amplitude); } /* apply pressure change depending of the angle of the stroke to simulate a pen with shape */ @@ -712,10 +685,10 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure { bGPdata *gpd = p->gpd; Brush *brush = p->brush; + BrushGpencilSettings *brush_settings = p->brush->gpencil_settings; tGPspoint *pt; Object *obact = (Object *)p->ownerPtr.data; RegionView3D *rv3d = p->ar->regiondata; - MaterialGPencilStyle *gp_style = p->material->gp_style; /* check painting mode */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { @@ -764,100 +737,72 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure return GP_STROKEADD_INVALID; } + /* Set vertex colors for buffer. */ + ED_gpencil_sbuffer_vertex_color_set(p->scene->toolsettings, p->brush, gpd); + /* get pointer to destination point */ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used); /* store settings */ + pt->strength = brush_settings->draw_strength; + pt->pressure = 1.0f; + pt->uv_rot = 0.0f; + copy_v2_v2(&pt->x, mval); + /* pressure */ - if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) { - pt->pressure = BKE_curvemapping_evaluateF( - brush->gpencil_settings->curve_sensitivity, 0, pressure); - } - else { - pt->pressure = 1.0f; + if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) { + pt->pressure *= BKE_curvemapping_evaluateF(brush_settings->curve_sensitivity, 0, pressure); } - /* Apply jitter to position */ - if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && - (brush->gpencil_settings->draw_jitter > 0.0f)) { - float r_mval[2]; - const float jitpress = (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) ? - pressure : - 1.0f; - gp_brush_jitter(gpd, brush, pt, mval, jitpress, r_mval, p->rng); - copy_v2_v2(&pt->x, r_mval); - } - else { - copy_v2_v2(&pt->x, mval); + /* color strength */ + if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { + pt->strength *= BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, pressure); + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); } - /* apply randomness to pressure */ - if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && - (brush->gpencil_settings->draw_random_press > 0.0f)) { - float tmp_pressure = BKE_curvemapping_evaluateF( - brush->gpencil_settings->curve_sensitivity, 0, pressure); - if (BLI_rng_get_float(p->rng) > 0.5f) { - pt->pressure -= tmp_pressure * (brush->gpencil_settings->draw_random_press * 2.0f) * - BLI_rng_get_float(p->rng); + + if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) { + /* Apply jitter to position */ + if (brush_settings->draw_jitter > 0.0f) { + float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; + float jitpress = 1.0f; + if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) { + jitpress = BKE_curvemapping_evaluateF(brush_settings->curve_jitter, 0, pressure); + } + /* FIXME the +2 means minimum jitter is 4 which is a bit strange for UX. */ + const float exp_factor = brush_settings->draw_jitter + 2.0f; + const float fac = rand * SQUARE(exp_factor) * jitpress; + gp_brush_jitter(gpd, pt, fac); } - else { - pt->pressure += tmp_pressure * (brush->gpencil_settings->draw_random_press * 2.0f) * - BLI_rng_get_float(p->rng); + /* apply randomness to pressure */ + if (brush_settings->draw_random_press > 0.0f) { + float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; + pt->pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press; + CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f); } - 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; + /* apply randomness to uv texture rotation */ + if (brush_settings->uv_random > 0.0f) { + float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; + pt->uv_rot += rand * M_PI * brush_settings->uv_random; + CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); } - else { - pt->uv_rot = (BLI_rng_get_float(p->rng) * M_PI) * brush->gpencil_settings->uv_random; + /* apply randomness to color strength */ + if (brush_settings->draw_random_strength) { + float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; + pt->strength *= 1.0 + rand * brush_settings->draw_random_strength; + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); } - 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->gpencil_settings->draw_angle_factor != 0.0f) { + if (brush_settings->draw_angle_factor != 0.0f) { gp_brush_angle(gpd, brush, pt, mval); } - /* color strength */ - if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { - float tmp_pressure = BKE_curvemapping_evaluateF( - brush->gpencil_settings->curve_strength, 0, pressure); - - pt->strength = tmp_pressure * brush->gpencil_settings->draw_strength; - } - else { - pt->strength = brush->gpencil_settings->draw_strength; - } - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); - - /* apply randomness to color 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->gpencil_settings->draw_random_strength * - BLI_rng_get_float(p->rng); - } - else { - pt->strength += pt->strength * brush->gpencil_settings->draw_random_strength * - BLI_rng_get_float(p->rng); - } - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); - } - /* point time */ pt->time = (float)(curtime - p->inittime); /* point uv (only 3d view) */ if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) { - float pixsize = gp_style->texture_pixsize / 1000000.0f; tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1; bGPDspoint spt, spt2; @@ -871,11 +816,8 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* reproject previous */ ED_gpencil_tpoint_to_point(p->ar, origin, ptb, &spt2); ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2); - p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize; + p->totpixlen += len_v3v3(&spt.x, &spt2.x); pt->uv_fac = p->totpixlen; - if ((gp_style) && (gp_style->sima)) { - pt->uv_fac /= gp_style->sima->gen_x; - } } else { p->totpixlen = 0.0f; @@ -894,6 +836,9 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure } } + /* Update evaluated data. */ + ED_gpencil_sbuffer_update_eval(p->depsgraph, p->ob); + return GP_STROKEADD_NORMAL; } /* return invalid state for now... */ @@ -967,25 +912,19 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* copy appropriate settings for stroke */ gps->totpoints = totelem; gps->thickness = brush->size; + gps->fill_opacity_fac = 1.0f; gps->gradient_f = brush->gpencil_settings->gradient_f; copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s); gps->flag = gpd->runtime.sbuffer_sflag; gps->inittime = p->inittime; gps->uv_scale = 1.0f; - /* enable recalculation flag by default */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - /* allocate enough memory for a continuous array for storage points */ const int subdivide = brush->gpencil_settings->draw_subdivide; gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); gps->dvert = NULL; - /* initialize triangle memory to dummy data */ - gps->triangles = NULL; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; /* drawing batch cache is dirty now */ gp_update_cache(p->gpd); /* set pointer to first non-initialized point */ @@ -994,11 +933,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) dvert = gps->dvert + (gps->totpoints - totelem); } - /* Apply the mix color to fill for stroke. */ - if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) { - copy_v3_v3(gps->mix_color_fill, brush->rgb); - gps->mix_color_fill[3] = brush->gpencil_settings->vertex_factor; - } + /* Apply the vertex color to fill. */ + ED_gpencil_fill_vertex_color_set(ts, brush, gps); /* copy points from the buffer to the stroke */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { @@ -1014,11 +950,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; - /* Point mix color. */ - copy_v3_v3(pt->mix_color, brush->rgb); - pt->mix_color[3] = GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) ? - brush->gpencil_settings->vertex_factor : - 0.0f; + /* Apply the vertex color to point. */ + ED_gpencil_point_vertex_color_set(ts, brush, pt); pt++; @@ -1050,11 +983,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; - /* Point mix color. */ - copy_v3_v3(pt->mix_color, brush->rgb); - pt->mix_color[3] = GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) ? - brush->gpencil_settings->vertex_factor : - 0.0f; + /* Apply the vertex color to point. */ + ED_gpencil_point_vertex_color_set(ts, brush, pt); if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) { BKE_gpencil_dvert_ensure(gps); @@ -1176,11 +1106,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt->time = ptc->time; pt->uv_fac = ptc->uv_fac; pt->uv_rot = ptc->uv_rot; - /* Point mix color. */ - copy_v3_v3(pt->mix_color, brush->rgb); - pt->mix_color[3] = GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) ? - brush->gpencil_settings->vertex_factor : - 0.0f; + /* Apply the vertex color to point. */ + ED_gpencil_point_vertex_color_set(ts, brush, pt); if (dvert != NULL) { dvert->totweight = 0; @@ -1202,8 +1129,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) float reduce = 0.0f; for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) { for (i = 0; i < gps->totpoints - 1; i++) { - BKE_gpencil_smooth_stroke(gps, i, brush->gpencil_settings->draw_smoothfac - reduce); - BKE_gpencil_smooth_stroke_strength(gps, i, brush->gpencil_settings->draw_smoothfac); + BKE_gpencil_stroke_smooth(gps, i, brush->gpencil_settings->draw_smoothfac - reduce); + BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac); } reduce += 0.25f; /* reduce the factor */ } @@ -1212,7 +1139,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* Simplify adaptive */ if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && (brush->gpencil_settings->simplify_f > 0.0f)) { - BKE_gpencil_simplify_stroke(gps, brush->gpencil_settings->simplify_f); + BKE_gpencil_stroke_simplify(gps, brush->gpencil_settings->simplify_f); } /* reproject to plane (only in 3d space) */ @@ -1240,9 +1167,6 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } } - /* 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 when drawing the background. @@ -1268,9 +1192,12 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* post process stroke */ if ((p->brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) && p->brush->gpencil_settings->flag & GP_BRUSH_TRIM_STROKE) { - BKE_gpencil_trim_stroke(gps); + BKE_gpencil_stroke_trim(gps); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + gp_stroke_added_enable(p); } @@ -1316,7 +1243,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p, float diff_mat[4][4]; /* calculate difference matrix if parent object */ - ED_gpencil_parent_location(p->depsgraph, obact, p->gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(p->depsgraph, obact, gpl, diff_mat); if (ED_view3d_autodist_simple(p->ar, mval_i, mval_3d, 0, NULL)) { const float depth_mval = view3d_point_depth(rv3d, mval_3d); @@ -1441,7 +1368,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, round_v2i_v2fl(mval_i, mval); /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, obact, p->gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); if (gps->totpoints == 0) { /* just free stroke */ @@ -1638,7 +1565,6 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, /* erase strokes which fall under the eraser strokes */ static void gp_stroke_doeraser(tGPsdata *p) { - bGPDlayer *gpl; bGPDstroke *gps, *gpn; rcti rect; Brush *brush = p->brush; @@ -1679,11 +1605,11 @@ static void gp_stroke_doeraser(tGPsdata *p) * only a subset of layers, it is harder to perform the same erase operation * on multiple layers... */ - for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) { bGPDframe *gpf = gpl->actframe; /* only affect layer if it's editable (and visible) */ - if (gpencil_layer_is_editable(gpl) == false) { + if (BKE_gpencil_layer_is_editable(gpl) == false) { continue; } else if (gpf == NULL) { @@ -1841,51 +1767,12 @@ static void gp_init_colors(tGPsdata *p) { bGPdata *gpd = p->gpd; Brush *brush = p->brush; - ToolSettings *ts = p->scene->toolsettings; - - MaterialGPencilStyle *gp_style = NULL; /* use brush material */ p->material = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush); - /* assign color information to temp tGPsdata */ - gp_style = p->material->gp_style; - if (gp_style) { - - /* set colors */ - if (gp_style->flag & GP_STYLE_STROKE_SHOW) { - copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba); - } - else { - /* if no stroke, use fill */ - copy_v4_v4(gpd->runtime.scolor, gp_style->fill_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; - } - - /* Apply the mix color to fill. */ - if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) { - interp_v3_v3v3(gpd->runtime.sfill, - gpd->runtime.sfill, - brush->rgb, - brush->gpencil_settings->vertex_factor); - } - - gpd->runtime.mode = (short)gp_style->mode; - gpd->runtime.bstroke_style = gp_style->stroke_style; - gpd->runtime.bfill_style = gp_style->fill_style; - - /* Apply the mix color to stroke. */ - if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) { - interp_v3_v3v3(gpd->runtime.scolor, - gpd->runtime.scolor, - brush->rgb, - brush->gpencil_settings->vertex_factor); - } - } + gpd->runtime.matid = BKE_object_material_slot_find_index(p->ob, p->material); + gpd->runtime.brush_size = brush->size; } /* (re)init new painting data */ @@ -2091,7 +1978,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps ToolSettings *ts = scene->toolsettings; /* get active layer (or add a new one if non-existent) */ - p->gpl = BKE_gpencil_layer_getactive(p->gpd); + p->gpl = BKE_gpencil_layer_active_get(p->gpd); if (p->gpl == NULL) { p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("GP_Layer"), true); @@ -2116,9 +2003,9 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps */ bool has_layer_to_erase = false; - for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) { /* Skip if layer not editable */ - if (gpencil_layer_is_editable(gpl) == false) { + if (BKE_gpencil_layer_is_editable(gpl) == false) { continue; } @@ -2130,7 +2017,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_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); has_layer_to_erase = true; } @@ -2159,7 +2046,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps add_frame_mode = GP_GETFRAME_ADD_NEW; } - p->gpf = BKE_gpencil_layer_getframe(p->gpl, CFRA, add_frame_mode); + p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode); if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; @@ -2186,8 +2073,6 @@ 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 */ @@ -2232,6 +2117,8 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps } } } + /* Tag datablock. */ + gp_update_cache(p->gpd); } /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */ @@ -2276,7 +2163,6 @@ static void gp_paint_cleanup(tGPsdata *p) p->gpf->flag &= ~GP_FRAME_PAINT; } } - /* ------------------------------- */ /* Helper callback for drawing the cursor itself */ @@ -2451,23 +2337,6 @@ 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) -{ - UNUSED_VARS(p); - return; - /* Disable while we get a better cursor handling for direct input devices (Cintiq/Ipad)*/ -#if 0 - Brush *brush = p->brush; - if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) { - WM_cursor_modal_set(p->win, WM_CURSOR_CROSS); /* XXX need a better cursor */ - } - else { - WM_cursor_modal_set(p->win, WM_CURSOR_NONE); - } -#endif -} - /* update UI indicators of status, including cursor and header prints */ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) { @@ -3162,9 +3031,9 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event else { /* don't erase empty frames */ bool has_layer_to_erase = false; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Skip if layer not editable */ - if (gpencil_layer_is_editable(gpl)) { + if (BKE_gpencil_layer_is_editable(gpl)) { if (gpl->actframe && gpl->actframe->strokes.first) { has_layer_to_erase = true; break; @@ -3192,18 +3061,13 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event } /* TODO: set any additional settings that we can take from the events? - /* if eraser is on, draw radial aid */ + * if eraser is on, draw radial aid */ 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)... - */ - 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) { @@ -3280,27 +3144,9 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op) 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; -} - /* Add arc points between two mouse events using the previous segment to determine the vertice of * the arc. - * /* CTL + * /+ CTL * / | * / | * PtA +...|...+ PtB @@ -3807,7 +3653,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) 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 */ diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index f106138b42a..7d9c3b7785c 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -122,6 +122,9 @@ static void gp_session_validatebuffer(tGPDprimitive *p) gpd->runtime.sbuffer_sflag = 0; gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE; + /* Set vertex colors for buffer. */ + ED_gpencil_sbuffer_vertex_color_set(p->scene->toolsettings, p->brush, gpd); + if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) { gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC; } @@ -131,51 +134,12 @@ static void gp_init_colors(tGPDprimitive *p) { bGPdata *gpd = p->gpd; Brush *brush = p->brush; - ToolSettings *ts = p->scene->toolsettings; - - MaterialGPencilStyle *gp_style = NULL; /* use brush material */ p->mat = BKE_gpencil_object_material_ensure_from_active_input_brush(p->bmain, p->ob, brush); - /* assign color information to temp data */ - gp_style = p->mat->gp_style; - if (gp_style) { - - /* set colors */ - if (gp_style->flag & GP_STYLE_STROKE_SHOW) { - copy_v4_v4(gpd->runtime.scolor, gp_style->stroke_rgba); - } - else { - /* if no stroke, use fill */ - copy_v4_v4(gpd->runtime.scolor, gp_style->fill_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; - } - /* Apply the mix color to fill. */ - if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) { - interp_v3_v3v3(gpd->runtime.sfill, - gpd->runtime.sfill, - brush->rgb, - brush->gpencil_settings->vertex_factor); - } - - gpd->runtime.mode = (short)gp_style->mode; - gpd->runtime.bstroke_style = gp_style->stroke_style; - gpd->runtime.bfill_style = gp_style->fill_style; - - /* Apply the mix color to stroke. */ - if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) { - interp_v3_v3v3(gpd->runtime.scolor, - gpd->runtime.scolor, - brush->rgb, - brush->gpencil_settings->vertex_factor); - } - } + gpd->runtime.matid = BKE_object_material_slot_find_index(p->ob, p->mat); + gpd->runtime.brush_size = brush->size; } /* Helper to square a primitive */ @@ -270,18 +234,6 @@ static void gp_primitive_update_cps(tGPDprimitive *tgpi) } } -/* Helper to reflect point */ -static void UNUSED_FUNCTION(gp_reflect_point_v2_v2v2v2)(float va[2], - const float p[2], - const float a[2], - const float b[2]) -{ - float point[2]; - closest_to_line_v2(point, p, a, b); - va[0] = point[0] - (p[0] - point[0]); - va[1] = point[1] - (p[1] - point[1]); -} - /* Poll callback for primitive operators */ static bool gpencil_primitive_add_poll(bContext *C) { @@ -310,7 +262,7 @@ static bool gpencil_primitive_add_poll(bContext *C) /* 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); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(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"); @@ -357,20 +309,16 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) /* create new temp stroke */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "Temp bGPDstroke"); gps->thickness = 2.0f; + gps->fill_opacity_fac = 1.0f; gps->gradient_f = 1.0f; gps->gradient_s[0] = 1.0f; gps->gradient_s[1] = 1.0f; gps->uv_scale = 1.0f; gps->inittime = 0.0f; - /* Apply the mix color to fill. */ - if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) { - copy_v3_v3(gps->mix_color_fill, brush->rgb); - gps->mix_color_fill[3] = brush->gpencil_settings->vertex_factor; - } + /* Apply the vertex color to fill. */ + ED_gpencil_fill_vertex_color_set(ts, brush, gps); - /* enable recalculation flag by default */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; gps->flag &= ~GP_STROKE_SELECT; /* the polygon must be closed, so enabled cyclic */ if (ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) { @@ -393,10 +341,10 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) gps->totpoints = 0; gps->points = MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points"); gps->dvert = NULL; + /* initialize triangle memory to dummy data */ gps->tot_triangles = 0; gps->triangles = NULL; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; /* add to strokes */ BLI_addtail(&tgpi->gpf->strokes, gps); @@ -407,6 +355,8 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi) /* Random generator, only init once. */ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX); tgpi->rng = BLI_rng_new(rng_seed); + + DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE); } /* add new segment to curve */ @@ -998,14 +948,13 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* point uv */ if (gpd->runtime.sbuffer_used > 0) { - MaterialGPencilStyle *gp_style = tgpi->mat->gp_style; - const float pixsize = gp_style->texture_pixsize / 1000000.0f; tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1; bGPDspoint spt, spt2; /* get origin to reproject point */ float origin[3]; - ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin); + ED_gpencil_drawing_reference_get( + tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin); /* reproject current */ ED_gpencil_tpoint_to_point(tgpi->ar, origin, tpt, &spt); ED_gp_project_point_to_plane( @@ -1015,11 +964,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) ED_gpencil_tpoint_to_point(tgpi->ar, origin, tptb, &spt2); ED_gp_project_point_to_plane( tgpi->scene, tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2); - tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize; + tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x); tpt->uv_fac = tgpi->totpixlen; - if ((gp_style) && (gp_style->sima)) { - tpt->uv_fac /= gp_style->sima->gen_x; - } } else { tgpi->totpixlen = 0.0f; @@ -1048,11 +994,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) pt->time = 0.0f; pt->flag = 0; pt->uv_fac = tpt->uv_fac; - /* Point mix color. */ - copy_v3_v3(pt->mix_color, brush->rgb); - pt->mix_color[3] = GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush) ? - brush->gpencil_settings->vertex_factor : - 0.0f; + /* Apply the vertex color to point. */ + ED_gpencil_point_vertex_color_set(ts, brush, pt); if (gps->dvert != NULL) { MDeformVert *dvert = &gps->dvert[i]; @@ -1077,7 +1020,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* reproject to plane */ if (!is_depth) { float origin[3]; - ED_gp_get_drawing_reference(tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin); + ED_gpencil_drawing_reference_get( + tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin); ED_gp_project_stroke_to_plane( tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1); } @@ -1093,8 +1037,11 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps); } - /* force fill recalc */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + + /* Update evaluated data. */ + ED_gpencil_sbuffer_update_eval(tgpi->depsgraph, tgpi->ob); MEM_SAFE_FREE(depth_arr); @@ -1334,7 +1281,7 @@ static void gpencil_primitive_interaction_end(bContext *C, add_frame_mode = GP_GETFRAME_ADD_NEW; } - gpf = BKE_gpencil_layer_getframe(tgpi->gpl, tgpi->cframe, add_frame_mode); + gpf = BKE_gpencil_layer_frame_get(tgpi->gpl, tgpi->cframe, add_frame_mode); /* prepare stroke to get transferred */ gps = tgpi->gpf->strokes.first; @@ -1343,11 +1290,8 @@ static void gpencil_primitive_interaction_end(bContext *C, gps->gradient_f = brush->gpencil_settings->gradient_f; copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s); - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; - - /* calculate UVs along the stroke */ - ED_gpencil_calc_stroke_uv(tgpi->ob, gps); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* transfer stroke from temporary buffer to the actual frame */ @@ -1373,7 +1317,7 @@ static void gpencil_primitive_interaction_end(bContext *C, /* Close stroke with geometry */ if ((tgpi->type == GP_STROKE_BOX) || (tgpi->type == GP_STROKE_CIRCLE)) { - BKE_gpencil_close_stroke(gps); + BKE_gpencil_stroke_close(gps); } DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE); diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 94598314ba3..31227b8254b 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -85,7 +85,7 @@ /* Context for brush operators */ typedef struct tGP_BrushEditData { /* Current editor/region/etc. */ - /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */ + Depsgraph *depsgraph; Main *bmain; Scene *scene; Object *object; @@ -175,10 +175,6 @@ static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, const float save_pt[3]) { - if (gso->sa->spacetype != SPACE_VIEW3D) { - return; - } - const ToolSettings *ts = gso->scene->toolsettings; const View3DCursor *cursor = &gso->scene->cursor; const int axis = ts->gp_sculpt.lock_axis; @@ -282,18 +278,36 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c return influence; } -/* Force recal filling data */ -static void gp_recalc_geometry(bGPDstroke *gps) +/* Tag stroke to be recalculated. */ +static void gpencil_recalc_geometry_tag(bGPDstroke *gps) { - bGPDstroke *gps_orig = gps->runtime.gps_orig; - if (gps_orig) { - gps_orig->flag |= GP_STROKE_RECALC_GEOMETRY; - gps_orig->tot_triangles = 0; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; + gps_active->flag |= GP_STROKE_TAG; +} + +/* Recalc any stroke tagged. */ +static void gpencil_update_geometry(bGPdata *gpd) +{ + if (gpd == NULL) { + return; } - else { - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + if ((gpl->actframe != gpf) && ((gpf->flag & GP_FRAME_SELECT) == 0)) { + continue; + } + + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (gps->flag & GP_STROKE_TAG) { + BKE_gpencil_stroke_geometry_update(gps); + gps->flag &= ~GP_STROKE_TAG; + } + } + } } + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } /* ************************************************ */ @@ -318,20 +332,18 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, /* perform smoothing */ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) { - BKE_gpencil_smooth_stroke(gps, pt_index, inf); + BKE_gpencil_stroke_smooth(gps, pt_index, inf); } if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) { - BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf); + BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf); } if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_THICKNESS) { - BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf); + BKE_gpencil_stroke_smooth_thickness(gps, pt_index, inf); } if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_UV) { - BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf); + BKE_gpencil_stroke_smooth_uv(gps, pt_index, inf); } - gp_recalc_geometry(gps); - return true; } @@ -413,7 +425,7 @@ static bool gp_brush_strength_apply(tGP_BrushEditData *gso, CLAMP(pt->strength, 0.0f, 1.0f); /* smooth the strength */ - BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf); + BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf); return true; } @@ -507,38 +519,27 @@ static bool gp_brush_grab_store_points(tGP_BrushEditData *gso, static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso) { /* Convert mouse-movements to movement vector */ - // TODO: incorporate pressure into this? - // XXX: screen-space strokes in 3D space will suffer! - if (gso->sa->spacetype == SPACE_VIEW3D) { - RegionView3D *rv3d = gso->ar->regiondata; - float *rvec = gso->object->loc; - float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); - - float mval_f[2]; - - /* convert from 2D screenspace to 3D... */ - mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]); - mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]); - - /* apply evaluated data transformation */ - if (gso->rot_eval != 0.0f) { - const float cval = cos(gso->rot_eval); - const float sval = sin(gso->rot_eval); - float r[2]; - r[0] = (mval_f[0] * cval) - (mval_f[1] * sval); - r[1] = (mval_f[0] * sval) + (mval_f[1] * cval); - copy_v2_v2(mval_f, r); - } + RegionView3D *rv3d = gso->ar->regiondata; + float *rvec = gso->object->loc; + float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); - ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac); - } - else { - /* 2D - just copy */ - // XXX: view2d? - gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]); - gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]); - gso->dvec[2] = 0.0f; /* unused */ + float mval_f[2]; + + /* convert from 2D screenspace to 3D... */ + mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]); + mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]); + + /* apply evaluated data transformation */ + if (gso->rot_eval != 0.0f) { + const float cval = cos(gso->rot_eval); + const float sval = sin(gso->rot_eval); + float r[2]; + r[0] = (mval_f[0] * cval) - (mval_f[1] * sval); + r[1] = (mval_f[0] * sval) + (mval_f[1] * cval); + copy_v2_v2(mval_f, r); } + + ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac); } /* Apply grab transform to all relevant points of the affected strokes */ @@ -548,6 +549,8 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, { tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps); int i; + float inverse_diff_mat[4][4]; + invert_m4_m4(inverse_diff_mat, diff_mat); /* Apply dvec to all of the stored points */ for (i = 0; i < data->size; i++) { @@ -569,14 +572,11 @@ static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso, /* 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); } - gp_recalc_geometry(gps); } /* free customdata used for handling this stroke */ @@ -620,8 +620,6 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, /* compute lock axis */ gpsculpt_compute_lock_axis(gso, pt, save_pt); - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - /* done */ return true; } @@ -631,35 +629,26 @@ static bool gp_brush_push_apply(tGP_BrushEditData *gso, /* Compute reference midpoint for the brush - this is what we'll be moving towards */ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso) { - if (gso->sa->spacetype == SPACE_VIEW3D) { - /* Convert mouse position to 3D space - * See: gpencil_paint.c :: gp_stroke_convertcoords() - */ - RegionView3D *rv3d = gso->ar->regiondata; - const float *rvec = gso->object->loc; - float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); - - float mval_f[2]; - copy_v2_v2(mval_f, gso->mval); - float mval_prj[2]; - float dvec[3]; - - if (ED_view3d_project_float_global(gso->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(gso->ar, mval_f, dvec, zfac); - sub_v3_v3v3(gso->dvec, rvec, dvec); - } - else { - zero_v3(gso->dvec); - } + /* Convert mouse position to 3D space + * See: gpencil_paint.c :: gp_stroke_convertcoords() + */ + RegionView3D *rv3d = gso->ar->regiondata; + const float *rvec = gso->object->loc; + float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); + + float mval_f[2]; + copy_v2_v2(mval_f, gso->mval); + float mval_prj[2]; + float dvec[3]; + + if (ED_view3d_project_float_global(gso->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(gso->ar, mval_f, dvec, zfac); + sub_v3_v3v3(gso->dvec, rvec, dvec); } else { - /* Just 2D coordinates */ - // XXX: fix View2D offsets later - gso->dvec[0] = (float)gso->mval[0]; - gso->dvec[1] = (float)gso->mval[1]; - gso->dvec[2] = 0.0f; + zero_v3(gso->dvec); } } @@ -711,8 +700,6 @@ static bool gp_brush_pinch_apply(tGP_BrushEditData *gso, /* compute lock axis */ gpsculpt_compute_lock_axis(gso, pt, save_pt); - gp_recalc_geometry(gps); - /* done */ return true; } @@ -799,8 +786,6 @@ static bool gp_brush_twist_apply(tGP_BrushEditData *gso, } } - gp_recalc_geometry(gps); - /* done */ return true; } @@ -853,32 +838,17 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, /* convert to dataspace */ if (gps->flag & GP_STROKE_3DSPACE) { /* 3D: Project to 3D space */ - if (gso->sa->spacetype == SPACE_VIEW3D) { - bool flip; - RegionView3D *rv3d = gso->ar->regiondata; - float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip); - if (flip == false) { - 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 { - /* ERROR */ - BLI_assert(!"3D stroke being sculpted in non-3D view"); + bool flip; + RegionView3D *rv3d = gso->ar->regiondata; + float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip); + if (flip == false) { + 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 { - /* 2D: As-is */ - // XXX: v2d scaling/offset? - float nco[2]; - nco[0] = (float)co[0] + svec[0]; - nco[1] = (float)co[1] + svec[1]; - - copy_v2_v2(&pt->x, nco); - } } /* apply random to strength */ if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) { @@ -913,69 +883,10 @@ static bool gp_brush_randomize_apply(tGP_BrushEditData *gso, CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); } - gp_recalc_geometry(gps); - /* done */ return true; } -/* Weight Paint Brush */ -/* Change weight paint for vertex groups */ -static bool gp_brush_weight_apply(tGP_BrushEditData *gso, - bGPDstroke *gps, - float UNUSED(rot_eval), - int pt_index, - const int radius, - const int co[2]) -{ - /* create dvert */ - BKE_gpencil_dvert_ensure(gps); - - 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); - DEG_relations_tag_update(gso->bmain); - gso->vrgroup = 0; - } - } - else { - bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup); - if (defgroup->flag & DG_LOCK_WEIGHT) { - return false; - } - } - /* get current weight */ - MDeformWeight *dw = defvert_verify_index(dvert, gso->vrgroup); - float curweight = dw ? dw->weight : 0.0f; - - if (gp_brush_invert_check(gso)) { - curweight -= inf; - } - else { - /* increase weight */ - curweight += inf; - /* verify maximum target weight */ - CLAMP_MAX(curweight, gso->brush->weight); - } - - CLAMP(curweight, 0.0f, 1.0f); - if (dw) { - dw->weight = curweight; - } - - return true; -} - /* ************************************************ */ /* Non Callback-Based Brushes */ /* Clone Brush ------------------------------------- */ @@ -1079,9 +990,9 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) { tGPSB_CloneBrushData *data = gso->customdata; - Object *ob = CTX_data_active_object(C); + Object *ob = gso->object; bGPdata *gpd = (bGPdata *)ob->data; - Scene *scene = CTX_data_scene(C); + Scene *scene = gso->scene; bGPDstroke *gps; float delta[3]; @@ -1110,24 +1021,17 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) if (gpl == NULL) { gpl = CTX_data_active_gpencil_layer(C); } - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); /* Make a new stroke */ - new_stroke = MEM_dupallocN(gps); - - 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->triangles = MEM_dupallocN(gps->triangles); + new_stroke = BKE_gpencil_stroke_duplicate(gps, true); new_stroke->next = new_stroke->prev = NULL; BLI_addtail(&gpf->strokes, new_stroke); /* Fix color references */ Material *ma = BLI_ghash_lookup(data->new_colors, POINTER_FROM_INT(new_stroke->mat_nr)); - new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma); + new_stroke->mat_nr = BKE_gpencil_object_material_index_get(ob, ma); if (!ma || new_stroke->mat_nr < 0) { new_stroke->mat_nr = 0; } @@ -1240,7 +1144,7 @@ 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); + ToolSettings *ts = scene->toolsettings; Object *ob = CTX_data_active_object(C); /* set the brush using the tool */ @@ -1250,6 +1154,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData"); op->customdata = gso; + gso->depsgraph = CTX_data_ensure_evaluated_depsgraph(C); gso->bmain = CTX_data_main(C); /* store state */ gso->settings = gpsculpt_get_settings(scene); @@ -1352,11 +1257,6 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op) /* update header */ gpsculpt_brush_header_set(C, gso); - /* setup cursor drawing */ - // WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_CROSS); - if (gso->sa->spacetype != SPACE_VIEW3D) { - ED_gpencil_toggle_brush_cursor(C, true, NULL); - } return true; } @@ -1396,16 +1296,15 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) BLI_rng_free(gso->rng); } - /* disable cursor and headerprints */ + /* Disable headerprints. */ ED_workspace_status_text(C, NULL); - WM_cursor_modal_restore(win); - if (gso->sa->spacetype != SPACE_VIEW3D) { - ED_gpencil_toggle_brush_cursor(C, false, NULL); - } /* disable temp invert flag */ gso->brush->gpencil_settings->sculpt_flag &= ~GP_SCULPT_FLAG_TMP_INVERT; + /* Update geometry data for tagged strokes. */ + gpencil_update_geometry(gso->gpd); + /* free operator data */ MEM_freeN(gso); op->customdata = NULL; @@ -1414,6 +1313,11 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op) /* poll callback for stroke sculpting operator(s) */ static bool gpsculpt_brush_poll(bContext *C) { + ScrArea *sa = CTX_wm_area(C); + if (sa && sa->spacetype != SPACE_VIEW3D) { + return false; + } + /* NOTE: this is a bit slower, but is the most accurate... */ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0; } @@ -1424,7 +1328,6 @@ static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso) { bGPdata *gpd = gso->gpd; - bGPDlayer *gpl; Scene *scene = gso->scene; int cfra = CFRA; @@ -1434,9 +1337,9 @@ static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso) } /* go through each layer, and ensure that we've got a valid frame to use */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf = gpl->actframe; /* Make a new frame to work on if the layer's frame @@ -1528,8 +1431,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd); - bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; bGPDspoint *pt1, *pt2; @@ -1541,13 +1443,19 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, bool include_last = false; bool changed = false; float rot_eval = 0.0f; + + /* Check if the stroke collide with brush. */ + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) { + return false; + } + if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; /* 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 */ @@ -1600,8 +1508,8 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, /* To each point individually... */ pt = &gps->points[i]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i); ok = apply(gso, gps_active, rot_eval, index, radius, pc1); @@ -1617,8 +1525,8 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, */ if (i + 1 == gps->totpoints - 1) { pt = &gps->points[i + 1]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; if (pt_active != NULL) { rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1); ok |= apply(gso, gps_active, rot_eval, index, radius, pc2); @@ -1638,8 +1546,8 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso, * (but wasn't added then, to avoid double-ups). */ pt = &gps->points[i]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i); changed |= apply(gso, gps_active, rot_eval, index, radius, pc1); @@ -1661,11 +1569,11 @@ static bool gpsculpt_brush_do_frame(bContext *C, const float diff_mat[4][4]) { bool changed = false; - Object *ob = CTX_data_active_object(C); - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd); + bool redo_geom = false; + Object *ob = gso->object; char tool = gso->brush->gpencil_sculpt_tool; - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; @@ -1679,6 +1587,7 @@ static bool gpsculpt_brush_do_frame(bContext *C, case GPSCULPT_TOOL_SMOOTH: /* Smooth strokes */ { changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply); + redo_geom |= changed; break; } @@ -1696,7 +1605,7 @@ static bool gpsculpt_brush_do_frame(bContext *C, case GPSCULPT_TOOL_GRAB: /* Grab points */ { - bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; if (gps_active != NULL) { if (gso->first) { /* First time this brush stroke is being applied: @@ -1712,30 +1621,35 @@ static bool gpsculpt_brush_do_frame(bContext *C, changed |= true; } } + redo_geom |= changed; break; } case GPSCULPT_TOOL_PUSH: /* Push points */ { changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply); + redo_geom |= changed; break; } case GPSCULPT_TOOL_PINCH: /* Pinch points */ { changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply); + redo_geom |= changed; break; } case GPSCULPT_TOOL_TWIST: /* Twist points around midpoint */ { changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply); + redo_geom |= changed; break; } case GPSCULPT_TOOL_RANDOMIZE: /* Apply jitter */ { changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply); + redo_geom |= changed; break; } @@ -1743,8 +1657,25 @@ static bool gpsculpt_brush_do_frame(bContext *C, printf("ERROR: Unknown type of GPencil Sculpt brush \n"); break; } - /* Triangulation must be calculated if changed */ - gp_recalc_geometry(gps); + + /* Triangulation must be calculated. */ + if (redo_geom) { + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; + if (gpl->actframe == gpf) { + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + /* Update active frame now, only if material has fill. */ + if (gp_style->flag & GP_MATERIAL_FILL_SHOW) { + BKE_gpencil_stroke_geometry_update(gps_active); + } + else { + gpencil_recalc_geometry_tag(gps_active); + } + } + else { + /* Delay a full recalculation for other frames. */ + gpencil_recalc_geometry_tag(gps_active); + } + } } return changed; @@ -1753,13 +1684,14 @@ static bool gpsculpt_brush_do_frame(bContext *C, /* 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_ensure_evaluated_depsgraph(C); + ToolSettings *ts = gso->scene->toolsettings; + Depsgraph *depsgraph = gso->depsgraph; Object *obact = gso->object; - Object *ob_eval = DEG_get_evaluated_object(depsgraph, obact); - bGPdata *gpd = gso->gpd; bool changed = false; + Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id); + bGPdata *gpd = (bGPdata *)ob_eval->data; + /* Calculate brush-specific data which applies equally to all points */ char tool = gso->brush->gpencil_sculpt_tool; switch (tool) { @@ -1793,21 +1725,15 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) } /* Find visible strokes, and perform operations on those if hit */ - CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* If no active frame, don't do anything... */ - if (gpl->actframe == NULL) { - continue; - } - /* Get evaluated frames array data */ - int idx_eval = BLI_findindex(&gpd->layers, gpl); - bGPDframe *gpf_eval = &ob_eval->runtime.gpencil_evaluated_frames[idx_eval]; - if (gpf_eval == NULL) { + if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) { continue; } /* calculate difference matrix */ float diff_mat[4][4]; - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { @@ -1819,7 +1745,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) BKE_gpencil_get_range_selected(gpl, &f_init, &f_end); } - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* Always do active frame; Otherwise, only include selected frames */ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { /* compute multiframe falloff factor */ @@ -1839,12 +1765,13 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) } } else { - /* Apply to active frame's strokes */ - gso->mf_falloff = 1.0f; - changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf_eval, diff_mat); + if (gpl->actframe != NULL) { + /* 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; return changed; } diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 82de633dbd7..6a2012b99ee 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -373,7 +373,7 @@ static void gp_select_same_layer(bContext *C) Scene *scene = CTX_data_scene(C); CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); bGPDstroke *gps; bool found = false; @@ -868,13 +868,12 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd, const int selectmode, const float scale) { - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); bGPDspoint *pt1 = NULL; bGPDspoint *pt2 = NULL; int x0 = 0, y0 = 0, x1 = 0, y1 = 0; int i; bool changed = false; - bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; if (gps->totpoints == 1) { @@ -933,22 +932,22 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd, */ hit = true; if (select) { - pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + pt_active = pt1->runtime.pt_orig; if (pt_active != NULL) { pt_active->flag |= GP_SPOINT_SELECT; } - pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2; + pt_active = pt2->runtime.pt_orig; if (pt_active != NULL) { pt_active->flag |= GP_SPOINT_SELECT; } changed = true; } else { - pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + pt_active = pt1->runtime.pt_orig; if (pt_active != NULL) { pt_active->flag &= ~GP_SPOINT_SELECT; } - pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2; + pt_active = pt2->runtime.pt_orig; if (pt_active != NULL) { pt_active->flag &= ~GP_SPOINT_SELECT; } @@ -965,7 +964,7 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd, /* if stroke mode expand selection */ if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) { for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) { - pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + pt_active = (pt1->runtime.pt_orig) ? pt1->runtime.pt_orig : pt1; if (pt_active != NULL) { if (select) { pt_active->flag |= GP_SPOINT_SELECT; @@ -978,7 +977,7 @@ static bool gp_stroke_do_circle_sel(bGPdata *gpd, } /* expand selection to segment */ - pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1; + pt_active = (pt1->runtime.pt_orig) ? pt1->runtime.pt_orig : pt1; if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) { float r_hita[3], r_hitb[3]; bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT); @@ -1183,16 +1182,16 @@ static int gpencil_generic_select_exec(bContext *C, /* select/deselect points */ GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) { - bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt; int i; bool hit = false; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { + if (pt->runtime.pt_orig == NULL) { continue; } - bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + bGPDspoint *pt_active = pt->runtime.pt_orig; /* convert point coords to screenspace */ const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data); @@ -1230,7 +1229,7 @@ static int gpencil_generic_select_exec(bContext *C, if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) { continue; } - bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; if (sel_op_result) { pt_active->flag |= GP_SPOINT_SELECT; @@ -1475,7 +1474,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op) /* XXX: maybe we should go from the top of the stack down instead... */ GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps) { - bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt; int i; @@ -1704,11 +1703,11 @@ static int gpencil_select_color_exec(bContext *C, wmOperator *op) bool gps_selected = false; /* Check all stroke points. */ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if (pt->mix_color[3] < 0.03f) { + if (pt->vert_color[3] < 0.03f) { continue; } - rgb_to_hsv_compat_v(pt->mix_color, hsv_stroke); + rgb_to_hsv_compat_v(pt->vert_color, hsv_stroke); /* Only check Hue to get full value and saturation ranges. */ if (compare_ff(hsv_stroke[0], hsv_brush[0], threshold)) { pt->flag |= GP_SPOINT_SELECT; diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index 7b57dacd3e4..f9403fd94b0 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -90,14 +90,14 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name) if (gpd_ptr) { if (*gpd_ptr) { bGPdata *gpd = *gpd_ptr; - bGPDlayer *gpl, *gpld; + bGPDlayer *gpld; BKE_gpencil_free_layers(&gpd->layers); /* copy layers */ BLI_listbase_clear(&gpd->layers); - for (gpl = new_gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* make a copy of source layer and its data */ gpld = BKE_gpencil_layer_duplicate(gpl); BLI_addtail(&gpd->layers, gpld); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 8eed1a634f0..6995f7074e8 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -328,7 +328,7 @@ bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr) bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra) { if (ob && ob->data && (ob->type == OB_GPENCIL)) { - bGPDlayer *gpl = BKE_gpencil_layer_getactive(ob->data); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(ob->data); if (gpl) { if (gpl->actframe) { // XXX: assumes that frame has been fetched already @@ -336,7 +336,7 @@ bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra) } else { /* XXX: disabled as could be too much of a penalty */ - /* return BKE_gpencil_layer_find_frame(gpl, cfra); */ + /* return BKE_gpencil_layer_frame_find(gpl, cfra); */ } } } @@ -367,7 +367,7 @@ bool gp_active_layer_poll(bContext *C) return false; } bGPdata *gpd = (bGPdata *)ob->data; - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); return (gpl != NULL); } @@ -553,10 +553,10 @@ bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstr MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); if (gp_style != NULL) { - if (gp_style->flag & GP_STYLE_COLOR_HIDE) { + if (gp_style->flag & GP_MATERIAL_HIDE) { return false; } - if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_STYLE_COLOR_LOCKED)) { + if (((gpl->flag & GP_LAYER_UNLOCK_COLOR) == 0) && (gp_style->flag & GP_MATERIAL_LOCKED)) { return false; } } @@ -640,7 +640,7 @@ void gp_apply_parent( float inverse_diff_mat[4][4]; float fpt[3]; - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); for (i = 0; i < gps->totpoints; i++) { @@ -661,7 +661,7 @@ void gp_apply_parent_point( float inverse_diff_mat[4][4]; float fpt[3]; - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); mul_v3_m4v3(fpt, inverse_diff_mat, &pt->x); @@ -867,7 +867,7 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc, const RegionView3D *rv3d = gsc->ar->regiondata; float rvec[3]; - ED_gp_get_drawing_reference( + ED_gpencil_drawing_reference_get( scene, gsc->ob, gsc->gpl, scene->toolsettings->gpencil_v3d_align, rvec); float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL); @@ -927,7 +927,7 @@ void gp_stroke_convertcoords_tpoint(Scene *scene, /* Current method just converts each point in screen-coordinates to * 3D-coordinates using the 3D-cursor as reference. */ - ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, rvec); + ED_gpencil_drawing_reference_get(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) { @@ -945,7 +945,7 @@ void gp_stroke_convertcoords_tpoint(Scene *scene, * Get drawing reference point for conversion or projection of the stroke * \param[out] r_vec : Reference point found */ -void ED_gp_get_drawing_reference( +void ED_gpencil_drawing_reference_get( const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl), char align_flag, float r_vec[3]) { const float *fp = scene->cursor.location; @@ -975,7 +975,6 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * Scene *scene = CTX_data_scene(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *ob = CTX_data_active_object(C); - bGPdata *gpd = (bGPdata *)ob->data; GP_SpaceConversion gsc = {NULL}; bGPDspoint *pt; @@ -986,7 +985,7 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); - ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat); invert_m4_m4(inverse_diff_mat, diff_mat); /* Adjust each point */ @@ -1178,7 +1177,6 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide) if (gps->dvert != NULL) { gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; /* move points from last to first to new place */ i2 = gps->totpoints - 1; @@ -1193,7 +1191,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide) pt_final->flag = pt->flag; pt_final->uv_fac = pt->uv_fac; pt_final->uv_rot = pt->uv_rot; - copy_v4_v4(pt_final->mix_color, pt->mix_color); + copy_v4_v4(pt_final->vert_color, pt->vert_color); if (gps->dvert != NULL) { MDeformVert *dvert = &gps->dvert[i]; @@ -1220,7 +1218,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide) 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); - interp_v4_v4v4(pt_final->mix_color, pt->mix_color, next->mix_color, 0.5f); + interp_v4_v4v4(pt_final->vert_color, pt->vert_color, next->vert_color, 0.5f); if (gps->dvert != NULL) { MDeformVert *dvert_final = &gps->dvert[i2]; @@ -1249,63 +1247,11 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int subdivide) /* free temp memory */ MEM_SAFE_FREE(temp_points); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } -/* ******************************************************** */ -/* Layer Parenting - Compute Parent Transforms */ - -/* calculate difference matrix */ -void ED_gpencil_parent_location(const Depsgraph *depsgraph, - Object *obact, - bGPdata *UNUSED(gpd), - bGPDlayer *gpl, - float diff_mat[4][4]) -{ - 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, obparent_eval->obmat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); - return; - } - else if (gpl->partype == PARBONE) { - bPoseChannel *pchan = BKE_pose_channel_find_name(obparent_eval->pose, gpl->parsubstr); - if (pchan) { - float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, obparent_eval->obmat, pchan->pose_mat); - mul_m4_m4m4(diff_mat, tmp_mat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); - } - else { - /* if bone not found use object (armature) */ - mul_m4_m4m4(diff_mat, obparent_eval->obmat, gpl->inverse); - add_v3_v3(diff_mat[3], ob_eval->obmat[3]); - } - return; - } - else { - unit_m4(diff_mat); /* not defined type */ - } - } -} - -/* reset parent matrix for all layers */ +/* Reset parent matrix for all layers. */ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata *gpd) { bGPDspoint *pt; @@ -1315,7 +1261,7 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata float gpl_loc[3]; zero_v3(gpl_loc); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->parent != NULL) { /* calculate new matrix */ if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { @@ -1335,12 +1281,12 @@ void ED_gpencil_reset_layers_parent(Depsgraph *depsgraph, Object *obact, bGPdata /* only redo if any change */ if (!equals_m4m4(gpl->inverse, cur_mat)) { /* first apply current transformation to all strokes */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); /* undo local object */ sub_v3_v3(diff_mat[3], gpl_loc); - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { mul_m4_v3(diff_mat, &pt->x); } @@ -1742,7 +1688,7 @@ static void gp_brush_cursor_draw(bContext *C, int x, int y, void *customdata) } /* get current drawing color */ - ma = BKE_gpencil_object_material_get_from_brush(ob, brush); + ma = BKE_gpencil_object_material_from_brush_get(ob, brush); if (ma) { gp_style = ma->gp_style; @@ -1995,6 +1941,7 @@ void ED_gpencil_tpoint_to_point(ARegion *ar, float origin[3], const tGPspoint *t /* conversion to 3d format */ gpencil_stroke_convertcoords(ar, tpt, origin, p3d); copy_v3_v3(&pt->x, p3d); + zero_v4(pt->vert_color); pt->pressure = tpt->pressure; pt->strength = tpt->strength; @@ -2002,63 +1949,6 @@ void ED_gpencil_tpoint_to_point(ARegion *ar, float origin[3], const tGPspoint *t 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_gpencil_material_settings(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.0001f; - } - pixsize = MAX2(pixsize, 0.0000001f); - - bGPDspoint *pt = NULL; - bGPDspoint *ptb = NULL; - int i; - float totlen = 0.0f; - - /* 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->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && - (gp_style->sima)) { - factor = gp_style->sima->gen_x; - } - else if (totlen == 0) { - return; - } - 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) { @@ -2071,11 +1961,11 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat) continue; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* 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) { + if (BKE_gpencil_layer_is_editable(gpl)) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* check if it is editable */ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) { continue; @@ -2083,7 +1973,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat) gps_ma = BKE_gpencil_material(ob, gps->mat_nr + 1); /* update */ if ((gps_ma) && (gps_ma == mat)) { - ED_gpencil_calc_stroke_uv(ob, gps); + BKE_gpencil_stroke_uv_update(gps); } } } @@ -2160,7 +2050,7 @@ static void gp_copy_points(bGPDstroke *gps, bGPDspoint *pt, bGPDspoint *pt_final pt_final->flag = pt->flag; pt_final->uv_fac = pt->uv_fac; pt_final->uv_rot = pt->uv_rot; - copy_v4_v4(pt_final->mix_color, pt->mix_color); + copy_v4_v4(pt_final->vert_color, pt->vert_color); if (gps->dvert != NULL) { MDeformVert *dvert = &gps->dvert[i]; @@ -2215,7 +2105,6 @@ static void gp_insert_point( if (gps->dvert != NULL) { gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); } - gps->flag |= GP_STROKE_RECALC_GEOMETRY; /* copy all points */ int i2 = 0; @@ -2239,6 +2128,8 @@ static void gp_insert_point( i2++; } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); MEM_SAFE_FREE(temp_points); } @@ -2482,10 +2373,9 @@ void ED_gpencil_select_toggle_all(bContext *C, int action) * nothing should be able to touch it */ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - bGPDframe *gpf; /* deselect all strokes on all frames */ - for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { bGPDstroke *gps; for (gps = gpf->strokes.first; gps; gps = gps->next) { @@ -2582,6 +2472,21 @@ tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array, return buffer_array; } +void ED_gpencil_sbuffer_update_eval(Depsgraph *depsgraph, Object *ob) +{ + bGPdata *gpd = (bGPdata *)ob->data; + + Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id); + bGPdata *gpd_eval = (bGPdata *)ob_eval->data; + + gpd_eval->runtime.sbuffer = gpd->runtime.sbuffer; + gpd_eval->runtime.sbuffer_sflag = gpd->runtime.sbuffer_sflag; + gpd_eval->runtime.sbuffer_used = gpd->runtime.sbuffer_used; + gpd_eval->runtime.sbuffer_size = gpd->runtime.sbuffer_size; + gpd_eval->runtime.tot_cp_points = gpd->runtime.tot_cp_points; + gpd_eval->runtime.cp_points = gpd->runtime.cp_points; +} + /* Tag all scene grease pencil object to update. */ void ED_gpencil_tag_scene_gpencil(Scene *scene) { @@ -2602,3 +2507,87 @@ void ED_gpencil_tag_scene_gpencil(Scene *scene) WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } + +void ED_gpencil_fill_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDstroke *gps) +{ + if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) { + copy_v3_v3(gps->vert_color_fill, brush->rgb); + gps->vert_color_fill[3] = brush->gpencil_settings->vertex_factor; + srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill); + } + else { + zero_v4(gps->vert_color_fill); + } +} + +void ED_gpencil_point_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDspoint *pt) +{ + if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) { + copy_v3_v3(pt->vert_color, brush->rgb); + pt->vert_color[3] = brush->gpencil_settings->vertex_factor; + srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color); + } + else { + zero_v4(pt->vert_color); + } +} + +void ED_gpencil_sbuffer_vertex_color_set(ToolSettings *ts, Brush *brush, bGPdata *gpd) +{ + float vertex_color[4]; + copy_v3_v3(vertex_color, brush->rgb); + vertex_color[3] = brush->gpencil_settings->vertex_factor; + srgb_to_linearrgb_v4(vertex_color, vertex_color); + + /* Copy fill vertex color. */ + if (GPENCIL_USE_VERTEX_COLOR_FILL(ts, brush)) { + copy_v4_v4(gpd->runtime.vert_color_fill, vertex_color); + } + else { + zero_v4(gpd->runtime.vert_color_fill); + } + /* Copy stroke vertex color. */ + if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) { + copy_v4_v4(gpd->runtime.vert_color, vertex_color); + } + else { + zero_v4(gpd->runtime.vert_color); + } +} + +/* Check if the stroke collides with brush. */ +bool ED_gpencil_stroke_check_collision(GP_SpaceConversion *gsc, + bGPDstroke *gps, + float mouse[2], + const int radius, + const float diff_mat[4][4]) +{ + const int offset = (int)ceil(sqrt((radius * radius) * 2)); + bGPDspoint pt_dummy, pt_dummy_ps; + float gps_collision_min[2] = {0.0f}; + float gps_collision_max[2] = {0.0f}; + float zerov3[3]; + + /* Check we have something to use (only for old files). */ + if (equals_v3v3(zerov3, gps->collision_min)) { + BKE_gpencil_stroke_collision_get(gps); + } + + /* Convert bound box to 2d */ + copy_v3_v3(&pt_dummy.x, gps->collision_min); + gp_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps); + gp_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &gps_collision_min[0], &gps_collision_min[1]); + + copy_v3_v3(&pt_dummy.x, gps->collision_max); + gp_point_to_parent_space(&pt_dummy, diff_mat, &pt_dummy_ps); + gp_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &gps_collision_max[0], &gps_collision_max[1]); + + rcti rect_stroke = { + gps_collision_min[0], gps_collision_max[0], gps_collision_min[1], gps_collision_max[1]}; + + /* For mouse, add a small offet to avoid false negative in corners. */ + rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset}; + + /* Check collision between both rectangles. */ + return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL); +} diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index e5f2bd76d0a..b38b2d9fb7d 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -171,7 +171,6 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is } /* Calc selected strokes center. */ - bGPdata *gpd = opdata->gpd; zero_v2(opdata->mcenter); float center[3] = {0.0f}; int i = 0; @@ -240,9 +239,9 @@ static void gpencil_uv_transform_exit(bContext *C, wmOperator *op) static void gpencil_transform_fill_cancel(bContext *C, wmOperator *op) { - GpUvData *opdata; + GpUvData *opdata = op->customdata; + UNUSED_VARS(opdata); - opdata = op->customdata; gpencil_uv_transform_exit(C, op); /* need to force redisplay or we may still view the modified result */ @@ -299,7 +298,8 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) else { copy_v2_v2(gps->uv_translation, location); } - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); i++; } } @@ -313,7 +313,8 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { gps->uv_rotation = (opdata->is_modal) ? opdata->array_rot[i] + uv_rotation : uv_rotation; - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); i++; } } @@ -340,7 +341,8 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op) GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) { if (gps->flag & GP_STROKE_SELECT) { gps->uv_scale = (opdata->is_modal) ? opdata->array_scale[i] + scale : scale; - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); i++; } } @@ -384,7 +386,7 @@ static bool gpencil_transform_fill_poll(bContext *C) return false; } - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); if ((gpl == NULL) || (ob->mode != OB_MODE_EDIT_GPENCIL)) { return false; @@ -542,7 +544,8 @@ static int gpencil_reset_transform_fill_exec(bContext *C, wmOperator *op) if ((mode == GP_UV_SCALE) || (mode == GP_UV_ALL)) { gps->uv_scale = 1.0f; } - gps->tot_triangles = 0; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); changed = true; } } diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 2226257f6a6..348655d5fe9 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -137,9 +137,9 @@ static int gp_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { changed = true; if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->mix_color_fill[3] > 0.0f) { + if (gps->vert_color_fill[3] > 0.0f) { for (int i2 = 0; i2 < 3; i2++) { - gps->mix_color_fill[i2] = gain * gps->mix_color_fill[i2] + offset; + gps->vert_color_fill[i2] = gain * gps->vert_color_fill[i2] + offset; } } } @@ -148,9 +148,9 @@ static int gp_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator *op) /* Stroke points. */ if (mode != GP_PAINT_VERTEX_FILL) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->mix_color[3] > 0.0f)) { + if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { for (int i2 = 0; i2 < 3; i2++) { - pt->mix_color[i2] = gain * pt->mix_color[i2] + offset; + pt->vert_color[i2] = gain * pt->vert_color[i2] + offset; } } } @@ -214,9 +214,9 @@ static int gp_vertexpaint_hsv_exec(bContext *C, wmOperator *op) /* Fill color. */ if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->mix_color_fill[3] > 0.0f) { + if (gps->vert_color_fill[3] > 0.0f) { - rgb_to_hsv_v(gps->mix_color_fill, hsv); + rgb_to_hsv_v(gps->vert_color_fill, hsv); hsv[0] += (hue - 0.5f); if (hsv[0] > 1.0f) { @@ -228,15 +228,15 @@ static int gp_vertexpaint_hsv_exec(bContext *C, wmOperator *op) hsv[1] *= sat; hsv[2] *= val; - hsv_to_rgb_v(hsv, gps->mix_color_fill); + hsv_to_rgb_v(hsv, gps->vert_color_fill); } } /* Stroke points. */ if (mode != GP_PAINT_VERTEX_FILL) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->mix_color[3] > 0.0f)) { - rgb_to_hsv_v(pt->mix_color, hsv); + if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { + rgb_to_hsv_v(pt->vert_color, hsv); hsv[0] += (hue - 0.5f); if (hsv[0] > 1.0f) { @@ -248,7 +248,7 @@ static int gp_vertexpaint_hsv_exec(bContext *C, wmOperator *op) hsv[1] *= sat; hsv[2] *= val; - hsv_to_rgb_v(hsv, pt->mix_color); + hsv_to_rgb_v(hsv, pt->vert_color); } } } @@ -305,9 +305,9 @@ static int gp_vertexpaint_invert_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { changed = true; if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->mix_color_fill[3] > 0.0f) { + if (gps->vert_color_fill[3] > 0.0f) { for (int i2 = 0; i2 < 3; i2++) { - gps->mix_color_fill[i2] = 1.0f - gps->mix_color_fill[i2]; + gps->vert_color_fill[i2] = 1.0f - gps->vert_color_fill[i2]; } } } @@ -316,9 +316,9 @@ static int gp_vertexpaint_invert_exec(bContext *C, wmOperator *op) /* Stroke points. */ if (mode != GP_PAINT_VERTEX_FILL) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->mix_color[3] > 0.0f)) { + if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { for (int i2 = 0; i2 < 3; i2++) { - pt->mix_color[i2] = 1.0f - pt->mix_color[i2]; + pt->vert_color[i2] = 1.0f - pt->vert_color[i2]; } } } @@ -374,9 +374,9 @@ static int gp_vertexpaint_levels_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { changed = true; if (mode != GP_PAINT_VERTEX_STROKE) { - if (gps->mix_color_fill[3] > 0.0f) { + if (gps->vert_color_fill[3] > 0.0f) { for (int i2 = 0; i2 < 3; i2++) { - gps->mix_color_fill[i2] = gain * (gps->mix_color_fill[i2] + offset); + gps->vert_color_fill[i2] = gain * (gps->vert_color_fill[i2] + offset); } } } @@ -385,9 +385,9 @@ static int gp_vertexpaint_levels_exec(bContext *C, wmOperator *op) /* Stroke points. */ if (mode != GP_PAINT_VERTEX_FILL) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - if ((pt->flag & GP_SPOINT_SELECT) && (pt->mix_color[3] > 0.0f)) { + if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) { for (int i2 = 0; i < 3; i2++) { - pt->mix_color[i2] = gain * (pt->mix_color[i2] + offset); + pt->vert_color[i2] = gain * (pt->vert_color[i2] + offset); } } } @@ -450,8 +450,8 @@ static int gp_vertexpaint_set_exec(bContext *C, wmOperator *op) if (gps->flag & GP_STROKE_SELECT) { changed = true; if (mode != GP_PAINT_VERTEX_STROKE) { - copy_v3_v3(gps->mix_color_fill, brush->rgb); - gps->mix_color_fill[3] = factor; + copy_v3_v3(gps->vert_color_fill, brush->rgb); + gps->vert_color_fill[3] = factor; } } @@ -459,8 +459,8 @@ static int gp_vertexpaint_set_exec(bContext *C, wmOperator *op) if (mode != GP_PAINT_VERTEX_FILL) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { if (pt->flag & GP_SPOINT_SELECT) { - copy_v3_v3(pt->mix_color, brush->rgb); - pt->mix_color[3] = factor; + copy_v3_v3(pt->vert_color, brush->rgb); + pt->vert_color[3] = factor; } } } @@ -509,8 +509,8 @@ static bool gp_extract_palette_from_vertex(bContext *C, const bool selected, con /* Extract all colors. */ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } @@ -526,8 +526,8 @@ static bool gp_extract_palette_from_vertex(bContext *C, const bool selected, con continue; } - bool use_stroke = (gp_style->flag & GP_STYLE_STROKE_SHOW); - bool use_fill = (gp_style->flag & GP_STYLE_FILL_SHOW); + bool use_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW); + bool use_fill = (gp_style->flag & GP_MATERIAL_FILL_SHOW); /* Material is disabled. */ if ((!use_fill) && (!use_stroke)) { @@ -535,21 +535,21 @@ static bool gp_extract_palette_from_vertex(bContext *C, const bool selected, con } /* Only solid strokes or stencil. */ - if ((use_stroke) && ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && - ((gp_style->flag & GP_STYLE_STROKE_PATTERN) == 0))) { + if ((use_stroke) && ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && + ((gp_style->flag & GP_MATERIAL_STROKE_PATTERN) == 0))) { continue; } /* Only solid fill. */ - if ((use_fill) && (gp_style->fill_style != GP_STYLE_FILL_STYLE_SOLID)) { + if ((use_fill) && (gp_style->fill_style != GP_MATERIAL_FILL_STYLE_SOLID)) { continue; } /* Fill color. */ - if (gps->mix_color_fill[3] > 0.0f) { - col[0] = truncf(gps->mix_color_fill[0] * range) / range; - col[1] = truncf(gps->mix_color_fill[1] * range) / range; - col[2] = truncf(gps->mix_color_fill[2] * range) / range; + if (gps->vert_color_fill[3] > 0.0f) { + col[0] = truncf(gps->vert_color_fill[0] * range) / range; + col[1] = truncf(gps->vert_color_fill[1] * range) / range; + col[2] = truncf(gps->vert_color_fill[2] * range) / range; uint key = rgb_to_cpack(col[0], col[1], col[2]); @@ -562,9 +562,9 @@ static bool gp_extract_palette_from_vertex(bContext *C, const bool selected, con bGPDspoint *pt; int i; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - col[0] = truncf(pt->mix_color[0] * range) / range; - col[1] = truncf(pt->mix_color[1] * range) / range; - col[2] = truncf(pt->mix_color[2] * range) / range; + col[0] = truncf(pt->vert_color[0] * range) / range; + col[1] = truncf(pt->vert_color[1] * range) / range; + col[2] = truncf(pt->vert_color[2] * range) / range; uint key = rgb_to_cpack(col[0], col[1], col[2]); if (!BLI_ghash_haskey(color_table, POINTER_FROM_INT(key))) { @@ -600,17 +600,17 @@ static uint get_material_type(MaterialGPencilStyle *gp_style, uint r_i = 0; if ((use_stroke) && (use_fill)) { switch (gp_style->mode) { - case GP_STYLE_MODE_LINE: { + case GP_MATERIAL_MODE_LINE: { r_i = 1; strcpy(name, "Line Stroke-Fill"); break; } - case GP_STYLE_MODE_DOTS: { + case GP_MATERIAL_MODE_DOT: { r_i = 2; strcpy(name, "Dots Stroke-Fill"); break; } - case GP_STYLE_MODE_BOX: { + case GP_MATERIAL_MODE_SQUARE: { r_i = 3; strcpy(name, "Boxes Stroke-Fill"); break; @@ -621,17 +621,17 @@ static uint get_material_type(MaterialGPencilStyle *gp_style, } else if (use_stroke) { switch (gp_style->mode) { - case GP_STYLE_MODE_LINE: { + case GP_MATERIAL_MODE_LINE: { r_i = 4; strcpy(name, "Line Stroke"); break; } - case GP_STYLE_MODE_DOTS: { + case GP_MATERIAL_MODE_DOT: { r_i = 5; strcpy(name, "Dots Stroke"); break; } - case GP_STYLE_MODE_BOX: { + case GP_MATERIAL_MODE_SQUARE: { r_i = 6; strcpy(name, "Boxes Stroke"); break; @@ -695,8 +695,8 @@ static int gp_material_to_vertex_exec(bContext *C, wmOperator *op) /* Update stroke material index. */ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; } @@ -713,23 +713,25 @@ static int gp_material_to_vertex_exec(bContext *C, wmOperator *op) continue; } - bool use_stroke = (gp_style->flag & GP_STYLE_STROKE_SHOW); - bool use_fill = (gp_style->flag & GP_STYLE_FILL_SHOW); - bool is_stencil = ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && - (gp_style->flag & GP_STYLE_STROKE_PATTERN)); + bool use_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) && + (gp_style->stroke_rgba[3] > 0.0f)); + bool use_fill = ((gp_style->flag & GP_MATERIAL_FILL_SHOW) && + (gp_style->fill_rgba[3] > 0.0f)); + bool is_stencil = ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && + (gp_style->flag & GP_MATERIAL_STROKE_PATTERN)); /* Material is disabled. */ if ((!use_fill) && (!use_stroke)) { continue; } /* Only solid strokes or stencil. */ - if ((use_stroke) && ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && - ((gp_style->flag & GP_STYLE_STROKE_PATTERN) == 0))) { + if ((use_stroke) && ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && + ((gp_style->flag & GP_MATERIAL_STROKE_PATTERN) == 0))) { continue; } /* Only solid fill. */ - if ((use_fill) && (gp_style->fill_style != GP_STYLE_FILL_STYLE_SOLID)) { + if ((use_fill) && (gp_style->fill_style != GP_MATERIAL_FILL_STYLE_SOLID)) { continue; } @@ -755,17 +757,17 @@ static int gp_material_to_vertex_exec(bContext *C, wmOperator *op) if (!found) { ma = BKE_gpencil_material_add(bmain, name); if (use_stroke) { - ma->gp_style->flag |= GP_STYLE_STROKE_SHOW; + ma->gp_style->flag |= GP_MATERIAL_STROKE_SHOW; } else { - ma->gp_style->flag &= ~GP_STYLE_STROKE_SHOW; + ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW; } if (use_fill) { - ma->gp_style->flag |= GP_STYLE_FILL_SHOW; + ma->gp_style->flag |= GP_MATERIAL_FILL_SHOW; } else { - ma->gp_style->flag &= ~GP_STYLE_FILL_SHOW; + ma->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW; } ma->gp_style->stroke_rgba[3] = gp_style->stroke_rgba[3]; @@ -787,14 +789,14 @@ static int gp_material_to_vertex_exec(bContext *C, wmOperator *op) } changed = true; - copy_v3_v3(gps->mix_color_fill, gp_style->fill_rgba); - gps->mix_color_fill[3] = 1.0f; + copy_v3_v3(gps->vert_color_fill, gp_style->fill_rgba); + gps->vert_color_fill[3] = 1.0f; /* Update all points. */ bGPDspoint *pt; for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - copy_v3_v3(pt->mix_color, gp_style->stroke_rgba); - pt->mix_color[3] = 1.0f; + copy_v3_v3(pt->vert_color, gp_style->stroke_rgba); + pt->vert_color[3] = 1.0f; } } } diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index a9fc9513b15..7b590a7c052 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -386,7 +386,7 @@ static void gp_grid_colors_calc(tGP_BrushVertexpaintData *gso) if (grid_index > -1) { grid = &gso->grid[grid_index]; /* Add stroke mix color (only if used). */ - if (pt->mix_color[3] > 0.0f) { + if (pt->vert_color[3] > 0.0f) { add_v3_v3(grid->color, selected->color); grid->color[3] = 1.0f; grid->totcol++; @@ -412,7 +412,7 @@ static void gp_grid_colors_calc(tGP_BrushVertexpaintData *gso) /* ************************************************ */ /* Brush Callbacks -/* This section defines the callbacks used by each brush to perform their magic. + * This section defines the callbacks used by each brush to perform their magic. * These are called on each point within the brush's radius. */ /* Tint Brush */ @@ -434,35 +434,42 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso, bGPDspoint *pt = &gps->points[pt_index]; - float alpha = pt->mix_color[3]; - float alpha_fill = gps->mix_color_fill[3]; - - if (brush_invert_check(gso)) { - alpha -= inf; - alpha_fill -= inf_fill; - } - else { - alpha += inf; - alpha_fill += inf_fill; - } - /* Apply color to Stroke point. */ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) { - CLAMP(alpha, 0.0f, 1.0f); - interp_v3_v3v3(pt->mix_color, pt->mix_color, brush->rgb, inf); - pt->mix_color[3] = alpha; + if (brush_invert_check(gso)) { + pt->vert_color[3] -= inf; + CLAMP_MIN(pt->vert_color[3], 0.0f); + } + else { + /* Premult. */ + mul_v3_fl(pt->vert_color, pt->vert_color[3]); + /* "Alpha over" blending. */ + interp_v3_v3v3(pt->vert_color, pt->vert_color, brush->rgb, inf); + pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf; + /* Un-premult. */ + if (pt->vert_color[3] > 0.0f) { + mul_v3_fl(pt->vert_color, 1.0f / pt->vert_color[3]); + } + } } /* Apply color to Fill area (all with same color and factor). */ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) { - CLAMP(alpha_fill, 0.0f, 1.0f); - if (equals_v3v3(gps->mix_color_fill, brush->rgb)) { - copy_v3_v3(gps->mix_color_fill, brush->rgb); + if (brush_invert_check(gso)) { + gps->vert_color_fill[3] -= inf_fill; + CLAMP_MIN(gps->vert_color_fill[3], 0.0f); } else { - interp_v3_v3v3(gps->mix_color_fill, gps->mix_color_fill, brush->rgb, inf_fill); + /* Premult. */ + mul_v3_fl(gps->vert_color_fill, gps->vert_color_fill[3]); + /* "Alpha over" blending. */ + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, brush->rgb, inf_fill); + gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill; + /* Un-premult. */ + if (gps->vert_color_fill[3] > 0.0f) { + mul_v3_fl(gps->vert_color_fill, 1.0f / gps->vert_color_fill[3]); + } } - gps->mix_color_fill[3] = alpha_fill; } return true; @@ -476,19 +483,19 @@ static bool brush_replace_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, /* Apply color to Stroke point. */ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) { - copy_v3_v3(pt->mix_color, brush->rgb); + copy_v3_v3(pt->vert_color, brush->rgb); /* If not mix color, full replace. */ - if (pt->mix_color[3] == 0.0f) { - pt->mix_color[3] = 1.0f; + if (pt->vert_color[3] == 0.0f) { + pt->vert_color[3] = 1.0f; } } /* Apply color to Fill area (all with same color and factor). */ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) { - copy_v3_v3(gps->mix_color_fill, brush->rgb); + copy_v3_v3(gps->vert_color_fill, brush->rgb); /* If not mix color, full replace. */ - if (gps->mix_color_fill[3] == 0.0f) { - gps->mix_color_fill[3] = 1.0f; + if (gps->vert_color_fill[3] == 0.0f) { + gps->vert_color_fill[3] = 1.0f; } } @@ -520,7 +527,7 @@ static bool get_surrounding_color(tGP_BrushVertexpaintData *gso, pt = &gps_selected->points[selected->pt_index]; /* Add stroke mix color (only if used). */ - if (pt->mix_color[3] > 0.0f) { + if (pt->vert_color[3] > 0.0f) { add_v3_v3(r_color, selected->color); totcol++; } @@ -554,12 +561,12 @@ static bool brush_blur_apply(tGP_BrushVertexpaintData *gso, if (get_surrounding_color(gso, gps, pt_index, blur_color)) { /* Apply color to Stroke point. */ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) { - interp_v3_v3v3(pt->mix_color, pt->mix_color, blur_color, inf); + interp_v3_v3v3(pt->vert_color, pt->vert_color, blur_color, inf); } /* Apply color to Fill area (all with same color and factor). */ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) { - interp_v3_v3v3(gps->mix_color_fill, gps->mix_color_fill, blur_color, inf_fill); + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, blur_color, inf_fill); } return true; } @@ -584,8 +591,8 @@ static bool brush_average_apply(tGP_BrushVertexpaintData *gso, bGPDspoint *pt = &gps->points[pt_index]; - float alpha = pt->mix_color[3]; - float alpha_fill = gps->mix_color_fill[3]; + float alpha = pt->vert_color[3]; + float alpha_fill = gps->vert_color_fill[3]; if (brush_invert_check(gso)) { alpha -= inf; @@ -599,15 +606,15 @@ static bool brush_average_apply(tGP_BrushVertexpaintData *gso, /* Apply color to Stroke point. */ if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) { CLAMP(alpha, 0.0f, 1.0f); - interp_v3_v3v3(pt->mix_color, pt->mix_color, average_color, inf); - pt->mix_color[3] = alpha; + interp_v3_v3v3(pt->vert_color, pt->vert_color, average_color, inf); + pt->vert_color[3] = alpha; } /* Apply color to Fill area (all with same color and factor). */ if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) { CLAMP(alpha_fill, 0.0f, 1.0f); - copy_v3_v3(gps->mix_color_fill, average_color); - gps->mix_color_fill[3] = alpha_fill; + copy_v3_v3(gps->vert_color_fill, average_color); + gps->vert_color_fill[3] = alpha_fill; } return true; @@ -672,8 +679,8 @@ static bool brush_smear_apply(tGP_BrushVertexpaintData *gso, if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)) { if (grid_index > -1) { if (grid->color[3] > 0.0f) { - // copy_v3_v3(pt->mix_color, grid->color); - interp_v3_v3v3(pt->mix_color, pt->mix_color, grid->color, inf); + // copy_v3_v3(pt->vert_color, grid->color); + interp_v3_v3v3(pt->vert_color, pt->vert_color, grid->color, inf); changed = true; } } @@ -683,7 +690,7 @@ static bool brush_smear_apply(tGP_BrushVertexpaintData *gso, if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) { if (grid_index > -1) { if (grid->color[3] > 0.0f) { - interp_v3_v3v3(gps->mix_color_fill, gps->mix_color_fill, grid->color, inf); + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, grid->color, inf); changed = true; } } @@ -810,7 +817,7 @@ static void gp_save_selected_point(tGP_BrushVertexpaintData *gso, selected->gps = gps; selected->pt_index = index; copy_v2_v2_int(selected->pc, pc); - copy_v4_v4(selected->color, pt->mix_color); + copy_v4_v4(selected->color, pt->vert_color); gso->pbuffer_used++; } @@ -825,8 +832,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, Brush *brush = gso->brush; const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd); - bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; bGPDspoint *pt1, *pt2; @@ -837,13 +843,18 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, int index; bool include_last = false; + /* Check if the stroke collide with brush. */ + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) { + return; + } + if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; /* 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 */ @@ -894,8 +905,8 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, /* To each point individually... */ pt = &gps->points[i]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { gp_save_selected_point(gso, gps_active, index, pc1); } @@ -910,8 +921,8 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, */ if (i + 1 == gps->totpoints - 1) { pt = &gps->points[i + 1]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; if (pt_active != NULL) { gp_save_selected_point(gso, gps_active, index, pc2); include_last = false; @@ -928,8 +939,8 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, * (but wasn't added then, to avoid double-ups). */ pt = &gps->points[i]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { gp_save_selected_point(gso, gps_active, index, pc1); @@ -962,7 +973,7 @@ static bool gp_vertexpaint_brush_do_frame(bContext *C, * all selected points before apply the effect, because it could be * required to average data. *--------------------------------------------------------------------- */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* Skip strokes that are invalid for current view. */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; @@ -987,14 +998,14 @@ static bool gp_vertexpaint_brush_do_frame(bContext *C, bGPDspoint *pt = &gps->points[selected->pt_index]; /* Add stroke mix color (only if used). */ - if (pt->mix_color[3] > 0.0f) { - add_v3_v3(average_color, pt->mix_color); + if (pt->vert_color[3] > 0.0f) { + add_v3_v3(average_color, pt->vert_color); totcol++; } /* If Fill color mix, add to average. */ - if (gps->mix_color_fill[3] > 0.0f) { - add_v3_v3(average_color, gps->mix_color_fill); + if (gps->vert_color_fill[3] > 0.0f) { + add_v3_v3(average_color, gps->vert_color_fill); totcol++; } } @@ -1060,26 +1071,21 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai ToolSettings *ts = CTX_data_tool_settings(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obact = gso->object; - Object *ob_eval = DEG_get_evaluated_object(depsgraph, obact); - bGPdata *gpd = gso->gpd; bool changed = false; + Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id); + bGPdata *gpd = (bGPdata *)ob_eval->data; + /* Find visible strokes, and perform operations on those if hit */ - CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - /* If no active frame, don't do anything... */ - if (gpl->actframe == NULL) { - continue; - } - /* Get evaluated frames array data */ - int idx_eval = BLI_findindex(&gpd->layers, gpl); - bGPDframe *gpf_eval = &ob_eval->runtime.gpencil_evaluated_frames[idx_eval]; - if (gpf_eval == NULL) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + /* If locked or no active frame, don't do anything. */ + if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) { continue; } /* calculate difference matrix */ float diff_mat[4][4]; - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { @@ -1091,7 +1097,7 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai BKE_gpencil_get_range_selected(gpl, &f_init, &f_end); } - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* Always do active frame; Otherwise, only include selected frames */ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { /* compute multiframe falloff factor */ @@ -1113,11 +1119,12 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai } else { /* Apply to active frame's strokes */ - gso->mf_falloff = 1.0f; - changed |= gp_vertexpaint_brush_do_frame(C, gso, gpl, gpf_eval, diff_mat); + if (gpl->actframe != NULL) { + gso->mf_falloff = 1.0f; + changed |= gp_vertexpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + } } } - CTX_DATA_END; return changed; } diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index 8a07af5c6f4..3d8073ec045 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -246,7 +246,7 @@ static void brush_calc_dvec_2d(tGP_BrushWeightpaintData *gso) /* ************************************************ */ /* Brush Callbacks -/* This section defines the callbacks used by each brush to perform their magic. + * This section defines the callbacks used by each brush to perform their magic. * These are called on each point within the brush's radius. */ /* Draw Brush */ @@ -421,7 +421,7 @@ static void gp_save_selected_point(tGP_BrushWeightpaintData *gso, selected->gps = gps; selected->pt_index = index; copy_v2_v2_int(selected->pc, pc); - copy_v4_v4(selected->color, pt->mix_color); + copy_v4_v4(selected->color, pt->vert_color); gso->pbuffer_used++; } @@ -436,8 +436,7 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, Brush *brush = gso->brush; const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure : gso->brush->size; - const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd); - bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps; + bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps; bGPDspoint *pt_active = NULL; bGPDspoint *pt1, *pt2; @@ -448,13 +447,18 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, int index; bool include_last = false; + /* Check if the stroke collide with brush. */ + if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, diff_mat)) { + return; + } + if (gps->totpoints == 1) { bGPDspoint pt_temp; pt = &gps->points[0]; gp_point_to_parent_space(gps->points, diff_mat, &pt_temp); gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; /* 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 */ @@ -496,8 +500,8 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, /* To each point individually... */ pt = &gps->points[i]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { gp_save_selected_point(gso, gps_active, index, pc1); } @@ -512,8 +516,8 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, */ if (i + 1 == gps->totpoints - 1) { pt = &gps->points[i + 1]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1; if (pt_active != NULL) { gp_save_selected_point(gso, gps_active, index, pc2); include_last = false; @@ -530,8 +534,8 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, * (but wasn't added then, to avoid double-ups). */ pt = &gps->points[i]; - pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt; - index = (!is_multiedit) ? pt->runtime.idx_orig : i; + pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; + index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i; if (pt_active != NULL) { gp_save_selected_point(gso, gps_active, index, pc1); @@ -563,7 +567,7 @@ static bool gp_weightpaint_brush_do_frame(bContext *C, * all selected points before apply the effect, because it could be * required to do some step. Now is not used, but the operator is ready. *--------------------------------------------------------------------- */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* Skip strokes that are invalid for current view. */ if (ED_gpencil_stroke_can_use(C, gps) == false) { continue; @@ -609,26 +613,21 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai ToolSettings *ts = CTX_data_tool_settings(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obact = gso->object; - Object *ob_eval = DEG_get_evaluated_object(depsgraph, obact); - bGPdata *gpd = gso->gpd; bool changed = false; + Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id); + bGPdata *gpd = (bGPdata *)ob_eval->data; + /* Find visible strokes, and perform operations on those if hit */ - CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { - /* If no active frame, don't do anything... */ - if (gpl->actframe == NULL) { - continue; - } - /* Get evaluated frames array data */ - int idx_eval = BLI_findindex(&gpd->layers, gpl); - bGPDframe *gpf_eval = &ob_eval->runtime.gpencil_evaluated_frames[idx_eval]; - if (gpf_eval == NULL) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + /* If locked or no active frame, don't do anything. */ + if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) { continue; } /* calculate difference matrix */ float diff_mat[4][4]; - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { @@ -640,7 +639,7 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai BKE_gpencil_get_range_selected(gpl, &f_init, &f_end); } - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* Always do active frame; Otherwise, only include selected frames */ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { /* compute multiframe falloff factor */ @@ -661,12 +660,13 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai } } else { - /* Apply to active frame's strokes */ - gso->mf_falloff = 1.0f; - changed |= gp_weightpaint_brush_do_frame(C, gso, gpl, gpf_eval, diff_mat); + if (gpl->actframe != NULL) { + /* Apply to active frame's strokes */ + gso->mf_falloff = 1.0f; + changed |= gp_weightpaint_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat); + } } } - CTX_DATA_END; return changed; } diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index e7bc61d5a4b..937ca83899f 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -35,6 +35,7 @@ struct bGPDspoint; struct bGPDstroke; struct bGPdata; struct tGPspoint; +struct GP_SpaceConversion; struct ARegion; struct Depsgraph; @@ -42,6 +43,7 @@ struct Main; struct RegionView3D; struct ReportList; struct Scene; +struct ToolSettings; struct ScrArea; struct View3D; struct ViewLayer; @@ -201,12 +203,6 @@ bool ED_gpencil_add_lattice_modifier(const struct bContext *C, /* ------------ Transformation Utilities ------------ */ -/* 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 Depsgraph *depsgraph, struct Object *obact, @@ -241,11 +237,11 @@ void ED_gp_project_point_to_plane(const struct Scene *scene, const float origin[3], const int axis, struct bGPDspoint *pt); -void ED_gp_get_drawing_reference(const struct Scene *scene, - const struct Object *ob, - struct bGPDlayer *gpl, - char align_flag, - float vec[3]); +void ED_gpencil_drawing_reference_get(const struct Scene *scene, + const struct Object *ob, + struct bGPDlayer *gpl, + char align_flag, + float vec[3]); void ED_gpencil_project_stroke_to_view(struct bContext *C, struct bGPDlayer *gpl, struct bGPDstroke *gps); @@ -267,7 +263,6 @@ 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); /* extend selection to stroke intersections @@ -293,7 +288,26 @@ struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array, int *buffer_size, int *buffer_used, const bool clear); +void ED_gpencil_sbuffer_update_eval(struct Depsgraph *depsgraph, struct Object *ob); + /* Tag all scene grease pencil object to update. */ void ED_gpencil_tag_scene_gpencil(struct Scene *scene); +/* Vertex color set. */ +void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts, + struct Brush *brush, + struct bGPDstroke *gps); +void ED_gpencil_point_vertex_color_set(struct ToolSettings *ts, + struct Brush *brush, + struct bGPDspoint *pt); +void ED_gpencil_sbuffer_vertex_color_set(struct ToolSettings *ts, + struct Brush *brush, + struct bGPdata *gpd); + +bool ED_gpencil_stroke_check_collision(struct GP_SpaceConversion *gsc, + struct bGPDstroke *gps, + float mouse[2], + const int radius, + const float diff_mat[4][4]); + #endif /* __ED_GPENCIL_H__ */ diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c index 3acae220a54..f62efcfc766 100644 --- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c +++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c @@ -126,15 +126,15 @@ static void eyedropper_add_material( if (gp_style != NULL) { /* Check stroke color. */ bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) && - (gp_style->flag & GP_STYLE_STROKE_SHOW); + (gp_style->flag & GP_MATERIAL_STROKE_SHOW); /* Check fill color. */ bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) && - (gp_style->flag & GP_STYLE_FILL_SHOW); + (gp_style->flag & GP_MATERIAL_FILL_SHOW); - if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) { + if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) { found = true; } - else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0)) { + else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0)) { found = true; } else if ((both) && (found_stroke) && (found_fill)) { @@ -168,22 +168,22 @@ static void eyedropper_add_material( /* Only create Stroke (default option). */ if (only_stroke) { /* Stroke color. */ - gp_style_new->flag |= GP_STYLE_STROKE_SHOW; - gp_style_new->flag &= ~GP_STYLE_FILL_SHOW; + gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW; + gp_style_new->flag &= ~GP_MATERIAL_FILL_SHOW; copy_v3_v3(gp_style_new->stroke_rgba, col_conv); zero_v4(gp_style_new->fill_rgba); } /* Fill Only. */ else if (only_fill) { /* Fill color. */ - gp_style_new->flag &= ~GP_STYLE_STROKE_SHOW; - gp_style_new->flag |= GP_STYLE_FILL_SHOW; + gp_style_new->flag &= ~GP_MATERIAL_STROKE_SHOW; + gp_style_new->flag |= GP_MATERIAL_FILL_SHOW; zero_v4(gp_style_new->stroke_rgba); copy_v3_v3(gp_style_new->fill_rgba, col_conv); } /* Stroke and Fill. */ else if (both) { - gp_style_new->flag |= GP_STYLE_STROKE_SHOW | GP_STYLE_FILL_SHOW; + gp_style_new->flag |= GP_MATERIAL_STROKE_SHOW | GP_MATERIAL_FILL_SHOW; copy_v3_v3(gp_style_new->stroke_rgba, col_conv); copy_v3_v3(gp_style_new->fill_rgba, col_conv); } @@ -234,16 +234,7 @@ static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, Eyed float col_conv[4]; - /* Convert from linear rgb space to display space because grease pencil colors are in display - * space, and this conversion is needed to undo the conversion to linear performed by - * eyedropper_color_sample_fl. */ - if (eye->display) { - copy_v3_v3(col_conv, eye->color); - IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display); - } - else { - copy_v3_v3(col_conv, eye->color); - } + copy_v3_v3(col_conv, eye->color); /* Add material or Palette color*/ if (eye->mode == 0) { diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 2be0fed443b..6f7f53a50a3 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1528,7 +1528,7 @@ static int object_delete_exec(bContext *C, wmOperator *op) * Will also remove parent from grease pencil from other scenes, * even when use_global is false... */ for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->parent != NULL) { if (gpl->parent == ob) { gpl->parent = NULL; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 4f56664ec99..ddd9137add4 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -696,7 +696,7 @@ static int apply_objects_internal(bContext *C, /* Unsupported configuration */ bool has_unparented_layers = false; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* Parented layers aren't supported as we can't easily re-evaluate * the scene to sample parent movement */ if (gpl->parent == NULL) { @@ -1394,13 +1394,13 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* recalculate all strokes * (all layers are considered without evaluating lock attributes) */ - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, 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) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { float mpt[3]; mul_v3_m4v3(mpt, inverse_diff_mat, &pt->x); diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index a840d199823..540a4c05247 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -555,7 +555,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact); if (gpd) { - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); if (gpl) { CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl); @@ -567,7 +567,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene); if (gpd) { - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); if (gpl) { CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl); @@ -579,7 +579,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact); if (gpd) { - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); if (gpl) { CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe); @@ -609,7 +609,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult bGPDlayer *gpl; for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpencil_layer_is_editable(gpl)) { + if (BKE_gpencil_layer_is_editable(gpl)) { CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl); } } @@ -625,7 +625,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult bGPDlayer *gpl; for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpencil_layer_is_editable(gpl) && (gpl->actframe)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe)) { bGPDframe *gpf; bGPDstroke *gps; bGPDframe *init_gpf = gpl->actframe; diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 68d26cc5c74..beeac6f3fda 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -358,7 +358,7 @@ static int palette_extract_img_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void PALETTE_OT_extract_from_image(wmOperatorType *ot) +static void PALETTE_OT_extract_from_image(wmOperatorType *ot) { /* identifiers */ ot->name = "Extract Palette from Image"; @@ -454,7 +454,7 @@ static int palette_sort_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void PALETTE_OT_sort(wmOperatorType *ot) +static void PALETTE_OT_sort(wmOperatorType *ot) { static const EnumPropertyItem sort_type[] = { {-1, "HSV", 0, "Hue, Saturation, Value", ""}, @@ -499,7 +499,7 @@ static int palette_color_move_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void PALETTE_OT_color_move(wmOperatorType *ot) +static void PALETTE_OT_color_move(wmOperatorType *ot) { static const EnumPropertyItem slot_move[] = { {-1, "UP", 0, "Up", ""}, @@ -582,7 +582,7 @@ static int palette_join_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void PALETTE_OT_join(wmOperatorType *ot) +static void PALETTE_OT_join(wmOperatorType *ot) { /* identifiers */ ot->name = "Join Palette Swatches"; diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 6e44992ea6e..18cb90fd774 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -803,7 +803,7 @@ static void insert_gpencil_keys(bAnimContext *ac, short mode) /* insert gp frames */ for (ale = anim_data.first; ale; ale = ale->next) { bGPDlayer *gpl = (bGPDlayer *)ale->data; - BKE_gpencil_layer_getframe(gpl, CFRA, add_frame_mode); + BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode); } ANIM_animdata_update(ac, &anim_data); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 095b30aa57b..0b396bcd2b1 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -1759,8 +1759,8 @@ static int mouse_action_keys(bAnimContext *ac, gpl->flag |= GP_LAYER_SELECT; /* Update other layer status. */ - if (BKE_gpencil_layer_getactive(gpd) != gpl) { - BKE_gpencil_layer_setactive(gpd, gpl); + if (BKE_gpencil_layer_active_get(gpd) != gpl) { + BKE_gpencil_layer_active_set(gpd, gpl); BKE_gpencil_layer_autolock_set(gpd, false); WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 67e5b5045d4..5cf6c732a71 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -816,7 +816,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) bGPDlayer *gpl = te->directdata; /* always make layer active */ - BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_active_set(gpd, gpl); // XXX: name needs translation stuff BLI_uniquename( diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 51e837db4c2..7e3cc15729b 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -556,7 +556,7 @@ static eOLDrawState tree_element_active_gplayer(bContext *C, */ if (set != OL_SETSEL_NONE) { if (gpl) { - BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_active_set(gpd, gpl); DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd); } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 648c77fbcbf..45c9186b814 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -410,7 +410,7 @@ static bool view3d_ruler_item_mousemove(RulerInfo *ruler_info, /* Helper: Find the layer created as ruler. */ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd) { - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { if (gpl->flag & GP_LAYER_IS_RULER) { return gpl; } @@ -446,7 +446,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER; } - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); + gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW); BKE_gpencil_free_strokes(gpf); for (ruler_item = gzgroup->gizmos.first; ruler_item; @@ -479,6 +479,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup) gps->flag = GP_STROKE_3DSPACE; gps->thickness = 3; gps->gradient_f = 1.0f; + gps->fill_opacity_fac = 1.0f; gps->gradient_s[0] = 1.0f; gps->gradient_s[1] = 1.0f; gps->uv_scale = 1.0f; @@ -500,7 +501,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup) gpl = view3d_ruler_layer_get(scene->gpd); if (gpl) { bGPDframe *gpf; - gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV); + gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV); if (gpf) { bGPDstroke *gps; for (gps = gpf->strokes.first; gps; gps = gps->next) { diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 8feafc85c2f..1f24b55d083 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -862,7 +862,7 @@ static void posttrans_gpd_clean(bGPdata *gpd) for (gpf = gpl->frames.first; gpf; gpf = gpfn) { gpfn = gpf->next; if (gpfn && gpf->framenum == gpfn->framenum) { - BKE_gpencil_layer_delframe(gpl, gpf); + BKE_gpencil_layer_frame_delete(gpl, gpf); } } } diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index 2547e486a6a..cf3a6865c7e 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -111,7 +111,7 @@ void createTransGPencil(bContext *C, TransInfo *t) */ 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)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { bGPDframe *gpf; bGPDstroke *gps; bGPDframe *init_gpf = gpl->actframe; @@ -183,7 +183,7 @@ void createTransGPencil(bContext *C, TransInfo *t) /* Second Pass: Build transdata array */ 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)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene; bGPDframe *gpf = gpl->actframe; bGPDstroke *gps; @@ -203,7 +203,7 @@ void createTransGPencil(bContext *C, TransInfo *t) } /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat); /* undo matrix */ invert_m4_m4(inverse_diff_mat, diff_mat); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 5595c3a0e38..8142f9f99c2 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1215,12 +1215,15 @@ static void recalcData_sequencer(TransInfo *t) static void recalcData_gpencil_strokes(TransInfo *t) { TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + bGPDstroke *gps_prev = NULL; TransData *td = tc->data; for (int i = 0; i < tc->data_len; i++, td++) { bGPDstroke *gps = td->extra; - if (gps != NULL) { - gps->flag |= GP_STROKE_RECALC_GEOMETRY; + if ((gps != NULL) && (gps != gps_prev)) { + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); + gps_prev = gps; } } } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 3d3aa58a0de..ab29e3895f6 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -792,13 +792,13 @@ int ED_transform_calc_gizmo_stats(const bContext *C, if (is_gp_edit) { float diff_mat[4][4]; const bool use_mat_local = true; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* only editable and visible layers are considered */ - if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { + if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) { /* calculate difference matrix */ - ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat); + BKE_gpencil_parent_matrix_get(depsgraph, ob, 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/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 44c59f60377..400fb256128 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -187,44 +187,3 @@ float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr) return weight; } - -/* set material when apply modifiers (used in tint and color modifier) */ -void gpencil_apply_modifier_material( - Main *bmain, Object *ob, Material *mat, GHash *gh_color, bGPDstroke *gps, bool crt_material) -{ - MaterialGPencilStyle *gp_style = mat->gp_style; - - /* look for color */ - if (crt_material) { - 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); - newmat->preview = NULL; - - BKE_object_material_assign(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_USERPREF); - - 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); - DEG_id_tag_update(&newmat->id, ID_RECALC_COPY_ON_WRITE); - } - /* Reassign color index. */ - gps->mat_nr = BKE_gpencil_object_material_get_index(ob, newmat); - } - else { - /* reuse existing color (but update only first time) */ - if (BLI_ghash_lookup(gh_color, mat->id.name) == NULL) { - copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba); - copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba); - BLI_ghash_insert(gh_color, mat->id.name, mat); - } - /* update previews (icon and thumbnail) */ - if (mat->preview != NULL) { - mat->preview->flag[ICON_SIZE_ICON] |= PRV_CHANGED; - mat->preview->flag[ICON_SIZE_PREVIEW] |= PRV_CHANGED; - } - DEG_id_tag_update(&mat->id, ID_RECALC_COPY_ON_WRITE); - } -} diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index 2b1f8dbc71a..fc4522bc028 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -47,11 +47,4 @@ bool is_stroke_affected_by_modifier(struct Object *ob, float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr); -void gpencil_apply_modifier_material(struct Main *bmain, - struct Object *ob, - struct Material *mat, - struct GHash *gh_color, - struct bGPDstroke *gps, - bool crt_material); - #endif /* __MOD_GPENCIL_UTIL_H__ */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index 27c8175af3f..9252629865c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -116,6 +117,8 @@ static void deformStroke(GpencilModifierData *md, } gpencil_deform_verts(mmd, ob, gps); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) @@ -131,8 +134,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData return; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply armature effects on this frame * NOTE: this assumes that we don't want armature animation on non-keyframed frames */ @@ -140,7 +143,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* compute armature effects on this frame */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md_eval, depsgraph, object_eval, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index e258fbdccd1..2014c965e6c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -291,8 +291,8 @@ static void bakeModifier(Main *UNUSED(bmain), bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { generate_geometry(md, depsgraph, ob, gpl, gpf); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index e3e7168330d..2437beb1992 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -174,10 +174,8 @@ static void reduce_stroke_points(bGPDstroke *gps, gps->dvert = new_dvert; gps->totpoints = num_points; - /* mark stroke as needing to have its geometry caches rebuilt */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; - MEM_SAFE_FREE(gps->triangles); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* --------------------------------------------- */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index c383225368e..9e7edd536cb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" -#include "BLI_ghash.h" #include "BLI_math_color.h" #include "BLI_math_vector.h" @@ -52,7 +51,6 @@ static void initData(GpencilModifierData *md) ARRAY_SET_ITEMS(gpmd->hsv, 0.5f, 1.0f, 1.0f); gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; - gpmd->flag |= GP_COLOR_CREATE_COLORS; gpmd->modify_color = GP_MODIFY_COLOR_BOTH; } @@ -94,76 +92,54 @@ static void deformStroke(GpencilModifierData *md, factor[1] -= 1.0f; factor[2] -= 1.0f; - if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { - 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); - } - - if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - 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); - } + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - /* Apply to mix color. */ + /* Apply to Vertex Color. */ /* Fill */ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - rgb_to_hsv_v(gps->mix_color_fill, hsv); + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && + (gp_style->fill_rgba[3] > 0.0f)) { + copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); + gps->vert_color_fill[3] = 1.0f; + } + + rgb_to_hsv_v(gps->vert_color_fill, hsv); add_v3_v3(hsv, factor); CLAMP3(hsv, 0.0f, 1.0f); - hsv_to_rgb_v(hsv, gps->mix_color_fill); + hsv_to_rgb_v(hsv, gps->vert_color_fill); } /* Stroke */ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { + for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; - rgb_to_hsv_v(pt->mix_color, hsv); + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) { + copy_v4_v4(pt->vert_color, gp_style->stroke_rgba); + pt->vert_color[3] = 1.0f; + } + + rgb_to_hsv_v(pt->vert_color, hsv); add_v3_v3(hsv, factor); CLAMP3(hsv, 0.0f, 1.0f); - hsv_to_rgb_v(hsv, pt->mix_color); + hsv_to_rgb_v(hsv, pt->vert_color); } } } 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 = BKE_gpencil_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); - + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); - - gpencil_apply_modifier_material( - bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_COLOR_CREATE_COLORS)); } } } - /* free hash buffers */ - if (gh_color) { - BLI_ghash_free(gh_color, NULL, NULL); - gh_color = NULL; - } } GpencilModifierTypeInfo modifierType_Gpencil_Color = { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index bc62d0d69bb..942b0490ce0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -263,6 +264,8 @@ static void deformStroke(GpencilModifierData *md, } gp_hook_co_apply(&tData, weight, pt); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* FIXME: Ideally we be doing this on a copy of the main depsgraph @@ -279,8 +282,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData return; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply hook effects on this frame * NOTE: this assumes that we don't want hook animation on non-keyframed frames */ @@ -288,7 +291,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* compute hook effects on this frame */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 9dbf7b35bc5..ef3b1343827 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -108,6 +109,8 @@ static void deformStroke(GpencilModifierData *md, } calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* FIXME: Ideally we be doing this on a copy of the main depsgraph @@ -125,8 +128,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData return; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply lattice effects on this frame * NOTE: this assumes that we don't want lattice animation on non-keyframed frames */ @@ -137,7 +140,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData BKE_gpencil_lattice_init(ob); /* compute lattice effects on this frame */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index ef06e14b3d7..7a2ec889082 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -145,7 +145,7 @@ static void generateStrokes(GpencilModifierData *md, mmd->flag & GP_MIRROR_INVERT_PASS, mmd->flag & GP_MIRROR_INVERT_LAYERPASS, mmd->flag & GP_MIRROR_INVERT_MATERIAL)) { - gps_new = BKE_gpencil_stroke_duplicate(gps); + gps_new = BKE_gpencil_stroke_duplicate(gps, true); update_position(ob, mmd, gps_new, xi); BLI_addtail(&gpf->strokes, gps_new); } @@ -160,8 +160,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData bGPdata *gpd = ob->data; int oldframe = (int)DEG_get_ctime(depsgraph); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply mirror effects on this frame */ CFRA = gpf->framenum; BKE_scene_graph_update_for_newframe(depsgraph, bmain); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index bc545ce6ce8..3c46281a3ea 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -88,7 +88,7 @@ static void splitStroke(bGPDframe *gpf, bGPDstroke *gps, float split_angle) for (i = 1; i < new_gps->totpoints - 1; i++) { angle = angle_v3v3v3(&pt[i - 1].x, &pt[i].x, &pt[i + 1].x); if (angle < split_angle) { - if (BKE_gpencil_split_stroke(gpf, new_gps, i, &new_gps)) { + if (BKE_gpencil_stroke_split(gpf, new_gps, i, &new_gps)) { pt = new_gps->points; i = 0; continue; /* then i == 1 again */ @@ -177,8 +177,8 @@ static void duplicateStroke(bGPDstroke *gps, /* This ensures the original stroke is the last one to be processed. */ for (i = count - 1; i >= 0; i--) { if (i != 0) { - new_gps = BKE_gpencil_stroke_duplicate(gps); - new_gps->flag |= GP_STROKE_RECALC_GEOMETRY; + new_gps = BKE_gpencil_stroke_duplicate(gps, true); + BLI_addtail(results, new_gps); } else { @@ -215,6 +215,9 @@ static void duplicateStroke(bGPDstroke *gps, } } } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(new_gps); + MEM_freeN(t1_array); MEM_freeN(t2_array); } @@ -227,8 +230,8 @@ static void bakeModifier(Main *UNUSED(bmain), bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { ListBase duplicates = {0}; MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md; bGPDstroke *gps; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index f34477aaab2..a6e50362b34 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" @@ -243,9 +244,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 70d463fff76..97f78088530 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -108,6 +109,8 @@ static void deformStroke(GpencilModifierData *md, mul_m4_v3(mat, &pt->x); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } static void bakeModifier(struct Main *UNUSED(bmain), @@ -117,9 +120,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index b0fab5e8d69..e1aeec94574 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" -#include "BLI_ghash.h" #include "BLI_math_vector.h" #include "DNA_meshdata_types.h" @@ -54,7 +53,6 @@ static void initData(GpencilModifierData *md) gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; gpmd->vgname[0] = '\0'; - gpmd->flag |= GP_OPACITY_CREATE_COLORS; gpmd->modify_color = GP_MODIFY_COLOR_BOTH; } @@ -89,40 +87,12 @@ static void deformStroke(GpencilModifierData *md, return; } - if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) { - if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { - gps->runtime.tmp_stroke_rgba[3] *= mmd->factor; - /* if factor is > 1, then force opacity */ - if (mmd->factor > 1.0f) { - gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f; - } - CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f); - } - - if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - gps->runtime.tmp_fill_rgba[3] *= mmd->factor; - /* if factor is > 1, then force opacity */ - if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) { - gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f; - } - CLAMP(gps->runtime.tmp_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]; - pt->strength += mmd->factor - 1.0f; - CLAMP(pt->strength, 0.0f, 1.0f); - } - } - } - /* Apply opacity by strength */ - else { - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; + /* Stroke using strength. */ + if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { /* verify vertex group */ float weight = get_modifier_point_weight( dvert, (mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0, def_nr); @@ -143,45 +113,24 @@ static void deformStroke(GpencilModifierData *md, CLAMP(pt->strength, 0.0f, 1.0f); } } + + /* Fill using opacity factor. */ + if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { + gps->fill_opacity_fac = mmd->factor; + } } static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) { - OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md; bGPdata *gpd = ob->data; - GHash *gh_color = BLI_ghash_str_new("GP_Opacity 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 = BKE_gpencil_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); - + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); - - if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) { - gpencil_apply_modifier_material( - bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS)); - } } } } - /* free hash buffers */ - if (gh_color) { - BLI_ghash_free(gh_color, NULL, NULL); - gh_color = NULL; - } } GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index 9594fc8581e..3d07ba85430 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_scene_types.h" @@ -84,21 +85,21 @@ static void deformStroke(GpencilModifierData *md, switch (mmd->mode) { case GP_SIMPLIFY_FIXED: { for (int i = 0; i < mmd->step; i++) { - BKE_gpencil_simplify_fixed(gps); + BKE_gpencil_stroke_simplify_fixed(gps); } break; } case GP_SIMPLIFY_ADAPTIVE: { /* simplify stroke using Ramer-Douglas-Peucker algorithm */ - BKE_gpencil_simplify_stroke(gps, mmd->factor); + BKE_gpencil_stroke_simplify(gps, mmd->factor); break; } case GP_SIMPLIFY_SAMPLE: { - BKE_gpencil_sample_stroke(gps, mmd->length, false); + BKE_gpencil_stroke_sample(gps, mmd->length, false); break; } case GP_SIMPLIFY_MERGE: { - BKE_gpencil_merge_distance_stroke(gpf, gps, mmd->distance, true); + BKE_gpencil_stroke_merge_distance(gpf, gps, mmd->distance, true); break; } default: @@ -113,9 +114,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index 68060711681..59223c3ae68 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -98,19 +99,19 @@ static void deformStroke(GpencilModifierData *md, const float val = mmd->factor * weight; /* perform smoothing */ if (mmd->flag & GP_SMOOTH_MOD_LOCATION) { - BKE_gpencil_smooth_stroke(gps, i, val); + BKE_gpencil_stroke_smooth(gps, i, val); } if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) { - BKE_gpencil_smooth_stroke_strength(gps, i, val); + BKE_gpencil_stroke_smooth_strength(gps, i, val); } if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0.0f)) { /* thickness need to repeat process several times */ for (int r2 = 0; r2 < r * 10; r2++) { - BKE_gpencil_smooth_stroke_thickness(gps, i, val); + BKE_gpencil_stroke_smooth_thickness(gps, i, val); } } if (mmd->flag & GP_SMOOTH_MOD_UV) { - BKE_gpencil_smooth_stroke_uv(gps, i, val); + BKE_gpencil_stroke_smooth_uv(gps, i, val); } } } @@ -124,9 +125,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index 89d6565d0dd..71b2bd2e040 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -84,7 +85,7 @@ static void deformStroke(GpencilModifierData *md, return; } - BKE_gpencil_subdivide(gps, mmd->level, mmd->flag); + BKE_gpencil_stroke_subdivide(gps, mmd->level, mmd->flag); } static void bakeModifier(struct Main *UNUSED(bmain), @@ -94,9 +95,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index 036464e718d..0f9b2ea52d2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -23,6 +23,7 @@ #include <stdio.h> +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -179,9 +180,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { 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) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index cc3d17ded3e..775793e423f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" -#include "BLI_ghash.h" #include "BLI_math_vector.h" #include "DNA_scene_types.h" @@ -52,7 +51,6 @@ static void initData(GpencilModifierData *md) gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f); - gpmd->flag |= GP_TINT_CREATE_COLORS; gpmd->modify_color = GP_MODIFY_COLOR_BOTH; } @@ -86,24 +84,7 @@ static void deformStroke(GpencilModifierData *md, return; } - if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { - interp_v3_v3v3( - gps->runtime.tmp_stroke_rgba, gps->runtime.tmp_stroke_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; - } - CLAMP4(gps->runtime.tmp_stroke_rgba, 0.0f, 1.0f); - } - - if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - 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_fill_rgba[3] > 1e-5) { - gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f; - } - CLAMP4(gps->runtime.tmp_fill_rgba, 0.0f, 1.0f); - } + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); /* if factor > 1.0, affect the strength of the stroke */ if (mmd->factor > 1.0f) { @@ -114,58 +95,47 @@ static void deformStroke(GpencilModifierData *md, } } - /* Apply to mix color. */ + /* Apply to Vertex Color. */ float mixfac = mmd->factor; CLAMP(mixfac, 0.0, 1.0f); /* Fill */ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - interp_v3_v3v3(gps->mix_color_fill, gps->mix_color_fill, mmd->rgb, mixfac); + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && + (gp_style->fill_rgba[3] > 0.0f)) { + copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); + gps->vert_color_fill[3] = 1.0f; + } + + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, mmd->rgb, mixfac); } /* Stroke */ if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; - interp_v3_v3v3(pt->mix_color, pt->mix_color, mmd->rgb, mixfac); + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) { + copy_v4_v4(pt->vert_color, gp_style->stroke_rgba); + pt->vert_color[3] = 1.0f; + } + + interp_v3_v3v3(pt->vert_color, pt->vert_color, mmd->rgb, mixfac); } } } 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 = BKE_gpencil_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); - + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); - - gpencil_apply_modifier_material( - bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_TINT_CREATE_COLORS)); } } } - /* free hash buffers */ - if (gh_color) { - BLI_ghash_free(gh_color, NULL, NULL); - gh_color = NULL; - } } GpencilModifierTypeInfo modifierType_Gpencil_Tint = { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c index d33bc12144d..502935fddd0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c @@ -26,6 +26,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_listbase.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" @@ -230,8 +231,8 @@ static void deformStroke(GpencilModifierData *md, /* Apply to fill. */ if (mmd->mode != GPPAINT_MODE_STROKE) { BKE_colorband_evaluate(mmd->colorband, 1.0f, coba_res); - interp_v3_v3v3(gps->mix_color_fill, gps->mix_color_fill, coba_res, mmd->factor); - gps->mix_color_fill[3] = mmd->factor; + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, coba_res, mmd->factor); + gps->vert_color_fill[3] = mmd->factor; /* If no stroke, cancel loop. */ if (mmd->mode != GPPAINT_MODE_BOTH) { break; @@ -252,11 +253,11 @@ static void deformStroke(GpencilModifierData *md, float mix_factor = dist_sqr / radius_sqr; BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res); - interp_v3_v3v3(pt->mix_color, pt->mix_color, coba_res, mmd->factor * weight); - pt->mix_color[3] = mmd->factor; + interp_v3_v3v3(pt->vert_color, pt->vert_color, coba_res, mmd->factor * weight); + pt->vert_color[3] = mmd->factor; /* Apply Decay. */ if (mmd->flag & GP_VERTEXCOL_DECAY_COLOR) { - pt->mix_color[3] *= (1.0f - mix_factor); + pt->vert_color[3] *= (1.0f - mix_factor); } } } @@ -276,8 +277,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData return; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply effects on this frame * NOTE: this assumes that we don't want animation on non-keyframed frames */ @@ -285,7 +286,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* compute effects on this frame */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 7d0f8b0bcbf..213cbe30794 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -173,6 +173,8 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb, #define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \ GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil) +void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4]); + void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data); void GPU_framebuffer_read_color( GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data); diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h index e336aa53d24..2e06c1c3594 100644 --- a/source/blender/gpu/GPU_shader_interface.h +++ b/source/blender/gpu/GPU_shader_interface.h @@ -51,6 +51,7 @@ typedef enum { GPU_UNIFORM_COLOR, /* vec4 color */ GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */ GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */ + GPU_UNIFORM_RESOURCE_ID, /* int resourceId */ GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */ diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index bb6af227369..456d5941bfb 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -95,6 +95,7 @@ typedef enum eGPUTextureFormat { #if 0 GPU_RGB10_A2, GPU_RGB10_A2UI, + GPU_SRGB8_A8, #endif GPU_R11F_G11F_B10F, GPU_DEPTH32F_STENCIL8, @@ -124,7 +125,6 @@ typedef enum eGPUTextureFormat { /* Special formats texture only */ #if 0 - GPU_SRGB8_A8, GPU_SRGB8, GPU_RGB9_E5, GPU_COMPRESSED_RG_RGTC2, diff --git a/source/blender/gpu/GPU_vertex_format.h b/source/blender/gpu/GPU_vertex_format.h index b50665d0256..7e10bdbdc1f 100644 --- a/source/blender/gpu/GPU_vertex_format.h +++ b/source/blender/gpu/GPU_vertex_format.h @@ -108,6 +108,8 @@ uint GPU_vertformat_attr_add( GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode); void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias); +void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count); + void GPU_vertformat_deinterleave(GPUVertFormat *format); int GPU_vertformat_attr_id_get(const GPUVertFormat *, const char *name); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index a531c22365c..b04cce095b7 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -612,6 +612,21 @@ void GPU_framebuffer_clear(GPUFrameBuffer *fb, glClear(mask); } +/* Clear all textures bound to this framebuffer with a different color. */ +void GPU_framebuffer_multi_clear(GPUFrameBuffer *fb, const float (*clear_cols)[4]) +{ + CHECK_FRAMEBUFFER_IS_BOUND(fb); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0; + for (int i = 0; type < GPU_FB_MAX_ATTACHEMENT; i++, type++) { + if (fb->attachments[type].tex != NULL) { + glClearBufferfv(GL_COLOR, i, clear_cols[i]); + } + } +} + void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data) { CHECK_FRAMEBUFFER_IS_BOUND(fb); diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index 983c5dfc27a..f895993a27d 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -67,6 +67,7 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) [GPU_UNIFORM_COLOR] = "color", [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance", [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk", + [GPU_UNIFORM_RESOURCE_ID] = "resourceId", [GPU_UNIFORM_CUSTOM] = NULL, [GPU_NUM_UNIFORMS] = NULL, diff --git a/source/blender/gpu/intern/gpu_vertex_format.c b/source/blender/gpu/intern/gpu_vertex_format.c index 65573b71c76..16d8f8f875b 100644 --- a/source/blender/gpu/intern/gpu_vertex_format.c +++ b/source/blender/gpu/intern/gpu_vertex_format.c @@ -206,6 +206,47 @@ void GPU_vertformat_alias_add(GPUVertFormat *format, const char *alias) attr->names[attr->name_len++] = copy_attr_name(format, alias); } +/** + * Makes vertex attrib from the next vertices to be accessible in the vertex shader. + * For an attrib named "attr" you can access the next nth vertex using "attrn". + * Use this function after specifying all the attribs in the format. + * + * NOTE: This does NOT work when using indexed rendering. + * NOTE: Only works for first attrib name. (this limitation can be changed if needed) + * + * WARNING: this function creates a lot of aliases/attribs, make sure to keep the attrib name + * short to avoid overflowing the namebuffer. + * */ +void GPU_vertformat_multiload_enable(GPUVertFormat *format, int load_count) +{ + /* Sanity check. Maximum can be upgraded if needed. */ + BLI_assert(load_count > 1 && load_count < 5); + /* We need a packed format because of format->stride. */ + if (!format->packed) { + VertexFormat_pack(format); + } + + BLI_assert((format->name_len + 1) * load_count < GPU_VERT_FORMAT_MAX_NAMES); + BLI_assert(format->attr_len * load_count <= GPU_VERT_ATTR_MAX_LEN); + BLI_assert(format->name_offset * load_count < GPU_VERT_ATTR_NAMES_BUF_LEN); + + const GPUVertAttr *attr = format->attrs; + int attr_len = format->attr_len; + for (int i = 0; i < attr_len; i++, attr++) { + const char *attr_name = GPU_vertformat_attr_name_get(format, attr, 0); + for (int j = 1; j < load_count; j++) { + char load_name[64]; + BLI_snprintf(load_name, sizeof(load_name), "%s%d", attr_name, j); + GPUVertAttr *dst_attr = &format->attrs[format->attr_len++]; + *dst_attr = *attr; + + dst_attr->names[0] = copy_attr_name(format, load_name); + dst_attr->name_len = 1; + dst_attr->offset += format->stride * j; + } + } +} + int GPU_vertformat_attr_id_get(const GPUVertFormat *format, const char *name) { for (int i = 0; i < format->attr_len; i++) { diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 8abae5de498..45e98c9f6e0 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -230,7 +230,6 @@ typedef struct TintGpencilModifierData { } TintGpencilModifierData; typedef enum eTintGpencil_Flag { - GP_TINT_CREATE_COLORS = (1 << 0), GP_TINT_INVERT_LAYER = (1 << 1), GP_TINT_INVERT_PASS = (1 << 2), GP_TINT_INVERT_LAYERPASS = (1 << 3), @@ -258,7 +257,6 @@ typedef struct ColorGpencilModifierData { } ColorGpencilModifierData; typedef enum eColorGpencil_Flag { - GP_COLOR_CREATE_COLORS = (1 << 0), GP_COLOR_INVERT_LAYER = (1 << 1), GP_COLOR_INVERT_PASS = (1 << 2), GP_COLOR_INVERT_LAYERPASS = (1 << 3), @@ -281,9 +279,7 @@ typedef struct OpacityGpencilModifierData { float factor; /** Modify stroke, fill or both. */ char modify_color; - /** Mode of opacity, colors or strength */ - char opacity_mode; - char _pad[2]; + char _pad[3]; /** Custom index for passes. */ int layer_pass; char _pad1[4]; @@ -293,7 +289,6 @@ typedef enum eOpacityGpencil_Flag { GP_OPACITY_INVERT_LAYER = (1 << 0), GP_OPACITY_INVERT_PASS = (1 << 1), GP_OPACITY_INVERT_VGROUP = (1 << 2), - GP_OPACITY_CREATE_COLORS = (1 << 3), GP_OPACITY_INVERT_LAYERPASS = (1 << 4), GP_OPACITY_INVERT_MATERIAL = (1 << 5), } eOpacityGpencil_Flag; diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 44f7c3733ef..409b758d570 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -36,6 +36,8 @@ struct MDeformVert; #define GP_DEFAULT_GRID_LINES 4 #define GP_MAX_INPUT_SAMPLES 10 +#define GP_MATERIAL_BUFFER_LEN 256 + /* ***************************************** */ /* GP Stroke Points */ @@ -78,9 +80,11 @@ typedef struct bGPDspoint { float uv_fac; /** Uv rotation for dot mode. */ float uv_rot; + /** Uv for fill mode */ + float uv_fill[2]; - /** Mix color RGBA (A=mix factor) */ - float mix_color[4]; + /** Vertex Color RGBA (A=mix factor). */ + float vert_color[4]; /** Runtime data */ char _pad2[4]; @@ -109,8 +113,6 @@ typedef enum eGPDspoint_Flag { typedef struct bGPDtriangle { /* indices for tessellated triangle used for GP Fill */ unsigned int verts[3]; - /* texture coordinates for verts */ - float uv[3][2]; } bGPDtriangle; /* ***************************************** */ @@ -170,18 +172,17 @@ typedef enum eGPDpalette_Flag { /* Runtime temp data for bGPDstroke */ typedef struct bGPDstroke_Runtime { - /** runtime final colors (result of original colors and modifiers) */ - float tmp_stroke_rgba[4]; - - /** runtime final fill colors (result of original colors and modifiers) */ - 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]; /** Runtime falloff factor (only for transform). */ float multi_frame_falloff; - char _pad[4]; + + /** Vertex offset in the vbo where this stroke starts. */ + int stroke_start; + /** Triangle offset in the ibo where this fill starts. */ + int fill_start; + int _pad[1]; /** Original stroke (used to dereference evaluated data) */ struct bGPDstroke *gps_orig; @@ -224,7 +225,14 @@ typedef struct bGPDstroke { float gradient_f; /** factor xy of shape for dots gradients */ float gradient_s[2]; - char _pad_3[4]; + + /** Factor of opacity for Fill color (used by opacity modifier). */ + float fill_opacity_fac; + + /** Min of the collision bound box used to speedup painting. */ + float collision_min[3]; + /** Max of the collision bound box used to speedup painting. */ + float collision_max[3]; /** UV rotation */ float uv_rotation; @@ -236,8 +244,8 @@ typedef struct bGPDstroke { struct MDeformVert *dvert; void *_pad3; - /** Vertex mix color for Fill (one for all stroke). */ - float mix_color_fill[4]; + /** Vertex Color for Fill (one for all stroke, A=mix factor). */ + float vert_color_fill[4]; bGPDstroke_Runtime runtime; } bGPDstroke; @@ -252,14 +260,13 @@ typedef enum eGPDstroke_Flag { GP_STROKE_2DIMAGE = (1 << 2), /* stroke is selected */ GP_STROKE_SELECT = (1 << 3), - /* Recalculate geometry data (triangulation, UVs, Bound Box,... - * (when true, force a new recalc) */ - GP_STROKE_RECALC_GEOMETRY = (1 << 4), /* 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), + /* Tag for update geometry */ + GP_STROKE_TAG = (1 << 14), /* only for use with stroke-buffer (while drawing eraser) */ GP_STROKE_ERASER = (1 << 15), } eGPDstroke_Flag; @@ -278,8 +285,13 @@ typedef enum eGPDstroke_Caps { /* Runtime temp data for bGPDframe */ typedef struct bGPDframe_Runtime { - /** Parent matrix for drawing. */ - float parent_obmat[4][4]; + /** Index of this frame in the listbase of frames. */ + int frameid; + /** Onion offset from active frame. 0 if not onion. INT_MAX to bypass frame. */ + int onion_id; + + /** Original frame (used to dereference evaluated data) */ + struct bGPDframe *gpf_orig; } bGPDframe_Runtime; /* Grease-Pencil Annotations - 'Frame' @@ -318,6 +330,8 @@ typedef struct bGPDlayer_Runtime { /** Id for dynamic icon used to show annotation color preview for layer. */ int icon_id; char _pad[4]; + /** Original layer (used to dereference evaluated data) */ + struct bGPDlayer *gpl_orig; } bGPDlayer_Runtime; /* Grease-Pencil Annotations - 'Layer' */ @@ -389,6 +403,9 @@ typedef struct bGPDlayer { float gcolor_next[3]; char _pad1[4]; + /** Mask Layer name. */ + char mask_layer[64]; + bGPDlayer_Runtime runtime; } bGPDlayer; @@ -402,6 +419,8 @@ typedef enum eGPDlayer_Flag { GP_LAYER_ACTIVE = (1 << 2), /* draw points of stroke for debugging purposes */ GP_LAYER_DRAWDEBUG = (1 << 3), + /* Flag used to display in Paint mode only layers with keyframe */ + GP_LAYER_SOLO_MODE = (1 << 4), /* for editing in Action Editor */ GP_LAYER_SELECT = (1 << 5), /* current frame for layer can't be changed */ @@ -410,14 +429,16 @@ typedef enum eGPDlayer_Flag { GP_LAYER_NO_XRAY = (1 << 7), /* "volumetric" strokes */ GP_LAYER_VOLUMETRIC = (1 << 10), + /* Use Scene lights */ + GP_LAYER_USE_LIGHTS = (1 << 11), /* Unlock color */ GP_LAYER_UNLOCK_COLOR = (1 << 12), /* Mask Layer */ - GP_LAYER_USE_MASK = (1 << 13), - /* Flag used to display in Paint mode only layers with keyframe */ - GP_LAYER_SOLO_MODE = (1 << 4), + GP_LAYER_USE_MASK = (1 << 13), /*TODO: DEPRECATED */ /* Ruler Layer */ GP_LAYER_IS_RULER = (1 << 14), + /* Invert masking behavior */ + GP_LAYER_MASK_INVERT = (1 << 15), } eGPDlayer_Flag; /* bGPDlayer->onion_flag */ @@ -445,18 +466,19 @@ typedef struct bGPdata_Runtime { struct ARegion *ar; /** Stroke buffer. */ void *sbuffer; + /** Temp batches cleared after drawing. */ + struct GPUBatch *sbuffer_stroke_batch; + struct GPUBatch *sbuffer_fill_batch; + /** Temp stroke used for drawing. */ + struct bGPDstroke *sbuffer_gps; /* GP Object drawing */ - /** Buffer stroke color. */ - float scolor[4]; - /** Buffer fill color. */ - float sfill[4]; - /** Settings for color. */ - short mode; - /** Buffer style for drawing strokes (used to select shader type). */ - short bstroke_style; - /** Buffer style for filling areas (used to select shader type). */ - short bfill_style; + char _pad[2]; + /** Material index of the stroke. */ + short matid; + /** Brush size of stroke. */ + float brush_size; + char _pad1[2]; /* Stroke Buffer data (only used during paint-session) * - buffer must be initialized before use, but freed after @@ -469,11 +491,18 @@ typedef struct bGPdata_Runtime { /** Number of total elements available in cache. */ int sbuffer_size; + /** Vertex Color applied to point (while drawing). */ + float vert_color[4]; + + /** Vertex Color applied to Fill (while drawing). */ + float vert_color_fill[4]; + /** Number of control-points for stroke. */ int tot_cp_points; - char _pad_[4]; /** Array of control-points for stroke. */ bGPDcontrolpoint *cp_points; + /** Runtime grease pencil drawing data */ + struct GpencilBatchCache *gpencil_cache; } bGPdata_Runtime; /* grid configuration */ @@ -495,7 +524,7 @@ typedef struct bGPdata { struct AnimData *adt; /* Grease-Pencil data */ - /** BGPDlayers. */ + /** bGPDlayer. */ ListBase layers; /** Settings for this data-block. */ int flag; @@ -595,8 +624,6 @@ typedef enum eGPdata_Flag { /* 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), /* Batch drawing cache need to be recalculated */ GP_DATA_CACHE_IS_DIRTY = (1 << 11), @@ -614,17 +641,9 @@ typedef enum eGPdata_Flag { /* Allow edit several frames at the same time */ GP_DATA_STROKE_MULTIEDIT = (1 << 16), - /* Force fill recalc if use deformation modifiers. - * this is required if the stroke is deformed and the triangulation data is - * not valid. - */ - GP_DATA_STROKE_FORCE_RECALC = (1 << 17), - /* Vertex Paint Mode - Toggle paint mode */ GP_DATA_STROKE_VERTEXMODE = (1 << 18), - /* Use adaptive UV scales */ - GP_DATA_UV_ADAPTIVE = (1 << 19), /* Autolock not active layers */ GP_DATA_AUTOLOCK_LAYERS = (1 << 20), /* Internal flag for python update */ @@ -679,7 +698,7 @@ typedef enum eGP_DrawMode { ((gpd) && \ (gpd->flag & (GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | \ GP_DATA_STROKE_WEIGHTMODE | GP_DATA_STROKE_VERTEXMODE))) -#define GPENCIL_EDIT_MODE(gpd) ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)) +#define GPENCIL_EDIT_MODE(gpd) ((gpd) && ((gpd)->flag & GP_DATA_STROKE_EDITMODE)) #define GPENCIL_ANY_EDIT_MODE(gpd) \ ((gpd) && (gpd->flag & \ (GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE | GP_DATA_STROKE_WEIGHTMODE))) diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index 1d1ccef8846..0db7feffa99 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -72,15 +72,14 @@ typedef struct MaterialGPencilStyle { /** Factor used to define shader behavior (several uses). */ float mix_factor; /** Angle used for gradients orientation. */ - float gradient_angle; + float gradient_angle DNA_DEPRECATED; /** Radius for radial gradients. */ - float gradient_radius; - /** Cheesboard size. */ - float pattern_gridsize; + float gradient_radius DNA_DEPRECATED; + char _pad2[4]; /** Uv coordinates scale. */ - float gradient_scale[2]; + float gradient_scale[2] DNA_DEPRECATED; /** Factor to shift filling in 2d space. */ - float gradient_shift[2]; + float gradient_shift[2] DNA_DEPRECATED; /** Angle used for texture orientation. */ float texture_angle; /** Texture scale (separated of uv scale). */ @@ -107,35 +106,35 @@ typedef struct MaterialGPencilStyle { /* MaterialGPencilStyle->flag */ typedef enum eMaterialGPencilStyle_Flag { /* Fill Texture is a pattern */ - GP_STYLE_FILL_PATTERN = (1 << 0), + GP_MATERIAL_FILL_PATTERN = (1 << 0), /* don't display color */ - GP_STYLE_COLOR_HIDE = (1 << 1), + GP_MATERIAL_HIDE = (1 << 1), /* protected from further editing */ - GP_STYLE_COLOR_LOCKED = (1 << 2), + GP_MATERIAL_LOCKED = (1 << 2), /* do onion skinning */ - GP_STYLE_COLOR_ONIONSKIN = (1 << 3), + GP_MATERIAL_ONIONSKIN = (1 << 3), /* clamp texture */ - GP_STYLE_COLOR_TEX_CLAMP = (1 << 4), + GP_MATERIAL_TEX_CLAMP = (1 << 4), /* mix fill texture */ - GP_STYLE_FILL_TEX_MIX = (1 << 5), + GP_MATERIAL_FILL_TEX_MIX = (1 << 5), /* Flip fill colors */ - GP_STYLE_COLOR_FLIP_FILL = (1 << 6), + GP_MATERIAL_FLIP_FILL = (1 << 6), /* Stroke Texture is a pattern */ - GP_STYLE_STROKE_PATTERN = (1 << 7), + GP_MATERIAL_STROKE_PATTERN = (1 << 7), /* Stroke show main switch */ - GP_STYLE_STROKE_SHOW = (1 << 8), - /* Fill show main switch */ - GP_STYLE_FILL_SHOW = (1 << 9), + GP_MATERIAL_STROKE_SHOW = (1 << 8), + /* Fill show main switch */ + GP_MATERIAL_FILL_SHOW = (1 << 9), /* mix stroke texture */ - GP_STYLE_STROKE_TEX_MIX = (1 << 11), + GP_MATERIAL_STROKE_TEX_MIX = (1 << 11), /* disable stencil clipping (overlap) */ - GP_STYLE_DISABLE_STENCIL = (1 << 12), + GP_MATERIAL_DISABLE_STENCIL = (1 << 12), } eMaterialGPencilStyle_Flag; typedef enum eMaterialGPencilStyle_Mode { - GP_STYLE_MODE_LINE = 0, /* line */ - GP_STYLE_MODE_DOTS = 1, /* dots */ - GP_STYLE_MODE_BOX = 2, /* rectangles */ + GP_MATERIAL_MODE_LINE = 0, + GP_MATERIAL_MODE_DOT = 1, + GP_MATERIAL_MODE_SQUARE = 2, } eMaterialGPencilStyle_Mode; typedef struct Material { @@ -332,28 +331,28 @@ enum { /* Grease Pencil Stroke styles */ enum { - GP_STYLE_STROKE_STYLE_SOLID = 0, - GP_STYLE_STROKE_STYLE_TEXTURE, + GP_MATERIAL_STROKE_STYLE_SOLID = 0, + GP_MATERIAL_STROKE_STYLE_TEXTURE, }; /* Grease Pencil Fill styles */ enum { - GP_STYLE_FILL_STYLE_SOLID = 0, - GP_STYLE_FILL_STYLE_GRADIENT, - GP_STYLE_FILL_STYLE_CHECKER, - GP_STYLE_FILL_STYLE_TEXTURE, + GP_MATERIAL_FILL_STYLE_SOLID = 0, + GP_MATERIAL_FILL_STYLE_GRADIENT, + GP_MATERIAL_FILL_STYLE_CHECKER, /* DEPRECATED (only for convert old files) */ + GP_MATERIAL_FILL_STYLE_TEXTURE, }; /* Grease Pencil Gradient Types */ enum { - GP_STYLE_GRADIENT_LINEAR = 0, - GP_STYLE_GRADIENT_RADIAL, + GP_MATERIAL_GRADIENT_LINEAR = 0, + GP_MATERIAL_GRADIENT_RADIAL, }; /* Grease Pencil Follow Drawing Modes */ enum { - GP_STYLE_FOLLOW_PATH = 0, - GP_STYLE_FOLLOW_OBJ, - GP_STYLE_FOLLOW_FIXED, + GP_MATERIAL_FOLLOW_PATH = 0, + GP_MATERIAL_FOLLOW_OBJ, + GP_MATERIAL_FOLLOW_FIXED, }; #endif diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index cbed2af7df2..06876048d98 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -167,6 +167,18 @@ typedef struct Object_Runtime { struct Mesh *mesh_deform_eval; /** + * Original grease pencil bGPdata pointer, before object->data was changed to point + * to gpd_eval. + * Is assigned by dependency graph's copy-on-write evaluation. + */ + struct bGPdata *gpd_orig; + /** + * bGPdata structure created during object evaluation. + * It has all modifiers applied. + */ + struct bGPdata *gpd_eval; + + /** * This is a mesh representation of corresponding object. * It created when Python calls `object.to_mesh()`. */ @@ -175,14 +187,6 @@ typedef struct Object_Runtime { /** Runtime evaluated curve-specific data, not stored in the file. */ struct CurveCache *curve_cache; - /** Runtime grease pencil drawing data */ - struct GpencilBatchCache *gpencil_cache; - /** Runtime grease pencil total layers used for evaluated data created by modifiers */ - int gpencil_tot_layers; - char _pad4[4]; - /** Runtime grease pencil evaluated data created by modifiers */ - struct bGPDframe *gpencil_evaluated_frames; - unsigned short local_collections_bits; short _pad2[3]; } Object_Runtime; @@ -552,6 +556,8 @@ enum { OB_DRAWTRANSP = 1 << 7, OB_DRAW_ALL_EDGES = 1 << 8, /* only for meshes currently */ OB_DRAW_NO_SHADOW_CAST = 1 << 9, + /* Enable lights for grease pencil. */ + OB_USE_GPENCIL_LIGHTS = 1 << 10, }; /* empty_drawtype: no flags */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 294486bdf75..486a2cf455e 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2278,14 +2278,12 @@ typedef enum eGPencil_SimplifyFlags { 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), /* Simplify Shader FX */ SIMPLIFY_GPENCIL_FX = (1 << 5), - /* Simplify layer blending */ - SIMPLIFY_GPENCIL_BLEND = (1 << 6), /* Simplify layer tint */ SIMPLIFY_GPENCIL_TINT = (1 << 7), + /* Simplify Antialiasing */ + SIMPLIFY_GPENCIL_AA = (1 << 8), } eGPencil_SimplifyFlags; /* ToolSettings.gpencil_*_align - Stroke Placement mode flags */ diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h index 6cda58a3279..b6a82854f83 100644 --- a/source/blender/makesdna/DNA_shader_fx_types.h +++ b/source/blender/makesdna/DNA_shader_fx_types.h @@ -34,7 +34,7 @@ typedef enum ShaderFxType { eShaderFxType_None = 0, eShaderFxType_Blur = 1, eShaderFxType_Flip = 2, - eShaderFxType_Light = 3, + eShaderFxType_Light_deprecated = 3, /* DEPRECATED (replaced by scene lights) */ eShaderFxType_Pixel = 4, eShaderFxType_Swirl = 5, eShaderFxType_Wave = 6, @@ -156,19 +156,6 @@ typedef enum eGlowShaderFx_Flag { FX_GLOW_USE_ALPHA = (1 << 0), } eGlowShaderFx_Flag; -typedef struct LightShaderFxData { - ShaderFxData shaderfx; - struct Object *object; - /** Flags. */ - int flag; - float energy; - float ambient; - /** Internal, not visible in rna. */ - float loc[4]; - char _pad[4]; - ShaderFxData_Runtime runtime; -} LightShaderFxData; - typedef struct PixelShaderFxData { ShaderFxData shaderfx; /** Last element used for shader only. */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index d741f22cc4f..f99699e0bcc 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -842,8 +842,7 @@ typedef struct UserDef { short pie_menu_threshold; short opensubdiv_compute_type; - /** #eMultiSample_Type, amount of samples for Grease Pencil. */ - short gpencil_multisamples; + short _pad6; char factor_display_type; @@ -1227,7 +1226,7 @@ typedef enum eNdof_Flag { #define NDOF_PIXELS_PER_SECOND 600.0f -/** UserDef.ogl_multisamples and gpencil_multisamples */ +/** UserDef.ogl_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 7ff2d76bbf4..3aaadd9fa96 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -400,13 +400,15 @@ typedef struct View3D { #define V3D_FLAG2_UNUSED_15 (1 << 15) /* cleared */ /** #View3D.gp_flag (short) */ -#define V3D_GP_SHOW_PAPER (1 << 0) /* Activate paper to cover all viewport */ -#define V3D_GP_SHOW_GRID (1 << 1) /* Activate paper grid */ +#define V3D_GP_FADE_OBJECTS (1 << 0) /* Fade all non GP objects */ +#define V3D_GP_SHOW_GRID (1 << 1) /* Activate paper grid */ #define V3D_GP_SHOW_EDIT_LINES (1 << 2) #define V3D_GP_SHOW_MULTIEDIT_LINES (1 << 3) #define V3D_GP_SHOW_ONION_SKIN (1 << 4) /* main switch at view level */ #define V3D_GP_FADE_NOACTIVE_LAYERS (1 << 5) /* fade layers not active */ #define V3D_GP_FADE_NOACTIVE_GPENCIL (1 << 6) /* Fade other GPencil objects */ +#define V3D_GP_SHOW_STROKE_DIRECTION (1 << 7) /* Show Strokes Directions */ +#define V3D_GP_SHOW_MATERIAL_NAME (1 << 8) /* Show Material names */ /** #View3DShading.light */ enum { diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 125f0546adf..ffe8845b6d5 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -141,6 +141,7 @@ static EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { # include "BKE_icons.h" # include "DEG_depsgraph.h" +# include "DEG_depsgraph_build.h" static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { @@ -148,11 +149,23 @@ static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Pointe WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); } +static void rna_GPencil_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) +{ + DEG_id_tag_update(ptr->owner_id, ID_RECALC_TRANSFORM); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_OBJECT | ND_PARENT, ptr->owner_id); + + DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); +} + static void rna_GPencil_uv_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { /* Force to recalc the UVs. */ bGPDstroke *gps = (bGPDstroke *)ptr->data; - gps->tot_triangles = 0; + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); DEG_id_tag_update(ptr->owner_id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); @@ -182,10 +195,10 @@ static void rna_GPencil_strokes_update(Main *UNUSED(bmain), Scene *UNUSED(scene) { bGPdata *gpd = (bGPdata *)ptr->owner_id; 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) { - BKE_gpencil_triangulate_stroke_fill(gpd, gps); + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + BKE_gpencil_stroke_fill_triangulate(gps); } } } @@ -393,7 +406,7 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, static int rna_GPencil_active_layer_index_get(PointerRNA *ptr) { bGPdata *gpd = (bGPdata *)ptr->owner_id; - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); return BLI_findindex(&gpd->layers, gpl); } @@ -403,7 +416,7 @@ static void rna_GPencil_active_layer_index_set(PointerRNA *ptr, int value) bGPdata *gpd = (bGPdata *)ptr->owner_id; bGPDlayer *gpl = BLI_findlink(&gpd->layers, value); - BKE_gpencil_layer_setactive(gpd, gpl); + BKE_gpencil_layer_active_set(gpd, gpl); /* Now do standard updates... */ DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); @@ -472,6 +485,25 @@ 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_layer_mask_set(PointerRNA *ptr, const bool value) +{ + bGPDlayer *gpl = ptr->data; + + const bool use_mask = gpl->flag & GP_LAYER_USE_MASK; + + /* Cycle through the 3 options */ + if (value != use_mask) { + if (use_mask && (gpl->flag & GP_LAYER_MASK_INVERT) == 0) { + /* Switch to invert mask instead of removing the masking. */ + gpl->flag |= GP_LAYER_MASK_INVERT; + } + else { + SET_FLAG_FROM_TEST(gpl->flag, value, GP_LAYER_USE_MASK); + gpl->flag &= ~GP_LAYER_MASK_INVERT; + } + } +} + static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd, const bGPDspoint *pt, bGPDlayer **r_gpl, @@ -568,7 +600,8 @@ static void rna_GPencil_stroke_point_add( stroke->totpoints += count; - stroke->flag |= GP_STROKE_RECALC_GEOMETRY; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(stroke); gpd->flag |= GP_DATA_PYTHON_UPDATED; DEG_id_tag_update(&gpd->id, @@ -629,7 +662,8 @@ static void rna_GPencil_stroke_point_pop(ID *id, MEM_freeN(pt_dvert); } - stroke->flag |= GP_STROKE_RECALC_GEOMETRY; + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(stroke); gpd->flag |= GP_DATA_PYTHON_UPDATED; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); @@ -676,7 +710,7 @@ static void rna_GPencil_stroke_close(ID *id, return; } - BKE_gpencil_close_stroke(stroke); + BKE_gpencil_stroke_close(stroke); DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); @@ -714,14 +748,14 @@ static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, { bGPDframe *frame; - if (BKE_gpencil_layer_find_frame(layer, frame_number)) { + if (BKE_gpencil_layer_frame_find(layer, frame_number)) { BKE_reportf(reports, RPT_ERROR, "Frame already exists on this frame number %d", frame_number); return NULL; } frame = BKE_gpencil_frame_addnew(layer, frame_number); if (active) { - layer->actframe = BKE_gpencil_layer_getframe(layer, frame_number, GP_GETFRAME_USE_PREV); + layer->actframe = BKE_gpencil_layer_frame_get(layer, frame_number, GP_GETFRAME_USE_PREV); } WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); @@ -736,7 +770,7 @@ static void rna_GPencil_frame_remove(bGPDlayer *layer, ReportList *reports, Poin return; } - BKE_gpencil_layer_delframe(layer, frame); + BKE_gpencil_layer_frame_delete(layer, frame); RNA_POINTER_INVALIDATE(frame_ptr); WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); @@ -746,7 +780,7 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src) { bGPDframe *frame = BKE_gpencil_frame_duplicate(src); - while (BKE_gpencil_layer_find_frame(layer, frame->framenum)) { + while (BKE_gpencil_layer_frame_find(layer, frame->framenum)) { frame->framenum++; } @@ -891,14 +925,14 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna) 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"); - /* Mix color. */ - prop = RNA_def_property(srna, "mix_color", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "mix_color"); + /* Vertex color. */ + prop = RNA_def_property(srna, "vertex_color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "vert_color"); RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( - prop, "Mix Color", "Color used to mix with point color to get final color"); + prop, "Vertex Color", "Color used to mix with point color to get final color"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); } @@ -972,27 +1006,6 @@ 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) @@ -1168,14 +1181,14 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna) RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_uv_update"); - /* Mix Vertex Color for Fill. */ - prop = RNA_def_property(srna, "mix_color_fill", PROP_FLOAT, PROP_COLOR_GAMMA); - RNA_def_property_float_sdna(prop, NULL, "mix_color_fill"); + /* Vertex Color for Fill. */ + prop = RNA_def_property(srna, "vertex_color_fill", PROP_FLOAT, PROP_COLOR); + RNA_def_property_float_sdna(prop, NULL, "vert_color_fill"); RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( - prop, "Mix Fill Color", "Color used to mix with fill color to get final color"); + prop, "Vertex Fill Color", "Color used to mix with fill color to get final color"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); } @@ -1365,7 +1378,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "tint_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "tintcolor"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1373,14 +1386,14 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Tint factor */ - prop = RNA_def_property(srna, "tint_factor", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "tint_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "tintcolor[3]"); RNA_def_property_range(prop, 0.0, 1.0f); RNA_def_property_ui_text(prop, "Tint Factor", "Factor of tinting color"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Vertex Paint opacity factor */ - prop = RNA_def_property(srna, "vertex_paint_opacity", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "vertex_paint_opacity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "vertex_paint_opacity"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_default(prop, 1.0f); @@ -1464,6 +1477,11 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "mask_layer_name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "mask_layer"); + RNA_def_property_ui_text(prop, "Mask", "Name of the masking layer"); + 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); @@ -1499,11 +1517,25 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) prop, "Disallow Locked Materials Editing", "Avoids editing locked materials in the layer"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); +# /* TODO: Deprecated */ prop = RNA_def_property(srna, "mask_layer", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_layer_mask_set"); + RNA_def_property_ui_text(prop, "Mask Layer", "Mask pixels from underlying layers drawing"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); +# + prop = RNA_def_property(srna, "invert_mask", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_MASK_INVERT); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Invert Mask", "Invert the masking behavior of the layer"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_lights", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_LIGHTS); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text( - prop, "Mask Layer", "Remove any pixel outside underlying layers drawing"); + prop, "Use Lights", "Enable the use of lights on stroke and fill materials"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* solo mode: Only display frames with keyframe */ @@ -1551,7 +1583,7 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Parent", "Parent Object"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_dependency_update"); /* parent type */ prop = RNA_def_property(srna, "parent_type", PROP_ENUM, PROP_NONE); @@ -1799,14 +1831,6 @@ static void rna_def_gpencil_data(BlenderRNA *brna) 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); - RNA_def_property_ui_text(prop, - "Show Direction", - "Show stroke drawing direction with a bigger green dot (start) " - "and smaller red dot (end) points"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - prop = RNA_def_property(srna, "stroke_thickness_space", PROP_ENUM, PROP_NONE); /* as an enum */ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, stroke_thickness_items); @@ -1832,20 +1856,6 @@ static void rna_def_gpencil_data(BlenderRNA *brna) "(keyframes must be selected to be included)"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - prop = RNA_def_property(srna, "use_force_fill_recalc", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_FORCE_RECALC); - RNA_def_property_ui_text( - prop, - "Force Fill Update", - "Force recalc of fill data after use deformation modifiers (reduce FPS)"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "use_adaptive_uv", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_UV_ADAPTIVE); - RNA_def_property_ui_text( - prop, "Adaptive UV", "Automatic UVs are calculated depending of the stroke size"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_strokes_update"); - prop = RNA_def_property(srna, "use_autolock_layers", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_AUTOLOCK_LAYERS); RNA_def_property_ui_text( @@ -1892,7 +1902,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "gcolor_prev"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1901,7 +1911,7 @@ static void rna_def_gpencil_data(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "gcolor_next"); RNA_def_property_array(prop, 3); RNA_def_property_range(prop, 0.0f, 1.0f); diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index cb51b8c8b42..fe5e8f5bdc1 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -144,16 +144,6 @@ static const EnumPropertyItem modifier_modify_color_items[] = { {0, NULL, 0, NULL, NULL}, }; -static const EnumPropertyItem modifier_opacity_mode_items[] = { - {GP_OPACITY_MODE_MATERIAL, - "MATERIAL", - 0, - "Material", - "Modify opacity using alpha channel of material"}, - {GP_OPACITY_MODE_STRENGTH, "STRENGTH", 0, "Strength", "Modify opacity using point strength"}, - {0, NULL, 0, NULL, NULL}, -}; - static const EnumPropertyItem modifier_gphook_falloff_items[] = { {eGPHook_Falloff_None, "NONE", 0, "No Falloff", ""}, {eGPHook_Falloff_Curve, "CURVE", 0, "Curve", ""}, @@ -969,7 +959,7 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Material", "Material name"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "rgb"); RNA_def_property_array(prop, 3); @@ -982,11 +972,6 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) 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_materials", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TINT_CREATE_COLORS); - RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material"); - 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); @@ -1147,11 +1132,6 @@ static void rna_def_modifier_gpencilcolor(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Value", "Color Value"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_COLOR_CREATE_COLORS); - RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material"); - 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); @@ -1200,11 +1180,6 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Mode", "Set what colors of the stroke are affected"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "opacity_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, modifier_opacity_mode_items); - RNA_def_property_ui_text(prop, "Opacity Mode", "Set what mode used to define opacity"); - RNA_def_property_update(prop, 0, "rna_GpencilModifier_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"); @@ -1227,11 +1202,6 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Factor", "Factor of Opacity"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - prop = RNA_def_property(srna, "create_materials", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OPACITY_CREATE_COLORS); - RNA_def_property_ui_text(prop, "Create Materials", "When apply modifier, create new material"); - 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); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index a29031900ac..4fb55f02645 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -411,42 +411,45 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) /* 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"}, + {GP_MATERIAL_MODE_LINE, "LINE", 0, "Line", "Draw strokes using a continuous line"}, + {GP_MATERIAL_MODE_DOT, "DOTS", 0, "Dots", "Draw strokes using separated dots"}, + {GP_MATERIAL_MODE_SQUARE, "BOX", 0, "Squares", "Draw strokes using separated squares"}, {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"}, + {GP_MATERIAL_STROKE_STYLE_SOLID, "SOLID", 0, "Solid", "Draw strokes with solid color"}, + {GP_MATERIAL_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_CHECKER, - "CHECKER", + {GP_MATERIAL_FILL_STYLE_SOLID, "SOLID", 0, "Solid", "Fill area with solid color"}, + {GP_MATERIAL_FILL_STYLE_GRADIENT, + "GRADIENT", 0, - "Checker Board", - "Fill area with checkerboard pattern"}, - {GP_STYLE_FILL_STYLE_TEXTURE, "TEXTURE", 0, "Texture", "Fill area with image texture"}, + "Gradient", + "Fill area with gradient color"}, + {GP_MATERIAL_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"}, + {GP_MATERIAL_GRADIENT_LINEAR, "LINEAR", 0, "Linear", "Fill area with gradient color"}, + {GP_MATERIAL_GRADIENT_RADIAL, "RADIAL", 0, "Radial", "Fill area with radial gradient"}, {0, NULL, 0, NULL, NULL}, }; static EnumPropertyItem alignment_draw_items[] = { - {GP_STYLE_FOLLOW_PATH, "PATH", 0, "Path", "Follow stroke drawing path and object rotation"}, - {GP_STYLE_FOLLOW_OBJ, "OBJECT", 0, "Object", "Follow object rotation only"}, - {GP_STYLE_FOLLOW_FIXED, + {GP_MATERIAL_FOLLOW_PATH, + "PATH", + 0, + "Path", + "Follow stroke drawing path and object rotation"}, + {GP_MATERIAL_FOLLOW_OBJ, "OBJECT", 0, "Object", "Follow object rotation only"}, + {GP_MATERIAL_FOLLOW_FIXED, "FIXED", 0, "Fixed", @@ -459,7 +462,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "stroke_rgba"); RNA_def_property_array(prop, 4); @@ -467,7 +470,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "fill_rgba"); RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -475,7 +478,7 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "mix_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "mix_rgba"); RNA_def_property_array(prop, 4); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -483,51 +486,17 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "mix_factor", PROP_FLOAT, PROP_FACTOR); 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_ui_text(prop, "Mix", "Mix Factor"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); /* Stroke Mix factor */ - prop = RNA_def_property(srna, "mix_stroke_factor", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "mix_stroke_factor", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "mix_stroke_factor"); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Mix", "Mix Stroke Color"); - 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_ui_text(prop, "Mix", "Mix Stroke Factor"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); /* Texture angle */ @@ -566,68 +535,48 @@ static void rna_def_material_greasepencil(BlenderRNA *brna) /* 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_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_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_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_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_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_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_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_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_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, "use_fill_texture_mix", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_TEX_MIX); - RNA_def_property_ui_text(prop, "Mix Texture", "Mix texture image with filling color"); - RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); - - prop = RNA_def_property(srna, "use_stroke_texture_mix", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_TEX_MIX); - RNA_def_property_ui_text(prop, "Mix Texture", "Mix texture image with stroke color"); - 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_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_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"); - prop = RNA_def_property(srna, "use_overlap_strokes", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_DISABLE_STENCIL); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_DISABLE_STENCIL); RNA_def_property_ui_text( prop, "Self Overlap", "Disable stencil and overlap self intersections with alpha materials"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); prop = RNA_def_property(srna, "show_stroke", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_STROKE_SHOW); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_STROKE_SHOW); RNA_def_property_ui_text(prop, "Show Stroke", "Show stroke lines of this material"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); prop = RNA_def_property(srna, "show_fill", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STYLE_FILL_SHOW); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_MATERIAL_FILL_SHOW); RNA_def_property_ui_text(prop, "Show Fill", "Show stroke fills of this material"); RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialGpencil_update"); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 69dee01a52b..8fbe83374ae 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -353,6 +353,16 @@ static void rna_MaterialIndex_update(Main *UNUSED(bmain), Scene *UNUSED(scene), } } +static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +{ + Object *ob = (Object *)ptr->owner_id; + if (ob && ob->type == OB_GPENCIL) { + bGPdata *gpd = (bGPdata *)ob->data; + DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); + } +} + static void rna_Object_matrix_local_get(PointerRNA *ptr, float values[16]) { Object *ob = (Object *)ptr->owner_id; @@ -3077,6 +3087,13 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Display All Edges", "Display all edges for mesh objects"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + prop = RNA_def_property(srna, "use_grease_pencil_lights", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_USE_GPENCIL_LIGHTS); + RNA_def_property_boolean_default(prop, true); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_ui_text(prop, "Use Lights", "Lights affect to grease pencil object"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update"); + prop = RNA_def_property(srna, "show_transparent", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWTRANSP); RNA_def_property_ui_text( @@ -3086,7 +3103,7 @@ static void rna_def_object(BlenderRNA *brna) prop = RNA_def_property(srna, "show_in_front", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWXRAY); RNA_def_property_ui_text(prop, "In Front", "Make the object draw in front of others"); - RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_GPencil_update"); /* pose */ prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 85ca851d220..f42f26698c1 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -734,7 +734,7 @@ static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value) } } -static void rna_Gpencil_extend_selection(bContext *C, PointerRNA *ptr) +static void rna_Gpencil_extend_selection(bContext *C, PointerRNA *UNUSED(ptr)) { /* Extend selection to all points in all selected strokes. */ ViewLayer *view_layer = CTX_data_view_layer(C); @@ -768,7 +768,7 @@ static void rna_Gpencil_selectmode_update(bContext *C, PointerRNA *ptr) rna_Gpencil_extend_selection(C, ptr); } -static void rna_Gpencil_mask_point_update(bContext *C, PointerRNA *ptr) +static void rna_Gpencil_mask_point_update(bContext *UNUSED(C), PointerRNA *ptr) { ToolSettings *ts = (ToolSettings *)ptr->data; @@ -786,7 +786,7 @@ static void rna_Gpencil_mask_stroke_update(bContext *C, PointerRNA *ptr) rna_Gpencil_extend_selection(C, ptr); } -static void rna_Gpencil_mask_segment_update(bContext *C, PointerRNA *ptr) +static void rna_Gpencil_mask_segment_update(bContext *UNUSED(C), PointerRNA *ptr) { ToolSettings *ts = (ToolSettings *)ptr->data; @@ -6303,7 +6303,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna) 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, "Simplify Playback", "Simplify Grease Pencil only during animation playback"); + prop, "Playback Only", "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_antialiasing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_AA); + RNA_def_property_ui_text(prop, "Antialiasing", "Use Antialiasing to smooth stroke edges"); 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); @@ -6311,26 +6316,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Fill", "Display 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_negative_sdna( - prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_REMOVE_FILL_LINE); - RNA_def_property_ui_text(prop, "Disable Lines", "Display 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); + prop = RNA_def_property(srna, "simplify_gpencil_modifier", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna( prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_MODIFIER); - RNA_def_property_ui_text(prop, "Disable Modifiers", "Display modifiers in the viewport"); + RNA_def_property_ui_text(prop, "Modifiers", "Display modifiers"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "simplify_gpencil_shader_fx", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_FX); - RNA_def_property_ui_text(prop, "Simplify Shaders", "Display Shader FX"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); - - prop = RNA_def_property(srna, "simplify_gpencil_blend", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_BLEND); - RNA_def_property_ui_text(prop, "Layers Blending", "Display blend layers"); + RNA_def_property_ui_text(prop, "ShadersFX", "Display Shader FX"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); prop = RNA_def_property(srna, "simplify_gpencil_tint", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index b8d5e09d112..3edb060071f 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -528,11 +528,6 @@ static char *rna_GPencilSculptSettings_path(PointerRNA *UNUSED(ptr)) return BLI_strdup("tool_settings.gpencil_sculpt"); } -static char *rna_GPencilSculptBrush_path(PointerRNA *UNUSED(ptr)) -{ - return BLI_strdup("tool_settings.gpencil_sculpt.brush"); -} - static char *rna_GPencilSculptGuide_path(PointerRNA *UNUSED(ptr)) { return BLI_strdup("tool_settings.gpencil_sculpt.guide"); @@ -1374,6 +1369,8 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + UNUSED_VARS(prop_direction_items); + StructRNA *srna; PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index cd4e027ce7c..1d8fd163011 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -52,7 +52,6 @@ const EnumPropertyItem rna_enum_object_shaderfx_type_items[] = { "Apply different tint effects"}, {eShaderFxType_Flip, "FX_FLIP", ICON_SHADERFX, "Flip", "Flip image"}, {eShaderFxType_Glow, "FX_GLOW", ICON_SHADERFX, "Glow", "Create a glow effect"}, - {eShaderFxType_Light, "FX_LIGHT", ICON_SHADERFX, "Light", "Simulate illumination"}, {eShaderFxType_Pixel, "FX_PIXEL", ICON_SHADERFX, "Pixelate", "Pixelate image"}, {eShaderFxType_Rim, "FX_RIM", ICON_SHADERFX, "Rim", "Add a rim to the image"}, {eShaderFxType_Shadow, "FX_SHADOW", ICON_SHADERFX, "Shadow", "Create a shadow effect"}, @@ -117,11 +116,10 @@ static StructRNA *rna_ShaderFx_refine(struct PointerRNA *ptr) return &RNA_ShaderFxFlip; case eShaderFxType_Glow: return &RNA_ShaderFxGlow; - case eShaderFxType_Light: - return &RNA_ShaderFxLight; /* Default */ case eShaderFxType_None: case NUM_SHADER_FX_TYPES: + default: return &RNA_ShaderFx; } @@ -192,7 +190,6 @@ static void shaderfx_object_set(Object *self, Object **ob_p, int type, PointerRN shaderfx_object_set((Object *)ptr->owner_id, &tmd->_prop, _obtype, value); \ } -RNA_FX_OBJECT_SET(Light, object, OB_EMPTY); RNA_FX_OBJECT_SET(Shadow, object, OB_EMPTY); RNA_FX_OBJECT_SET(Swirl, object, OB_EMPTY); @@ -256,14 +253,14 @@ static void rna_def_shader_fx_colorize(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "low_color", PROP_FLOAT, PROP_COLOR); 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); + prop = RNA_def_property(srna, "high_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "high_color"); RNA_def_property_array(prop, 4); @@ -334,7 +331,7 @@ static void rna_def_shader_fx_pixel(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "rgba"); RNA_def_property_array(prop, 4); @@ -363,14 +360,14 @@ static void rna_def_shader_fx_rim(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "rim_color", PROP_FLOAT, PROP_COLOR); 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); + prop = RNA_def_property(srna, "mask_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "mask_rgb"); RNA_def_property_array(prop, 3); @@ -433,7 +430,7 @@ static void rna_def_shader_fx_shadow(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Scale", "Offset of the shadow"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); - prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR_GAMMA); + prop = RNA_def_property(srna, "shadow_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "shadow_rgba"); RNA_def_property_array(prop, 4); @@ -507,14 +504,14 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna) RNA_def_struct_sdna(srna, "GlowShaderFxData"); RNA_def_struct_ui_icon(srna, ICON_SHADERFX); - prop = RNA_def_property(srna, "glow_color", PROP_FLOAT, PROP_COLOR_GAMMA); + prop = RNA_def_property(srna, "glow_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "glow_color"); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Glow Color", "Color used for generated glow"); RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_ShaderFx_update"); - prop = RNA_def_property(srna, "select_color", PROP_FLOAT, PROP_COLOR_GAMMA); + prop = RNA_def_property(srna, "select_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_range(prop, 0.0, 1.0); RNA_def_property_float_sdna(prop, NULL, "select_color"); RNA_def_property_array(prop, 3); @@ -614,38 +611,6 @@ static void rna_def_shader_fx_flip(BlenderRNA *brna) 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_SHADERFX); - - 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_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); - RNA_def_property_update(prop, 0, "rna_ShaderFx_dependency_update"); -} - void RNA_def_shader_fx(BlenderRNA *brna) { StructRNA *srna; @@ -712,7 +677,6 @@ void RNA_def_shader_fx(BlenderRNA *brna) rna_def_shader_fx_glow(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 dbb5c9b0084..c6482b9f8d6 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3697,8 +3697,8 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) 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, "gp_flag", V3D_GP_SHOW_PAPER); + prop = RNA_def_property(srna, "use_gpencil_fade_objects", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_FADE_OBJECTS); RNA_def_property_ui_text( prop, "Fade Objects", @@ -3716,12 +3716,26 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) prop, "Fade Layers", "Toggle fading of Grease Pencil layers except the active one"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); - prop = RNA_def_property(srna, "use_gpencil_fade_objects", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_gpencil_fade_gp_objects", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_FADE_NOACTIVE_GPENCIL); RNA_def_property_ui_text( prop, "Fade Grease Pencil Objects", "Fade Grease Pencil Objects, except the active one"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); + prop = RNA_def_property(srna, "use_gpencil_show_directions", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_STROKE_DIRECTION); + RNA_def_property_ui_text(prop, + "Stroke Direction", + "Show stroke drawing direction with a bigger green dot (start) " + "and smaller red dot (end) points"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); + + prop = RNA_def_property(srna, "use_gpencil_show_material_name", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_MATERIAL_NAME); + RNA_def_property_ui_text( + prop, "Stroke Material Name", "Show material name assigned to each stroke"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); + 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); @@ -3729,7 +3743,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "gpencil_fade_objects", 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_ui_text(prop, "Opacity", "Fade factor"); @@ -3747,12 +3761,12 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) /* show edit lines */ prop = RNA_def_property(srna, "use_gpencil_edit_lines", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gp_flag", V3D_GP_SHOW_EDIT_LINES); - RNA_def_property_ui_text(prop, "Show Edit Lines", "Show edit lines when editing strokes"); + RNA_def_property_ui_text(prop, "Show Edit Lines", "Show Edit Lines when editing 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, "gp_flag", V3D_GP_SHOW_MULTIEDIT_LINES); - RNA_def_property_ui_text(prop, "Lines Only", "Only show edit lines for additional frames"); + RNA_def_property_ui_text(prop, "Lines Only", "Show Edit Lines only in multiframe"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); /* main grease pencil onion switch */ @@ -3763,7 +3777,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) 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); + prop = RNA_def_property(srna, "vertex_opacity", PROP_FLOAT, PROP_FACTOR); 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"); @@ -3771,7 +3785,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update"); /* Vertex Paint opacity factor */ - prop = RNA_def_property(srna, "gpencil_vertex_paint_opacity", PROP_FLOAT, PROP_NONE); + prop = RNA_def_property(srna, "gpencil_vertex_paint_opacity", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "overlay.gpencil_vertex_paint_opacity"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_float_default(prop, 1.0f); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b9fb8638c49..7b4298f2467 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5010,15 +5010,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; - static const EnumPropertyItem multi_sample_levels[] = { - {USER_MULTISAMPLE_NONE, "NONE", 0, "No MultiSample", "Do not use OpenGL MultiSample"}, - {USER_MULTISAMPLE_2, "2", 0, "MultiSample: 2", "Use 2x OpenGL MultiSample"}, - {USER_MULTISAMPLE_4, "4", 0, "MultiSample: 4", "Use 4x OpenGL MultiSample"}, - {USER_MULTISAMPLE_8, "8", 0, "MultiSample: 8", "Use 8x OpenGL MultiSample"}, - {USER_MULTISAMPLE_16, "16", 0, "MultiSample: 16", "Use 16x OpenGL MultiSample"}, - {0, NULL, 0, NULL, NULL}, - }; - static const EnumPropertyItem image_draw_methods[] = { {IMAGE_DRAW_METHOD_AUTO, "AUTO", @@ -5111,16 +5102,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) "Enable Edit-Mode edge smoothing, reducing aliasing, 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( diff --git a/source/blender/shader_fx/CMakeLists.txt b/source/blender/shader_fx/CMakeLists.txt index 6d918763996..9835c5c0588 100644 --- a/source/blender/shader_fx/CMakeLists.txt +++ b/source/blender/shader_fx/CMakeLists.txt @@ -45,7 +45,6 @@ set(SRC intern/FX_shader_colorize.c intern/FX_shader_flip.c intern/FX_shader_glow.c - intern/FX_shader_light.c intern/FX_shader_pixel.c intern/FX_shader_rim.c intern/FX_shader_shadow.c diff --git a/source/blender/shader_fx/FX_shader_types.h b/source/blender/shader_fx/FX_shader_types.h index 7a87c77f313..f338f9bcc2a 100644 --- a/source/blender/shader_fx/FX_shader_types.h +++ b/source/blender/shader_fx/FX_shader_types.h @@ -30,7 +30,6 @@ extern ShaderFxTypeInfo shaderfx_Type_Blur; extern ShaderFxTypeInfo shaderfx_Type_Colorize; extern ShaderFxTypeInfo shaderfx_Type_Flip; extern ShaderFxTypeInfo shaderfx_Type_Glow; -extern ShaderFxTypeInfo shaderfx_Type_Light; extern ShaderFxTypeInfo shaderfx_Type_Pixel; extern ShaderFxTypeInfo shaderfx_Type_Rim; extern ShaderFxTypeInfo shaderfx_Type_Shadow; diff --git a/source/blender/shader_fx/intern/FX_shader_blur.c b/source/blender/shader_fx/intern/FX_shader_blur.c index 72d2a61dafd..70f53995201 100644 --- a/source/blender/shader_fx/intern/FX_shader_blur.c +++ b/source/blender/shader_fx/intern/FX_shader_blur.c @@ -30,8 +30,8 @@ static void initData(ShaderFxData *fx) { BlurShaderFxData *gpfx = (BlurShaderFxData *)fx; - ARRAY_SET_ITEMS(gpfx->radius, 1, 1); - gpfx->samples = 4; + ARRAY_SET_ITEMS(gpfx->radius, 5, 5); + gpfx->samples = 2; gpfx->coc = 0.025f; } @@ -45,7 +45,7 @@ ShaderFxTypeInfo shaderfx_Type_Blur = { /* structName */ "BlurShaderFxData", /* structSize */ sizeof(BlurShaderFxData), /* type */ eShaderFxType_GpencilType, - /* flags */ eShaderFxTypeFlag_Single, + /* flags */ 0, /* copyData */ copyData, diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c index 804b194ed68..41ca903ee08 100644 --- a/source/blender/shader_fx/intern/FX_shader_flip.c +++ b/source/blender/shader_fx/intern/FX_shader_flip.c @@ -47,7 +47,7 @@ ShaderFxTypeInfo shaderfx_Type_Flip = { /* structName */ "FlipShaderFxData", /* structSize */ sizeof(FlipShaderFxData), /* type */ eShaderFxType_GpencilType, - /* flags */ eShaderFxTypeFlag_Single, + /* flags */ 0, /* copyData */ copyData, diff --git a/source/blender/shader_fx/intern/FX_shader_pixel.c b/source/blender/shader_fx/intern/FX_shader_pixel.c index e0ea111d121..f39649bba07 100644 --- a/source/blender/shader_fx/intern/FX_shader_pixel.c +++ b/source/blender/shader_fx/intern/FX_shader_pixel.c @@ -44,7 +44,7 @@ ShaderFxTypeInfo shaderfx_Type_Pixel = { /* structName */ "PixelShaderFxData", /* structSize */ sizeof(PixelShaderFxData), /* type */ eShaderFxType_GpencilType, - /* flags */ eShaderFxTypeFlag_Single, + /* flags */ 0, /* copyData */ copyData, diff --git a/source/blender/shader_fx/intern/FX_shader_shadow.c b/source/blender/shader_fx/intern/FX_shader_shadow.c index 04160f618eb..68d23d65181 100644 --- a/source/blender/shader_fx/intern/FX_shader_shadow.c +++ b/source/blender/shader_fx/intern/FX_shader_shadow.c @@ -44,7 +44,7 @@ static void initData(ShaderFxData *md) gpfx->rotation = 0.0f; ARRAY_SET_ITEMS(gpfx->offset, 15, 20); ARRAY_SET_ITEMS(gpfx->scale, 1.0f, 1.0f); - ARRAY_SET_ITEMS(gpfx->shadow_rgba, 0.54f, 0.62f, 1.0f, 0.9f); + ARRAY_SET_ITEMS(gpfx->shadow_rgba, 0.0f, 0.0f, 0.0f, 0.8f); gpfx->amplitude = 10.0f; gpfx->period = 20.0f; diff --git a/source/blender/shader_fx/intern/FX_shader_util.c b/source/blender/shader_fx/intern/FX_shader_util.c index 908a2b249b8..c2dcae04b85 100644 --- a/source/blender/shader_fx/intern/FX_shader_util.c +++ b/source/blender/shader_fx/intern/FX_shader_util.c @@ -39,7 +39,6 @@ void shaderfx_type_init(ShaderFxTypeInfo *types[]) INIT_FX_TYPE(Colorize); INIT_FX_TYPE(Flip); INIT_FX_TYPE(Glow); - INIT_FX_TYPE(Light); INIT_FX_TYPE(Pixel); INIT_FX_TYPE(Rim); INIT_FX_TYPE(Shadow); diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c index 334024bbd3f..35d2e515f76 100644 --- a/source/blender/shader_fx/intern/FX_shader_wave.c +++ b/source/blender/shader_fx/intern/FX_shader_wave.c @@ -50,7 +50,7 @@ ShaderFxTypeInfo shaderfx_Type_Wave = { /* structName */ "WaveShaderFxData", /* structSize */ sizeof(WaveShaderFxData), /* type */ eShaderFxType_GpencilType, - /* flags */ eShaderFxTypeFlag_Single, + /* flags */ 0, /* copyData */ copyData, |