GPencil: Refactor of Draw Engine, Vertex Paint and all internal functions

This commit is a full refactor of the grease pencil modules including Draw Engine, Modifiers, VFX, depsgraph update, improvements in operators and conversion of Sculpt and Weight paint tools to real brushes.

Also, a huge code cleanup has been done at all levels.

Thanks to @fclem for his work and yo @pepeland and @mendio for the testing and help in the development.

Differential Revision: https://developer.blender.org/D6293
This commit is contained in:
2020-03-09 16:27:24 +01:00
parent dcb9312687
commit 29f3af9527
252 changed files with 21600 additions and 15192 deletions
@@ -187,7 +187,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,
@@ -199,6 +199,9 @@ def generate(context, space_type, use_fallback_keys=True, use_reset=True):
'WEIGHT_PAINT': "weight_tool",
'TEXTURE_PAINT': "image_tool",
'PAINT_GPENCIL': "gpencil_tool",
'VERTEX_GPENCIL': "gpencil_vertex_tool",
'SCULPT_GPENCIL': "gpencil_sculpt_tool",
'WEIGHT_GPENCIL': "gpencil_weight_tool",
}.get(mode, None)
if attr is not None:
setattr(kmi_hack_brush_select_properties, attr, item.data_block)
@@ -194,9 +194,26 @@ _km_hierarchy = [
('Grease Pencil Stroke Paint (Draw brush)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Paint (Fill)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Paint (Erase)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Paint (Tint)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Paint Mode', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt Mode', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Smooth)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Thickness)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Strength)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Grab)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Push)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Twist)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Pinch)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Randomize)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt (Clone)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Weight (Draw)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Vertex Mode', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Vertex (Draw)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Vertex (Blur)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Vertex (Average)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Vertex (Smear)', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Vertex (Replace)', 'EMPTY', 'WINDOW', []),
]),
('Mask Editing', 'EMPTY', 'WINDOW', []),
('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
@@ -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'
@@ -18,18 +16,11 @@ gpcolor.gradient_type = 'LINEAR'
gpcolor.mix_color = (1.0, 1.0, 1.0, 0.2)
gpcolor.mix_factor = 0.0
gpcolor.flip = False
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
@@ -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'
@@ -18,18 +16,11 @@ gpcolor.gradient_type = 'LINEAR'
gpcolor.mix_color = (1.0, 1.0, 1.0, 0.2)
gpcolor.mix_factor = 0.0
gpcolor.flip = False
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
@@ -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'
@@ -18,18 +16,11 @@ gpcolor.gradient_type = 'LINEAR'
gpcolor.mix_color = (1.0, 1.0, 1.0, 0.2)
gpcolor.mix_factor = 0.0
gpcolor.flip = False
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
@@ -3168,6 +3168,10 @@ def km_grease_pencil_stroke_edit_mode(params):
{"properties": [("mode", 1)]}),
("gpencil.selectmode_toggle", {"type": 'THREE', "value": 'PRESS'},
{"properties": [("mode", 2)]}),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
# Context menu
*_template_items_context_menu("VIEW3D_MT_gpencil_edit_context_menu", params.context_menu_event),
])
@@ -3211,6 +3215,10 @@ def km_grease_pencil_stroke_paint_mode(params):
{"properties": [("unselected", False)]}),
("gpencil.hide", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
# Draw context menu
*_template_items_context_panel("VIEW3D_PT_gpencil_draw_context_menu", params.context_menu_event),
])
@@ -3322,6 +3330,25 @@ def km_grease_pencil_stroke_paint_fill(params):
return keymap
def km_grease_pencil_stroke_paint_tint(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Tint)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_mode(params):
items = []
keymap = (
@@ -3336,14 +3363,22 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.strength')]}),
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt_paint.brush.strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.size')]}),
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt_paint.brush.size')]}),
# Copy
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
# Display
*_grease_pencil_display(),
# Keyframe menu
("gpencil.blank_frame_add", {"type": 'I', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
# Context menu
*_template_items_context_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
])
@@ -3351,7 +3386,187 @@ def km_grease_pencil_stroke_sculpt_mode(params):
return keymap
def km_grease_pencil_stroke_weight_mode(_params):
def km_grease_pencil_stroke_sculpt_smooth(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Smooth)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_thickness(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Thickness)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_strength(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Strength)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_grab(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Grab)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_push(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Push)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_twist(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Twist)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_pinch(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Pinch)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_randomize(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Randomize)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_clone(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Clone)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_weight_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Weight Mode",
@@ -3360,19 +3575,196 @@ def km_grease_pencil_stroke_weight_mode(_params):
)
items.extend([
# Painting
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.size')]}),
# Display
*_grease_pencil_display(),
# Keyframe menu
("gpencil.blank_frame_add", {"type": 'I', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
# Context menu
*_template_items_context_panel("VIEW3D_PT_gpencil_weight_context_menu", params.context_menu_event),
])
return keymap
def km_grease_pencil_stroke_weight_draw(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Draw)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Draw
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
])
return keymap
def km_grease_pencil_stroke_vertex_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex Mode",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Selection
*_grease_pencil_selection(params),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
# Display
*_grease_pencil_display(),
# Tools
op_tool("builtin_brush.Draw", {"type": 'D', "value": 'PRESS'}),
op_tool("builtin_brush.Blur", {"type": 'F', "value": 'PRESS'}),
op_tool("builtin_brush.Average", {"type": 'E', "value": 'PRESS'}),
op_tool("builtin.brush.Smear", {"type": 'K', "value": 'PRESS'}),
# Keyframe menu
("gpencil.blank_frame_add", {"type": 'I', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'X', "value": 'PRESS', "shift": True}, None),
("gpencil.active_frames_delete_all", {"type": 'DEL', "value": 'PRESS', "shift": True}, None),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
# Vertex Paint context menu
op_panel("VIEW3D_PT_gpencil_vertex_context_menu", params.context_menu_event),
])
return keymap
def km_grease_pencil_stroke_vertex_draw(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Draw)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.weight_brush.strength')]}),
# Brush sze
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.weight_brush.size')]}),
# Display
*_grease_pencil_display(),
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_blur(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Blur)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_average(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Average)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_smear(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Smear)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_replace(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Replace)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
@@ -6053,18 +6445,13 @@ def km_3d_view_tool_edit_gpencil_to_sphere(params):
)
# Also used for weight paint.
def km_3d_view_tool_sculpt_gpencil_paint(_params):
def km_3d_view_tool_edit_gpencil_transform_fill(params):
return (
"3D View Tool: Sculpt Gpencil, Paint",
"3D View Tool: Edit Gpencil, Transform Fill",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.transform_fill", {"type": params.tool_tweak, "value": 'ANY'},
{"properties": [("release_confirm", True)]}),
]},
)
@@ -6201,8 +6588,25 @@ def generate_keymaps(params=None):
km_grease_pencil_stroke_paint_draw_brush(params),
km_grease_pencil_stroke_paint_erase(params),
km_grease_pencil_stroke_paint_fill(params),
km_grease_pencil_stroke_paint_tint(params),
km_grease_pencil_stroke_sculpt_mode(params),
km_grease_pencil_stroke_sculpt_smooth(params),
km_grease_pencil_stroke_sculpt_thickness(params),
km_grease_pencil_stroke_sculpt_strength(params),
km_grease_pencil_stroke_sculpt_grab(params),
km_grease_pencil_stroke_sculpt_push(params),
km_grease_pencil_stroke_sculpt_twist(params),
km_grease_pencil_stroke_sculpt_pinch(params),
km_grease_pencil_stroke_sculpt_randomize(params),
km_grease_pencil_stroke_sculpt_clone(params),
km_grease_pencil_stroke_weight_mode(params),
km_grease_pencil_stroke_weight_draw(params),
km_grease_pencil_stroke_vertex_mode(params),
km_grease_pencil_stroke_vertex_draw(params),
km_grease_pencil_stroke_vertex_blur(params),
km_grease_pencil_stroke_vertex_average(params),
km_grease_pencil_stroke_vertex_smear(params),
km_grease_pencil_stroke_vertex_replace(params),
km_face_mask(params),
km_weight_paint_vertex_selection(params),
km_pose(params),
@@ -6345,7 +6749,7 @@ def generate_keymaps(params=None):
km_3d_view_tool_edit_gpencil_bend(params),
km_3d_view_tool_edit_gpencil_shear(params),
km_3d_view_tool_edit_gpencil_to_sphere(params),
km_3d_view_tool_sculpt_gpencil_paint(params),
km_3d_view_tool_edit_gpencil_transform_fill(params),
km_3d_view_tool_sculpt_gpencil_select(params),
km_3d_view_tool_sculpt_gpencil_select_box(params),
km_3d_view_tool_sculpt_gpencil_select_circle(params),
@@ -2364,6 +2364,10 @@ def km_grease_pencil_stroke_paint_mode(params):
op_tool_cycle("builtin_brush.Erase", {"type": 'E', "value": 'PRESS'}),
op_tool_cycle("builtin.cutter", {"type": 'K', "value": 'PRESS'}),
op_tool_cycle("builtin.cursor", {"type": 'C', "value": 'PRESS'}),
# Active layer
op_menu("GPENCIL_MT_layer_active", {"type": 'M', "value": 'PRESS'}),
# Keyframe menu
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
])
return keymap
@@ -2470,6 +2474,25 @@ def km_grease_pencil_stroke_paint_fill(params):
return keymap
def km_grease_pencil_stroke_paint_tint(params):
items = []
keymap = (
"Grease Pencil Stroke Paint (Tint)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_mode(params):
items = []
keymap = (
@@ -2481,21 +2504,199 @@ def km_grease_pencil_stroke_sculpt_mode(params):
items.extend([
# Selection
*_grease_pencil_selection(params),
# Painting
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt_paint.brush.strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt_paint.brush.size')]}),
# Copy
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
# Display
*_grease_pencil_display(),
# Context menu
op_panel("VIEW3D_PT_gpencil_sculpt_context_menu", params.context_menu_event),
])
return keymap
def km_grease_pencil_stroke_sculpt_smooth(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Smooth)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_thickness(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Thickness)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_strength(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Strength)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_grab(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Grab)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_push(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Push)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_twist(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Twist)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_pinch(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Pinch)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_randomize(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Randomize)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_sculpt_clone(_params):
items = []
keymap = (
"Grease Pencil Stroke Sculpt (Clone)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'U', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.strength')]}),
# Brush size
("wm.radial_control", {"type": 'S', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.size')]}),
# Context menu
*_template_items_context_panel("VIEW3D_PT_gpencil_sculpt_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
@@ -2510,24 +2711,181 @@ def km_grease_pencil_stroke_weight_mode(params):
)
items.extend([
# Selection
*_grease_pencil_selection(params),
# Painting
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
("gpencil.sculpt_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'U', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.weight_brush.strength')]}),
# Brush size.
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.strength')]}),
# Brush size
("wm.radial_control", {"type": 'S', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.weight_brush.size')]}),
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt.brush.size')]}),
# Context menu
*_template_items_context_panel("VIEW3D_PT_gpencil_weight_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
])
return keymap
def km_grease_pencil_stroke_weight_draw(_params):
items = []
keymap = (
"Grease Pencil Stroke Weight (Draw)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
])
return keymap
def km_grease_pencil_stroke_vertex_mode(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex Mode",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Selection
*_grease_pencil_selection(params),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
# Display
*_grease_pencil_display(),
# Tools
op_tool("builtin_brush.Draw", {"type": 'D', "value": 'PRESS'}),
op_tool("builtin_brush.Blur", {"type": 'F', "value": 'PRESS'}),
op_tool("builtin_brush.Average", {"type": 'E', "value": 'PRESS'}),
op_tool("builtin.brush.Smear", {"type": 'K', "value": 'PRESS'}),
op_tool("builtin.brush.Replace", {"type": 'R', "value": 'PRESS'}),
# Vertex Paint context menu
op_panel("VIEW3D_PT_gpencil_vertex_context_menu", params.context_menu_event),
])
return keymap
def km_grease_pencil_stroke_vertex_draw(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Draw)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_blur(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Blur)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_average(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Average)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_smear(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Smear)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
# Brush strength
("wm.radial_control", {"type": 'U', "value": 'PRESS', "shift": True},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.gpencil_settings.pen_strength')]}),
# Brush size
("wm.radial_control", {"type": 'S', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_grease_pencil_stroke_vertex_replace(params):
items = []
keymap = (
"Grease Pencil Stroke Vertex (Replace)",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items},
)
items.extend([
# Tint
("gpencil.vertex_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("wait_for_input", False)]}),
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
])
return keymap
def km_face_mask(params):
items = []
keymap = (
@@ -3679,8 +4037,25 @@ def generate_keymaps_impl(params=None):
km_grease_pencil_stroke_paint_draw_brush(params),
km_grease_pencil_stroke_paint_erase(params),
km_grease_pencil_stroke_paint_fill(params),
km_grease_pencil_stroke_paint_tint(params),
km_grease_pencil_stroke_sculpt_mode(params),
km_grease_pencil_stroke_sculpt_smooth(params),
km_grease_pencil_stroke_sculpt_thickness(params),
km_grease_pencil_stroke_sculpt_strength(params),
km_grease_pencil_stroke_sculpt_grab(params),
km_grease_pencil_stroke_sculpt_push(params),
km_grease_pencil_stroke_sculpt_twist(params),
km_grease_pencil_stroke_sculpt_pinch(params),
km_grease_pencil_stroke_sculpt_randomize(params),
km_grease_pencil_stroke_sculpt_clone(params),
km_grease_pencil_stroke_weight_mode(params),
km_grease_pencil_stroke_weight_draw(params),
km_grease_pencil_stroke_vertex_mode(params),
km_grease_pencil_stroke_vertex_draw(params),
km_grease_pencil_stroke_vertex_blur(params),
km_grease_pencil_stroke_vertex_average(params),
km_grease_pencil_stroke_vertex_smear(params),
km_grease_pencil_stroke_vertex_replace(params),
km_face_mask(params),
km_weight_paint_vertex_selection(params),
km_pose(params),
@@ -642,10 +642,7 @@ class AddPresetGpencilBrush(AddPresetBase, Operator):
"brush.smooth_stroke_factor",
"settings.pen_smooth_factor",
"settings.pen_smooth_steps",
"settings.pen_thick_smooth_factor",
"settings.pen_thick_smooth_steps",
"settings.pen_subdivision_steps",
"settings.random_subdiv",
"settings.use_settings_random",
"settings.random_pressure",
"settings.random_strength",
@@ -675,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",
@@ -686,18 +681,11 @@ class AddPresetGpencilMaterial(AddPresetBase, Operator):
"gpcolor.mix_color",
"gpcolor.mix_factor",
"gpcolor.flip",
"gpcolor.pattern_shift",
"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",
@@ -22,6 +22,7 @@ from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
from bl_ui.properties_grease_pencil_common import (
GreasePencilLayerMasksPanel,
GreasePencilLayerAdjustmentsPanel,
GreasePencilLayerRelationsPanel,
GreasePencilLayerDisplayPanel,
@@ -116,7 +117,7 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
def draw(self, context):
layout = self.layout
#layout.use_property_split = True
# layout.use_property_split = True
layout.use_property_decorate = False
gpd = context.gpencil
@@ -166,7 +167,6 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
col = layout.column(align=True)
if gpl:
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = True
@@ -178,6 +178,15 @@ class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):
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_masks(LayerDataButtonsPanel, GreasePencilLayerMasksPanel, Panel):
bl_label = "Masks"
bl_parent_id = 'DATA_PT_gpencil_layers'
bl_options = {'DEFAULT_CLOSED'}
class DATA_PT_gpencil_layer_adjustments(LayerDataButtonsPanel, GreasePencilLayerAdjustmentsPanel, Panel):
bl_label = "Adjustments"
@@ -264,7 +273,7 @@ class DATA_PT_gpencil_onion_skinning_display(DataButtonsPanel, Panel):
col.prop(gpd, "use_onion_fade", text="Fade")
sub = layout.column()
sub.active = gpd.onion_mode in {'RELATIVE', 'SELECTED'}
sub.prop(gpd, "use_onion_loop", text="Loop")
sub.prop(gpd, "use_onion_loop", text="Show Start Frame")
class GPENCIL_MT_gpencil_vertex_group(Menu):
@@ -364,9 +373,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"
@@ -381,8 +387,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):
@@ -411,6 +415,7 @@ class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel):
_context_path = "object.data"
_property_type = bpy.types.GreasePencil
###############################
@@ -420,6 +425,7 @@ classes = (
DATA_PT_gpencil_onion_skinning,
DATA_PT_gpencil_onion_skinning_custom_colors,
DATA_PT_gpencil_onion_skinning_display,
DATA_PT_gpencil_layer_masks,
DATA_PT_gpencil_layer_adjustments,
DATA_PT_gpencil_layer_relations,
DATA_PT_gpencil_layer_display,
@@ -437,5 +443,6 @@ classes = (
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)
@@ -1746,132 +1746,102 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
# ...to avoid lengthy if statements
# so each type must have a function here.
def GP_NOISE(self, layout, ob, md):
def gpencil_masking(self, layout, ob, md, use_vertex, use_curve=False):
gpd = ob.data
layout.separator()
layout.label(text="Influence Filters:")
split = layout.split(factor=0.25)
col1 = split.column()
col1.label(text="Layer:")
col1.label(text="Material:")
if use_vertex:
col1.label(text="Vertex Group:")
col2 = split.column()
split = col2.split(factor=0.6)
row = split.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = split.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
split = col2.split(factor=0.6)
row = split.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = split.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
if use_vertex:
row = col2.row(align=True)
row.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
row.prop(md, "invert_vertex", text="", icon='ARROW_LEFTRIGHT')
if use_curve:
col = layout.column()
col.separator()
col.prop(md, "use_custom_curve")
if md.use_custom_curve:
col.template_curve_mapping(md, "curve")
def GP_NOISE(self, layout, ob, md):
split = layout.split()
col = split.column()
row = col.row(align=True)
row.prop(md, "factor")
row.prop(md, "factor", text="Position")
row = col.row(align=True)
row.prop(md, "factor_strength", text="Strength")
row = col.row(align=True)
row.prop(md, "factor_thickness", text="Thickness")
row = col.row(align=True)
row.prop(md, "factor_uvs", text="UV")
col.separator()
row = col.row(align=True)
row.prop(md, "random", text="", icon='TIME', toggle=True)
row = col.row()
row.enabled = md.random
row.prop(md, "step")
row = col.row()
row.enabled = md.random
row.prop(md, "seed")
col.prop(md, "full_stroke")
col.prop(md, "move_extreme")
row = layout.row(align=True)
row.label(text="Affect:")
row = layout.row(align=True)
row.prop(md, "use_edit_position", text="Position", icon='MESH_DATA', toggle=True)
row.prop(md, "use_edit_strength", text="Strength", icon='COLOR', toggle=True)
row.prop(md, "use_edit_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
row.prop(md, "use_edit_uv", text="UV", icon='MOD_UVPROJECT', toggle=True)
subrow = row.row(align=True)
subrow.enabled = md.random
subrow.prop(md, "step")
subrow.prop(md, "seed")
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.prop(md, "noise_scale")
col = layout.column()
col.separator()
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, True, True)
def GP_SMOOTH(self, layout, ob, md):
gpd = ob.data
col = layout.column()
col.prop(md, "factor")
col.prop(md, "step")
col.prop(md, "step", text="Repeat")
col.label(text="Affect:")
row = col.row(align=True)
row.prop(md, "use_edit_position", text="Position", icon='MESH_DATA', toggle=True)
row.prop(md, "use_edit_strength", text="Strength", icon='COLOR', toggle=True)
row.prop(md, "use_edit_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
row.prop(md, "use_edit_uv", text="UV", icon='MOD_UVPROJECT', toggle=True)
row.prop(md, "use_edit_position", text="Position", toggle=True)
row.prop(md, "use_edit_strength", text="Strength", toggle=True)
row.prop(md, "use_edit_thickness", text="Thickness", toggle=True)
row.prop(md, "use_edit_uv", text="UV", toggle=True)
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="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, True, True)
def GP_SUBDIV(self, layout, ob, md):
gpd = ob.data
layout.row().prop(md, "subdivision_type", expand=True)
split = layout.split()
col = split.column()
row = col.row(align=True)
row.prop(md, "level")
row.prop(md, "simple", text="", icon='PARTICLE_POINT')
row.prop(md, "level", text="Subdivisions")
col = layout.column()
col.separator()
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, False)
def GP_SIMPLIFY(self, layout, ob, md):
gpd = ob.data
@@ -1893,77 +1863,21 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
elif md.mode == 'MERGE':
col.prop(md, "distance")
col = layout.column()
col.separator()
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, False)
def GP_THICK(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
row = col.row(align=True)
row.prop(md, "thickness", text="Thickness Factor")
col = layout.column()
col.prop(md, "normalize_thickness")
if not md.normalize_thickness:
split = layout.split()
col = split.column()
col.prop(md, "use_custom_curve")
if md.normalize_thickness:
col.prop(md, "thickness")
else:
col.prop(md, "thickness_factor")
if md.use_custom_curve:
col.template_curve_mapping(md, "curve")
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="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, True, True)
def GP_TINT(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
@@ -1971,30 +1885,9 @@ 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()
col.separator()
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, False, True)
def GP_TIME(self, layout, ob, md):
gpd = ob.data
@@ -2040,7 +1933,6 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
def GP_COLOR(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
@@ -2050,134 +1942,66 @@ 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()
col.separator()
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, False, True)
def GP_OPACITY(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.label(text="Opacity:")
col.prop(md, "factor")
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")
col.prop(md, "normalize_opacity")
if md.normalize_opacity is True:
text="Strength"
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')
text="Opacity Factor"
col = layout.column()
col.separator()
col.prop(md, "factor", text=text)
col.prop(md, "modify_color")
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, True, True)
def GP_ARRAY(self, layout, ob, md):
gpd = ob.data
col = layout.column()
col.prop(md, "count")
split = layout.split()
col = split.column()
col.label(text="Offset:")
col.prop(md, "offset", text="")
col.prop(md, "offset_object", text="Object")
col.prop(md, "use_constant_offset", text="Constant Offset")
subcol = col.column()
subcol.enabled = md.use_constant_offset
subcol.prop(md, "constant_offset", text="")
col.prop(md, "use_object_offset")
subcol = col.column()
subcol.enabled = md.use_object_offset
subcol.prop(md, "offset_object", text="")
col = split.column()
col.label(text="Shift:")
col.prop(md, "shift", text="")
col.prop(md, "use_relative_offset", text="Relative Offset")
subcol = col.column()
subcol.enabled = md.use_relative_offset
subcol.prop(md, "relative_offset", text="")
split = layout.split()
col = split.column()
col.label(text="Rotation:")
col.prop(md, "rotation", text="")
col.separator()
row = col.row(align=True)
row.prop(md, "random_rot", text="", icon='TIME', toggle=True)
row.prop(md, "rot_factor", text="")
col.label(text="Random Offset:")
col.prop(md, "random_offset", text="")
col = split.column()
col.label(text="Scale:")
col.prop(md, "scale", text="")
col.separator()
row = col.row(align=True)
row.prop(md, "random_scale", text="", icon='TIME', toggle=True)
row.prop(md, "scale_factor", text="")
col = layout.column()
col.prop(md, "replace_material", text="Material")
col.prop(md, "keep_on_top", text="Keep original stroke on top")
col.label(text="Random Rotation:")
col.prop(md, "random_rotation", text="")
col = split.column()
col.label(text="Random Scale:")
col.prop(md, "random_scale", text="")
col = layout.column()
col.prop(md, "seed")
col.separator()
col.prop(md, "replace_material", text="Material Override")
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, False)
def GP_BUILD(self, layout, ob, md):
gpd = ob.data
@@ -2215,7 +2039,6 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
def GP_LATTICE(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
@@ -2224,70 +2047,20 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
layout.prop(md, "strength", slider=True)
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="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, True)
def GP_MIRROR(self, layout, ob, md):
gpd = ob.data
row = layout.row(align=True)
row.prop(md, "x_axis")
row.prop(md, "y_axis")
row.prop(md, "z_axis")
layout.label(text="Object:")
layout.label(text="Mirror Object:")
layout.prop(md, "object", text="")
col = layout.column()
col.separator()
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, False)
def GP_HOOK(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
@@ -2317,71 +2090,16 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
col = split.column()
col.prop(md, "use_falloff_uniform")
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="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, True)
def GP_OFFSET(self, layout, ob, md):
gpd = ob.data
col = layout.column()
split = layout.split()
col.prop(md, "location")
col.prop(md, "scale")
col.prop(md, "rotation")
split.column().prop(md, "location")
split.column().prop(md, "rotation")
split.column().prop(md, "scale")
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="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
col = layout.column()
col.separator()
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
self.gpencil_masking(layout, ob, md, True)
def GP_ARMATURE(self, layout, ob, md):
split = layout.split()
@@ -2407,50 +2125,42 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT')
def GP_MULTIPLY(self, layout, ob, md):
gpd = ob.data
col = layout.column()
col.prop(md, "duplications")
col.prop(md, "duplicates")
subcol = col.column()
subcol.enabled = md.duplications > 0
subcol.enabled = md.duplicates > 0
subcol.prop(md, "distance")
subcol.prop(md, "offset", slider=True)
subcol.separator()
subcol.prop(md, "enable_fading")
if md.enable_fading:
subcol.prop(md, "use_fade")
if md.use_fade:
subcol.prop(md, "fading_center")
subcol.prop(md, "fading_thickness", slider=True)
subcol.prop(md, "fading_opacity", slider=True)
subcol.separator()
col.prop(md, "enable_angle_splitting")
if md.enable_angle_splitting:
col.prop(md, "split_angle")
self.gpencil_masking(layout, ob, md, False)
def GP_VERTEXCOLOR(self, layout, ob, md):
col = layout.column()
col.label(text="Object:")
col.prop(md, "object", text="")
col.separator()
col.label(text="Material:")
row = col.row(align=True)
row.prop_search(md, "material", gpd, "materials", text="", icon='SHADING_TEXTURE')
row.prop(md, "invert_materials", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_material_pass", text="", icon='ARROW_LEFTRIGHT')
row.prop(md, "radius")
row.prop(md, "factor", text="Strength", slider=True)
col = layout.column()
col.separator()
col.label(text="Colors:")
col.template_color_ramp(md, "colors")
col.label(text="Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row.prop(md, "invert_layers", text="", icon='ARROW_LEFTRIGHT')
row = layout.row(align=True)
row.prop(md, "layer_pass", text="Pass")
row.prop(md, "invert_layer_pass", text="", icon='ARROW_LEFTRIGHT')
col.separator()
col.prop(md, "vertex_mode")
self.gpencil_masking(layout, ob, md, True, True)
classes = (
@@ -2460,5 +2170,6 @@ classes = (
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)
@@ -56,27 +56,30 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel):
def FX_BLUR(self, layout, fx):
layout.prop(fx, "factor", text="Factor")
layout.prop(fx, "use_dof_mode", text="Use as Depth Of Field")
layout.separator()
col = layout.column()
col.enabled = not fx.use_dof_mode
col.prop(fx, "size", text="Size")
col.separator()
col.prop(fx, "rotation")
layout.prop(fx, "samples", text="Samples")
layout.separator()
layout.prop(fx, "use_dof_mode")
if fx.use_dof_mode:
layout.prop(fx, "coc")
def FX_COLORIZE(self, layout, fx):
layout.prop(fx, "mode", text="Mode")
if fx.mode == 'BITONE':
if fx.mode == 'DUOTONE':
layout.prop(fx, "low_color", text="Low Color")
if fx.mode == 'CUSTOM':
layout.prop(fx, "low_color", text="Color")
if fx.mode == 'BITONE':
if fx.mode == 'DUOTONE':
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)
@@ -127,16 +130,21 @@ class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel):
def FX_GLOW(self, layout, fx):
layout.prop(fx, "mode")
layout.prop(fx, "glow_color")
if fx.mode == 'LUMINANCE':
layout.prop(fx, "threshold")
else:
layout.prop(fx, "select_color")
layout.prop(fx, "glow_color")
layout.separator()
layout.prop(fx, "radius")
layout.prop(fx, "blend_mode", text="Blend")
layout.prop(fx, "opacity")
layout.prop(fx, "size")
layout.prop(fx, "rotation")
layout.prop(fx, "samples")
layout.prop(fx, "use_alpha_mode", text="Use Alpha Mode")
layout.prop(fx, "use_glow_under", text="Glow Under")
def FX_SWIRL(self, layout, fx):
layout.prop(fx, "object", text="Object")
@@ -144,18 +152,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,
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Menu, UIList
from bpy.types import Menu, UIList, Operator
from bpy.app.translations import pgettext_iface as iface_
@@ -108,11 +108,6 @@ class AnnotationDrawingToolsPanel:
sub.operator("gpencil.blank_frame_add", icon='FILE_NEW')
sub.operator("gpencil.active_frames_delete_all", icon='X', text="Delete Frame(s)")
#sub = col.column(align=True)
#sub.prop(context.tool_settings, "use_gpencil_draw_additive", text="Additive Drawing")
#sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing")
#sub.prop(context.tool_settings, "use_gpencil_draw_onback", text="Draw on Back")
col.separator()
col.separator()
@@ -125,9 +120,6 @@ class AnnotationDrawingToolsPanel:
elif is_clip_editor:
row.prop(context.space_data, "grease_pencil_source", expand=True)
# col.separator()
# col.separator()
gpencil_stroke_placement_settings(context, col)
@@ -136,29 +128,33 @@ class GreasePencilSculptOptionsPanel:
@classmethod
def poll(cls, context):
settings = context.tool_settings.gpencil_sculpt
tool = settings.sculpt_tool
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_sculpt_paint
brush = settings.brush
tool = brush.gpencil_sculpt_tool
return bool(tool in {'SMOOTH', 'RANDOMIZE', 'SMOOTH'})
return bool(tool in {'SMOOTH', 'RANDOMIZE'})
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
tool = settings.sculpt_tool
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_sculpt_paint
brush = settings.brush
gp_settings = brush.gpencil_settings
tool = brush.gpencil_sculpt_tool
if tool in {'SMOOTH', 'RANDOMIZE'}:
layout.prop(settings, "use_edit_position", text="Affect Position")
layout.prop(settings, "use_edit_strength", text="Affect Strength")
layout.prop(settings, "use_edit_thickness", text="Affect Thickness")
layout.prop(gp_settings, "use_edit_position", text="Affect Position")
layout.prop(gp_settings, "use_edit_strength", text="Affect Strength")
layout.prop(gp_settings, "use_edit_thickness", text="Affect Thickness")
if tool == 'SMOOTH':
layout.prop(brush, "use_edit_pressure")
layout.prop(gp_settings, "use_edit_pressure")
layout.prop(settings, "use_edit_uv", text="Affect UV")
layout.prop(gp_settings, "use_edit_uv", text="Affect UV")
# GP Object Tool Settings
@@ -174,7 +170,7 @@ class GreasePencilDisplayPanel:
if context.mode == 'PAINT_GPENCIL':
return brush.gpencil_tool != 'ERASE'
else:
# GP Sculpt and Weight Paint always have Brush Tip panel.
# GP Sculpt, Vertex and Weight Paint always have Brush Tip panel.
return True
return False
@@ -182,16 +178,18 @@ class GreasePencilDisplayPanel:
if self.is_popover:
return
tool_settings = context.tool_settings
if context.mode == 'PAINT_GPENCIL':
brush = context.tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
self.layout.prop(gp_settings, "use_cursor", text="")
elif context.mode in {'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
settings = context.tool_settings.gpencil_sculpt
brush = settings.brush
self.layout.prop(brush, "use_cursor", text="")
settings = tool_settings.gpencil_paint
elif context.mode == 'SCULPT_GPENCIL':
settings = tool_settings.gpencil_sculpt_paint
elif context.mode == 'WEIGHT_GPENCIL':
settings = tool_settings.gpencil_weight_paint
elif context.mode == 'VERTEX_GPENCIL':
settings = tool_settings.gpencil_vertex_paint
brush = settings.brush
if brush:
self.layout.prop(settings, "show_brush", text="")
def draw(self, context):
layout = self.layout
@@ -199,279 +197,101 @@ class GreasePencilDisplayPanel:
layout.use_property_decorate = False
tool_settings = context.tool_settings
ob = context.active_object
if context.mode == 'PAINT_GPENCIL':
settings = tool_settings.gpencil_paint
elif context.mode == 'SCULPT_GPENCIL':
settings = tool_settings.gpencil_sculpt_paint
elif context.mode == 'WEIGHT_GPENCIL':
settings = tool_settings.gpencil_weight_paint
elif context.mode == 'VERTEX_GPENCIL':
settings = tool_settings.gpencil_vertex_paint
brush = settings.brush
gp_settings = brush.gpencil_settings
ob = context.active_object
if ob.mode == 'PAINT_GPENCIL':
brush = tool_settings.gpencil_paint.brush
gp_settings = brush.gpencil_settings
if self.is_popover:
row = layout.row(align=True)
row.prop(gp_settings, "use_cursor", text="")
row.prop(settings, "show_brush", text="")
row.label(text="Display Cursor")
col = layout.column(align=True)
col.active = gp_settings.use_cursor
col.active = settings.show_brush
if brush.gpencil_tool == 'DRAW':
col.prop(gp_settings, "show_lasso", text="Show Fill Color While Drawing")
if brush.gpencil_tool == 'FILL':
col.prop(brush, "cursor_color_add", text="Cursor Color")
elif ob.mode in {'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
settings = tool_settings.gpencil_sculpt
brush = settings.brush
tool = settings.sculpt_tool
if self.is_popover:
row = layout.row(align=True)
row.prop(brush, "use_cursor", text="")
row.label(text="Display Cursor")
elif ob.mode == 'SCULPT_GPENCIL':
col = layout.column(align=True)
col.active = brush.use_cursor
col.active = settings.show_brush
col.prop(brush, "cursor_color_add", text="Cursor Color")
if tool in {'THICKNESS', 'STRENGTH', 'PINCH', 'TWIST'}:
col.prop(brush, "cursor_color_sub", text="Inverse Cursor Color")
if brush.gpencil_sculpt_tool in {'THICKNESS', 'STRENGTH', 'PINCH', 'TWIST'}:
col.prop(brush, "cursor_color_subtract", text="Inverse Cursor Color")
elif ob.mode == 'WEIGHT_GPENCIL':
col = layout.column(align=True)
col.active = settings.show_brush
col.prop(brush, "cursor_color_add", text="Cursor Color")
elif ob.mode == 'VERTEX_GPENCIL':
row = layout.row(align=True)
row.prop(settings, "show_brush", text="")
row.label(text="Display Cursor")
class GPENCIL_MT_pie_tool_palette(Menu):
"""A pie menu for quick access to Grease Pencil tools"""
bl_label = "Grease Pencil Tools"
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
gpd = context.gpencil_data
# W - Drawing Types
col = pie.column()
col.operator("gpencil.draw", text="Draw", icon='GREASEPENCIL').mode = 'DRAW'
col.operator("gpencil.draw", text="Straight Lines", icon='LINE_DATA').mode = 'DRAW_STRAIGHT'
col.operator("gpencil.draw", text="Poly", icon='MESH_DATA').mode = 'DRAW_POLY'
# E - Eraser
# XXX: needs a dedicated icon...
col = pie.column()
col.operator("gpencil.draw", text="Eraser", icon='FORCE_CURVE').mode = 'ERASER'
# E - "Settings" Palette is included here too, since it needs to be in a stable position...
if gpd and gpd.layers.active:
col.separator()
col.operator(
"wm.call_menu_pie",
text="Settings...",
icon='SCRIPTWIN').name = "GPENCIL_MT_pie_settings_palette"
# Editing tools
if gpd:
if gpd.use_stroke_edit_mode and context.editable_gpencil_strokes:
# S - Exit Edit Mode
pie.operator("gpencil.editmode_toggle", text="Exit Edit Mode", icon='EDIT')
# N - Transforms
col = pie.column()
row = col.row(align=True)
row.operator("transform.translate", icon='MAN_TRANS')
row.operator("transform.rotate", icon='MAN_ROT')
row.operator("transform.resize", text="Scale", icon='MAN_SCALE')
row = col.row(align=True)
row.label(text="Proportional Edit:")
row.prop(context.tool_settings, "use_proportional_edit", text="", icon_only=True)
row.prop(context.tool_settings, "proportional_edit_falloff", text="", icon_only=True)
# NW - Select (Non-Modal)
col = pie.column()
col.operator("gpencil.select_all", text="Select All", icon='PARTICLE_POINT')
col.operator("gpencil.select_all", text="Select Inverse", icon='BLANK1')
col.operator("gpencil.select_linked", text="Select Linked", icon='LINKED')
col.operator("gpencil.palettecolor_select", text="Select Color", icon='COLOR')
# NE - Select (Modal)
col = pie.column()
col.operator("gpencil.select_box", text="Box Select", icon='BORDER_RECT')
col.operator("gpencil.select_circle", text="Circle Select", icon='META_EMPTY')
col.operator("gpencil.select_lasso", text="Lasso Select", icon='BORDER_LASSO')
col.operator("gpencil.select_alternate", text="Alternate Select", icon='BORDER_LASSO')
# SW - Edit Tools
col = pie.column()
col.operator("gpencil.duplicate_move", icon='PARTICLE_PATH', text="Duplicate")
col.operator("gpencil.delete", icon='X', text="Delete...")
# SE - More Tools
pie.operator("wm.call_menu_pie", text="More...").name = "GPENCIL_MT_pie_tools_more"
else:
# Toggle Edit Mode
pie.operator("gpencil.editmode_toggle", text="Enable Stroke Editing", icon='EDIT')
class GPENCIL_MT_pie_settings_palette(Menu):
"""A pie menu for quick access to Grease Pencil settings"""
bl_label = "Grease Pencil Settings"
class GreasePencilBrushFalloff:
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return bool(context.gpencil_data and context.active_gpencil_layer)
ts = context.tool_settings
settings = None
if context.mode == 'PAINT_GPENCIL':
settings = ts.gpencil_paint
if context.mode == 'SCULPT_GPENCIL':
settings = ts.gpencil_sculpt_paint
elif context.mode == 'WEIGHT_GPENCIL':
settings = ts.gpencil_weight_paint
elif context.mode == 'VERTEX_GPENCIL':
settings = ts.gpencil_vertex_paint
return (settings and settings.brush and settings.brush.curve)
def draw(self, context):
layout = self.layout
ts = context.tool_settings
settings = None
if context.mode == 'PAINT_GPENCIL':
settings = ts.gpencil_paint
if context.mode == 'SCULPT_GPENCIL':
settings = ts.gpencil_sculpt_paint
elif context.mode == 'WEIGHT_GPENCIL':
settings = ts.gpencil_weight_paint
elif context.mode == 'VERTEX_GPENCIL':
settings = ts.gpencil_vertex_paint
pie = layout.menu_pie()
gpd = context.gpencil_data
gpl = context.active_gpencil_layer
palcolor = None # context.active_gpencil_palettecolor
if settings:
brush = settings.brush
is_editmode = bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
# W - Stroke draw settings
col = pie.column(align=True)
if palcolor is not None:
col.enabled = not palcolor.lock
col.label(text="Stroke")
col.prop(palcolor, "color", text="")
col.prop(palcolor, "alpha", text="", slider=True)
# E - Fill draw settings
col = pie.column(align=True)
if palcolor is not None:
col.enabled = not palcolor.lock
col.label(text="Fill")
col.prop(palcolor, "fill_color", text="")
col.prop(palcolor, "fill_alpha", text="", slider=True)
# S Brush settings
gpencil_active_brush_settings_simple(context, pie)
# N - Active Layer
col = pie.column()
col.label(text="Active Layer: ")
row = col.row()
row.operator_context = 'EXEC_REGION_WIN'
row.operator_menu_enum("gpencil.layer_change", "layer", text="", icon='GREASEPENCIL')
row.prop(gpl, "info", text="")
row.operator("gpencil.layer_remove", text="", icon='X')
row = col.row()
row.prop(gpl, "lock")
row.prop(gpl, "hide")
col.prop(gpl, "use_onion_skinning")
# NW/NE/SW/SE - These operators are only available in editmode
# as they require strokes to be selected to work
if is_editmode:
# NW - Move stroke Down
col = pie.column(align=True)
col.label(text="Arrange Strokes")
col.operator("gpencil.stroke_arrange", text="Send to Back").direction = 'BOTTOM'
col.operator("gpencil.stroke_arrange", text="Send Backward").direction = 'DOWN'
# NE - Move stroke Up
col = pie.column(align=True)
col.label(text="Arrange Strokes")
col.operator("gpencil.stroke_arrange", text="Bring to Front").direction = 'TOP'
col.operator("gpencil.stroke_arrange", text="Bring Forward").direction = 'UP'
# SW - Move stroke to color
col = pie.column(align=True)
col.operator("gpencil.stroke_change_color", text="Move to Color")
# SE - Join strokes
col = pie.column(align=True)
col.label(text="Join Strokes")
row = col.row()
row.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
row.operator("gpencil.stroke_join", text="Join & Copy").type = 'JOINCOPY'
col.operator("gpencil.stroke_flip", text="Flip Direction")
col.prop(gpd, "show_stroke_direction", text="Show Drawing Direction")
class GPENCIL_MT_pie_tools_more(Menu):
"""A pie menu for accessing more Grease Pencil tools"""
bl_label = "More Grease Pencil Tools"
@classmethod
def poll(cls, context):
gpd = context.gpencil_data
return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
def draw(self, _context):
layout = self.layout
pie = layout.menu_pie()
# gpd = context.gpencil_data
col = pie.column(align=True)
col.operator("gpencil.copy", text="Copy", icon='COPYDOWN')
col.operator("gpencil.paste", text="Paste", icon='PASTEDOWN').type = 'ACTIVE'
col.operator("gpencil.paste", text="Paste by Layer").type = 'LAYER'
col = pie.column(align=True)
col.operator("gpencil.select_more", icon='ADD')
col.operator("gpencil.select_less", icon='REMOVE')
pie.operator("transform.mirror", icon='MOD_MIRROR')
pie.operator("transform.bend", icon='MOD_SIMPLEDEFORM')
pie.operator("transform.shear", icon='MOD_TRIANGULATE')
pie.operator("transform.tosphere", icon='MOD_MULTIRES')
pie.operator("gpencil.convert", icon='OUTLINER_OB_CURVE', text="Convert...")
pie.operator("wm.call_menu_pie", text="Back to Main Palette...").name = "GPENCIL_MT_pie_tool_palette"
class GPENCIL_MT_pie_sculpt(Menu):
"""A pie menu for accessing Grease Pencil stroke sculpt settings"""
bl_label = "Grease Pencil Sculpt"
@classmethod
def poll(cls, context):
gpd = context.gpencil_data
return bool(gpd and gpd.use_stroke_edit_mode and context.editable_gpencil_strokes)
def draw(self, context):
layout = self.layout
pie = layout.menu_pie()
settings = context.tool_settings.gpencil_sculpt
brush = settings.brush
# W - Launch Sculpt Mode
col = pie.column()
# col.label(text="Tool:")
col.prop(settings, "sculpt_tool", text="")
col.operator("gpencil.sculpt_paint", text="Sculpt", icon='SCULPTMODE_HLT')
# E - Common Settings
col = pie.column(align=True)
col.prop(brush, "size", slider=True)
row = col.row(align=True)
row.prop(brush, "strength", slider=True)
# row.prop(brush, "use_pressure_strength", text="", icon_only=True)
col.prop(brush, "use_falloff")
if settings.sculpt_tool in {'SMOOTH', 'RANDOMIZE'}:
col = layout.column(align=True)
row = col.row(align=True)
row.prop(settings, "use_edit_position", text="Position", icon='MESH_DATA', toggle=True)
row.prop(settings, "use_edit_strength", text="Strength", icon='COLOR', toggle=True)
row.prop(settings, "use_edit_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
row.prop(brush, "curve_preset", text="")
# S - Change Brush Type Shortcuts
row = pie.row()
row.prop_enum(settings, "tool", value='GRAB')
row.prop_enum(settings, "tool", value='PUSH')
row.prop_enum(settings, "tool", value='CLONE')
if brush.curve_preset == 'CUSTOM':
layout.template_curve_mapping(brush, "curve", brush=True)
# N - Change Brush Type Shortcuts
row = pie.row()
row.prop_enum(settings, "tool", value='SMOOTH')
row.prop_enum(settings, "tool", value='THICKNESS')
row.prop_enum(settings, "tool", value='STRENGTH')
row.prop_enum(settings, "tool", value='RANDOMIZE')
col = layout.column(align=True)
row = col.row(align=True)
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
class GPENCIL_MT_snap(Menu):
@@ -515,6 +335,32 @@ class GPENCIL_MT_move_to_layer(Menu):
layout.operator("gpencil.layer_add", text="New Layer", icon='ADD')
class GPENCIL_MT_layer_active(Menu):
bl_label = "Change Active Layer"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
gpd = context.gpencil_data
if gpd:
gpl_active = context.active_gpencil_layer
tot_layers = len(gpd.layers)
i = tot_layers - 1
while i >= 0:
gpl = gpd.layers[i]
if gpl.info == gpl_active.info:
icon = 'GREASEPENCIL'
else:
icon = 'NONE'
layout.operator("gpencil.layer_active", text=gpl.info, icon=icon).layer = i
i -= 1
layout.separator()
layout.operator("gpencil.layer_add", text="New Layer", icon='ADD')
class GPENCIL_MT_gpencil_draw_delete(Menu):
bl_label = "Delete"
@@ -800,11 +646,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")
@@ -813,6 +655,48 @@ class GreasePencilMaterialsPanel:
row.template_ID(space, "pin_id")
class GreasePencilVertexcolorPanel:
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
ts = context.scene.tool_settings
is_vertex = context.mode == 'VERTEX_GPENCIL'
gpencil_paint = ts.gpencil_vertex_paint if is_vertex else ts.gpencil_paint
brush = gpencil_paint.brush
gp_settings = brush.gpencil_settings
tool = brush.gpencil_vertex_tool if is_vertex else brush.gpencil_tool
ob = context.object
if ob:
col = layout.column()
col.template_color_picker(brush, "color", value_slider=True)
sub_row = layout.row(align=True)
sub_row.prop(brush, "color", text="")
sub_row.prop(brush, "secondary_color", text="")
sub_row.operator("gpencil.tint_flip", icon='FILE_REFRESH', text="")
row = layout.row(align=True)
row.template_ID(gpencil_paint, "palette", new="palette.new")
if gpencil_paint.palette:
layout.template_palette(gpencil_paint, "palette", color=True)
if tool in {'DRAW', 'FILL'} and is_vertex is False:
row = layout.row(align=True)
row.prop(gp_settings, "vertex_mode", text="Mode")
row = layout.row(align=True)
row.prop(gp_settings, "vertex_color_factor", slider=True, text="Mix Factor")
if tool == 'TINT' or is_vertex is True:
row = layout.row(align=True)
row.prop(gp_settings, "vertex_mode", text="Mode")
class GPENCIL_UL_layer(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
# assert(isinstance(item, bpy.types.GPencilLayer)
@@ -830,9 +714,10 @@ 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 = 'MOD_MASK' if gpl.use_mask_layer else 'LAYER_ACTIVE'
row.prop(gpl, "use_mask_layer", text="", icon=icon_mask, emboss=False)
subrow = row.row(align=True)
subrow.prop(
@@ -868,16 +753,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:
@@ -913,6 +794,65 @@ class GreasePencilLayerAdjustmentsPanel:
col.prop(gpl, "lock_material")
class GPENCIL_UL_masks(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
mask = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row(align=True)
row.prop(mask, "name", text="", emboss=False, icon_value=icon)
row.prop(mask, "invert", text="", emboss=False)
row.prop(mask, "hide", text="", emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.prop(mask, "name", text="", emboss=False, icon_value=icon)
class GPENCIL_MT_layer_mask_menu(Menu):
bl_label = "Layer Specials"
def draw(self, context):
layout = self.layout
ob = context.object
gpd = ob.data
gpl_active = gpd.layers.active
done = False
for gpl in gpd.layers:
if gpl != gpl_active and gpl.info not in gpl_active.mask_layers:
done = True
layout.operator("gpencil.layer_mask_add", text=gpl.info).name=gpl.info
if done is False:
layout.label(text="No layers to add")
class GreasePencilLayerMasksPanel:
def draw_header(self, context):
ob = context.active_object
gpd = ob.data
gpl = gpd.layers.active
self.layout.prop(gpl, "use_mask_layer", text="")
def draw(self, context):
ob = context.active_object
gpd = ob.data
gpl = gpd.layers.active
layout = self.layout
layout.enabled = gpl.use_mask_layer
if gpl:
rows = 4
row = layout.row()
col = row.column()
col.template_list("GPENCIL_UL_masks", "", gpl, "mask_layers", gpl.mask_layers,
"active_mask_index", rows=rows, sort_lock=True)
col2 = row.column(align=True)
col2.menu("GPENCIL_MT_layer_mask_menu", icon='ADD', text="")
col2.operator("gpencil.layer_mask_remove", icon='REMOVE', text="")
class GreasePencilLayerRelationsPanel:
def draw(self, context):
@@ -952,20 +892,58 @@ class GreasePencilLayerDisplayPanel:
col.prop(gpl, "use_solo_mode", text="Show Only On Keyframed")
classes = (
GPENCIL_MT_pie_tool_palette,
GPENCIL_MT_pie_settings_palette,
GPENCIL_MT_pie_tools_more,
GPENCIL_MT_pie_sculpt,
class GreasePencilFlipTintColors(Operator):
bl_label = "Flip Colors"
bl_idname = "gpencil.tint_flip"
bl_description = "Switch Tint colors"
def execute(self, context):
try:
ts = context.tool_settings
settings = None
if context.mode == 'PAINT_GPENCIL':
settings = ts.gpencil_paint
if context.mode == 'SCULPT_GPENCIL':
settings = ts.gpencil_sculpt_paint
elif context.mode == 'WEIGHT_GPENCIL':
settings = ts.gpencil_weight_paint
elif context.mode == 'VERTEX_GPENCIL':
settings = ts.gpencil_vertex_paint
brush = settings.brush
if brush is not None:
color = brush.color
secondary_color = brush.secondary_color
orig_prim = color.hsv
orig_sec = secondary_color.hsv
color.hsv = orig_sec
secondary_color.hsv = orig_prim
return {'FINISHED'}
except Exception as e:
utils_core.error_handlers(self, "gpencil.tint_flip", e,
"Flip Colors could not be completed")
return {'CANCELLED'}
classes = (
GPENCIL_MT_snap,
GPENCIL_MT_cleanup,
GPENCIL_MT_move_to_layer,
GPENCIL_MT_layer_active,
GPENCIL_MT_gpencil_draw_delete,
GPENCIL_MT_layer_mask_menu,
GPENCIL_UL_annotation_layer,
GPENCIL_UL_layer,
GPENCIL_UL_masks,
GreasePencilFlipTintColors,
)
if __name__ == "__main__": # only for live edit.
@@ -47,6 +47,11 @@ class GPENCIL_MT_color_context_menu(Menu):
layout.separator()
layout.operator("object.material_slot_remove_unused")
layout.operator("gpencil.stroke_merge_material", text="Merge Similar")
layout.separator()
layout.operator("gpencil.material_to_vertex_color", text="Convert Materials to Vertex Color")
layout.operator("gpencil.extract_palette_vertex", text="Extract Palette from Vertex Color")
class GPENCIL_UL_matslots(UIList):
@@ -142,27 +147,25 @@ class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel):
col.prop(gpcolor, "stroke_style", text="Style")
row = col.row()
row.prop(gpcolor, "color", text="Base Color")
if gpcolor.stroke_style == 'TEXTURE':
row = col.row()
row.enabled = not gpcolor.lock
col = row.column(align=True)
col.template_ID(gpcolor, "stroke_image", open="image.open")
if gpcolor.stroke_style == 'TEXTURE':
row = col.row()
row.prop(gpcolor, "mix_stroke_factor", text="Blend", slider=True)
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")
if (gpcolor.stroke_style == 'SOLID' or gpcolor.use_stroke_pattern or gpcolor.use_stroke_texture_mix):
col.prop(gpcolor, "color", text="Color")
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")
@@ -188,55 +191,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':
if gpcolor.fill_style == 'SOLID':
col.prop(gpcolor, "fill_color", text="Base Color")
elif gpcolor.fill_style == 'GRADIENT':
col.prop(gpcolor, "gradient_type")
if gpcolor.fill_style != 'TEXTURE':
col.prop(gpcolor, "fill_color", text="Color")
col.prop(gpcolor, "fill_color", text="Base Color")
col.prop(gpcolor, "mix_color", text="Secondary Color")
col.prop(gpcolor, "mix_factor", text="Blend in Fill Gradient", slider=True)
col.prop(gpcolor, "flip", text="Flip Colors")
if gpcolor.fill_style in {'GRADIENT', 'CHECKER'}:
col.prop(gpcolor, "mix_color", text="Secondary Color")
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")
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")
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")
if gpcolor.fill_style == 'CHECKER':
col.prop(gpcolor, "pattern_gridsize", text="Box Size")
# 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="Color")
col.prop(gpcolor, "fill_color", text="Base Color")
col.prop(gpcolor, "texture_opacity", slider=True)
col.prop(gpcolor, "mix_factor", text="Blend in Fill Texture", 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"
@@ -291,5 +274,6 @@ classes = (
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)
@@ -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,
)
@@ -89,8 +89,12 @@ class UnifiedPaintPanel:
# Grease Pencil settings
elif mode == 'PAINT_GPENCIL':
return tool_settings.gpencil_paint
elif mode in {'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
return tool_settings.gpencil_sculpt
elif mode == 'SCULPT_GPENCIL':
return tool_settings.gpencil_sculpt_paint
elif mode == 'WEIGHT_GPENCIL':
return tool_settings.gpencil_weight_paint
elif mode == 'VERTEX_GPENCIL':
return tool_settings.gpencil_vertex_paint
return None
@staticmethod
@@ -1019,6 +1023,8 @@ def brush_basic_texpaint_settings(layout, context, brush, *, compact=False):
def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False):
tool_settings = context.tool_settings
settings = tool_settings.gpencil_paint
gp_settings = brush.gpencil_settings
tool = context.workspace.tools.from_space_view3d_mode(context.mode, create=False)
if gp_settings is None:
@@ -1043,7 +1049,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
row.prop(gp_settings, "eraser_thickness_factor")
row = layout.row(align=True)
row.prop(gp_settings, "use_cursor", text="Display Cursor")
row.prop(settings, "show_brush", text="Display Cursor")
# FIXME: tools must use their own UI drawing!
elif brush.gpencil_tool == 'FILL':
@@ -1091,51 +1097,62 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
def brush_basic_gpencil_sculpt_settings(layout, context, brush, *, compact=False):
tool_settings = context.tool_settings
settings = tool_settings.gpencil_sculpt
tool = settings.sculpt_tool
gp_settings = brush.gpencil_settings
tool = brush.gpencil_sculpt_tool
row = layout.row(align=True)
row.prop(brush, "size", slider=True)
sub = row.row(align=True)
sub.enabled = tool not in {'GRAB', 'CLONE'}
sub.prop(brush, "use_pressure_radius", text="")
sub.prop(gp_settings, "use_pressure", text="")
row = layout.row(align=True)
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
layout.prop(brush, "use_falloff")
if compact:
if tool in {'THICKNESS', 'STRENGTH', 'PINCH', 'TWIST'}:
row.separator()
row.prop(brush, "direction", expand=True, text="")
row.prop(gp_settings, "direction", expand=True, text="")
else:
use_property_split_prev = layout.use_property_split
layout.use_property_split = False
if tool in {'THICKNESS', 'STRENGTH'}:
layout.row().prop(brush, "direction", expand=True)
layout.row().prop(gp_settings, "direction", expand=True)
elif tool == 'PINCH':
row = layout.row(align=True)
row.prop_enum(brush, "direction", value='ADD', text="Pinch")
row.prop_enum(brush, "direction", value='SUBTRACT', text="Inflate")
row.prop_enum(gp_settings, "direction", value='ADD', text="Pinch")
row.prop_enum(gp_settings, "direction", value='SUBTRACT', text="Inflate")
elif tool == 'TWIST':
row = layout.row(align=True)
row.prop_enum(brush, "direction", value='ADD', text="CCW")
row.prop_enum(brush, "direction", value='SUBTRACT', text="CW")
row.prop_enum(gp_settings, "direction", value='ADD', text="CCW")
row.prop_enum(gp_settings, "direction", value='SUBTRACT', text="CW")
layout.use_property_split = use_property_split_prev
def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=False):
gp_settings = brush.gpencil_settings
layout.prop(brush, "size", slider=True)
row = layout.row(align=True)
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
layout.prop(brush, "weight", slider=True)
layout.prop(brush, "use_falloff")
layout.prop(brush, "weight", slider=True)
def brush_basic_gpencil_vertex_settings(layout, _context, brush, *, compact=False):
gp_settings = brush.gpencil_settings
# Brush details
row = layout.row(align=True)
row.prop(brush, "size", text="Radius")
row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
if brush.gpencil_vertex_tool in {'DRAW', 'BLUR', 'SMEAR'}:
row = layout.row(align=True)
row.prop(gp_settings, "pen_strength", slider=True)
row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
classes = (
VIEW3D_MT_tools_projectpaint_clone,
@@ -26,6 +26,7 @@ from bpy.types import (
)
from bl_ui.properties_grease_pencil_common import (
GreasePencilLayerMasksPanel,
GreasePencilLayerAdjustmentsPanel,
GreasePencilLayerRelationsPanel,
GreasePencilLayerDisplayPanel,
@@ -699,6 +700,15 @@ 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_masks(LayersDopeSheetPanel, GreasePencilLayerMasksPanel, Panel):
bl_label = "Masks"
bl_parent_id = 'DOPESHEET_PT_gpencil_mode'
bl_options = {'DEFAULT_CLOSED'}
class DOPESHEET_PT_gpencil_layer_adjustments(LayersDopeSheetPanel, GreasePencilLayerAdjustmentsPanel, Panel):
bl_label = "Adjustments"
@@ -736,6 +746,7 @@ classes = (
DOPESHEET_MT_snap_pie,
DOPESHEET_PT_filters,
DOPESHEET_PT_gpencil_mode,
DOPESHEET_PT_gpencil_layer_masks,
DOPESHEET_PT_gpencil_layer_adjustments,
DOPESHEET_PT_gpencil_layer_relations,
DOPESHEET_PT_gpencil_layer_display,
@@ -238,6 +238,11 @@ class IMAGE_MT_image(Menu):
layout.separator()
layout.operator("image.pack", text="Pack")
if ima:
layout.separator()
layout.operator("palette.extract_from_image", text="Extract Palette")
layout.operator("gpencil.image_to_grease_pencil", text="Generate Grease Pencil")
class IMAGE_MT_image_invert(Menu):
bl_label = "Invert"
@@ -1455,6 +1455,11 @@ class _defs_gpencil_paint:
@ToolDef.from_fn
def eyedropper():
def draw_settings(context, layout, tool):
props = tool.operator_properties("ui.eyedropper_gpencil_color")
row = layout.row()
row.use_property_split = False
row.prop(props, "mode", expand=True)
return dict(
idname="builtin.eyedropper",
label="Eyedropper",
@@ -1462,6 +1467,7 @@ class _defs_gpencil_paint:
cursor='EYEDROPPER',
widget=None,
keymap=(),
draw_settings=draw_settings,
)
@@ -1594,6 +1600,23 @@ class _defs_gpencil_edit:
draw_settings=_template_widget.VIEW3D_GGT_xform_extrude.draw_settings,
)
@ToolDef.from_fn
def transform_fill():
def draw_settings(context, layout, tool):
props = tool.operator_properties("gpencil.transform_fill")
row = layout.row()
row.use_property_split = False
row.prop(props, "mode", expand=True)
return dict(
idname="builtin.transform_fill",
label="Transform Fill",
icon="ops.gpencil.transform_fill",
cursor='DEFAULT',
widget=None,
keymap=(),
draw_settings=draw_settings,
)
class _defs_gpencil_sculpt:
@@ -1613,11 +1636,10 @@ class _defs_gpencil_sculpt:
context,
idname_prefix="builtin_brush.",
icon_prefix="ops.gpencil.sculpt_",
type=bpy.types.GPencilSculptSettings,
attr="sculpt_tool",
type=bpy.types.Brush,
attr="gpencil_sculpt_tool",
tooldef_keywords=dict(
operator="gpencil.sculpt_paint",
keymap="3D View Tool: Sculpt Gpencil, Paint",
),
)
@@ -1630,11 +1652,37 @@ class _defs_gpencil_weight:
context,
idname_prefix="builtin_brush.",
icon_prefix="ops.gpencil.sculpt_",
type=bpy.types.GPencilSculptSettings,
attr="weight_tool",
type=bpy.types.Brush,
attr="gpencil_weight_tool",
tooldef_keywords=dict(
operator="gpencil.sculpt_paint",
keymap="3D View Tool: Sculpt Gpencil, Paint",
operator="gpencil.weight_paint",
),
)
class _defs_gpencil_vertex:
@staticmethod
def poll_select_mask(context):
if context is None:
return True
ob = context.active_object
ts = context.scene.tool_settings
return ob and ob.type == 'GPENCIL' and (ts.use_gpencil_vertex_select_mask_point or
ts.use_gpencil_vertex_select_mask_stroke or
ts.use_gpencil_vertex_select_mask_segment)
@staticmethod
def generate_from_brushes(context):
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",
icon_prefix="brush.paint_vertex.",
type=bpy.types.Brush,
attr="gpencil_vertex_tool",
cursor='DOT',
tooldef_keywords=dict(
operator="gpencil.vertex_paint",
),
)
@@ -2202,6 +2250,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_gpencil_edit.tosphere,
),
None,
_defs_gpencil_edit.transform_fill,
None,
*_tools_annotate,
],
'SCULPT_GPENCIL': [
@@ -2219,6 +2269,17 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_annotate,
],
'VERTEX_GPENCIL': [
_defs_gpencil_vertex.generate_from_brushes,
None,
*_tools_annotate,
None,
lambda context: (
VIEW3D_PT_tools_active._tools_gpencil_select
if _defs_gpencil_vertex.poll_select_mask(context)
else ()
),
],
}
class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
bl_space_type = 'SEQUENCE_EDITOR'
@@ -165,11 +165,11 @@ class TOPBAR_PT_gpencil_layers(Panel):
srow = col.row(align=True)
srow.prop(gpl, "opacity", text="Opacity", slider=True)
srow.prop(gpl, "mask_layer", text="",
icon='MOD_MASK' if gpl.mask_layer else 'LAYER_ACTIVE')
srow.prop(gpl, "use_mask_layer", text="",
icon='MOD_MASK' if gpl.use_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()
@@ -668,7 +668,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")
+216 -53
View File
@@ -31,6 +31,7 @@ from bl_ui.properties_grease_pencil_common import (
AnnotationDataPanel,
AnnotationOnionSkin,
GreasePencilMaterialsPanel,
GreasePencilVertexcolorPanel,
)
from bl_ui.space_toolsystem_common import (
ToolActivePanelHelper,
@@ -119,21 +120,27 @@ class VIEW3D_HT_tool_header(Header):
if is_valid_context:
brush = context.tool_settings.gpencil_paint.brush
if brush.gpencil_tool != 'ERASE':
layout.popover("VIEW3D_PT_tools_grease_pencil_brush_advanced")
if brush.gpencil_tool != 'TINT':
layout.popover("VIEW3D_PT_tools_grease_pencil_brush_advanced")
if brush.gpencil_tool != 'FILL':
if brush.gpencil_tool not in {'FILL', 'TINT'}:
layout.popover("VIEW3D_PT_tools_grease_pencil_brush_stroke")
layout.popover("VIEW3D_PT_tools_grease_pencil_brushcurves")
layout.popover("VIEW3D_PT_tools_grease_pencil_paint_appearance")
elif tool_mode == 'SCULPT_GPENCIL':
settings = context.tool_settings.gpencil_sculpt
tool = settings.sculpt_tool
if tool in {'SMOOTH', 'RANDOMIZE', 'SMOOTH'}:
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_options")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
if is_valid_context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
tool = brush.gpencil_tool
if tool in ('SMOOTH', 'RANDOMIZE'):
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_options")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'WEIGHT_GPENCIL':
layout.popover("VIEW3D_PT_tools_grease_pencil_weight_appearance")
if is_valid_context:
layout.popover("VIEW3D_PT_tools_grease_pencil_weight_appearance")
elif tool_mode == 'VERTEX_GPENCIL':
if is_valid_context:
layout.popover("VIEW3D_PT_tools_grease_pencil_vertex_appearance")
def draw_mode_settings(self, context):
layout = self.layout
@@ -425,6 +432,15 @@ class _draw_tool_settings_context_mode:
row.prop(gp_settings, "use_material_pin", text="")
if brush.gpencil_tool in {'DRAW', 'FILL'} and ma:
row.separator(factor=1.0)
subrow = row.row(align=True)
row.prop_enum(settings, "color_mode", 'MATERIAL', text="", icon='MATERIAL')
row.prop_enum(settings, "color_mode", 'VERTEXCOLOR', text="", icon='VPAINT_HLT')
sub_row = row.row(align=True)
sub_row.enabled = settings.color_mode == 'VERTEXCOLOR'
sub_row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor")
row = layout.row(align=True)
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_paint
@@ -433,6 +449,10 @@ class _draw_tool_settings_context_mode:
if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}:
draw_color_selector()
if context.object and brush.gpencil_tool == 'TINT':
row.separator(factor=0.4)
row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor")
from bl_ui.properties_paint_common import (
brush_basic_gpencil_paint_settings,
)
@@ -444,9 +464,8 @@ class _draw_tool_settings_context_mode:
def SCULPT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
return False
tool_settings = context.tool_settings
settings = tool_settings.gpencil_sculpt
brush = settings.brush
paint = context.tool_settings.gpencil_sculpt_paint
brush = paint.brush
from bl_ui.properties_paint_common import (
brush_basic_gpencil_sculpt_settings,
@@ -459,9 +478,8 @@ class _draw_tool_settings_context_mode:
def WEIGHT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
return False
tool_settings = context.tool_settings
settings = tool_settings.gpencil_sculpt
brush = settings.brush
paint = context.tool_settings.gpencil_weight_paint
brush = paint.brush
from bl_ui.properties_paint_common import (
brush_basic_gpencil_weight_settings,
@@ -470,6 +488,31 @@ class _draw_tool_settings_context_mode:
return True
@staticmethod
def VERTEX_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
return False
paint = context.tool_settings.gpencil_vertex_paint
brush = paint.brush
row = layout.row(align=True)
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_vertex_paint
row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
if brush.gpencil_vertex_tool not in {'BLUR', 'AVERAGE', 'SMEAR'}:
row.separator(factor=0.4)
row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor")
from bl_ui.properties_paint_common import (
brush_basic_gpencil_vertex_settings,
)
brush_basic_gpencil_vertex_settings(layout, context, brush, compact=True)
return True
@staticmethod
def PARTICLE(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
@@ -550,7 +593,7 @@ class VIEW3D_HT_header(Header):
else:
if (object_mode not in {
'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT',
'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'
'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'
}) or has_pose_mode:
show_snap = True
else:
@@ -687,7 +730,14 @@ class VIEW3D_HT_header(Header):
row.prop(tool_settings, "use_gpencil_select_mask_stroke", text="")
row.prop(tool_settings, "use_gpencil_select_mask_segment", text="")
if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode:
# Select mode for Vertex Paint
if gpd.is_stroke_vertex_mode:
row = layout.row(align=True)
row.prop(tool_settings, "use_gpencil_vertex_select_mask_point", text="")
row.prop(tool_settings, "use_gpencil_vertex_select_mask_stroke", text="")
row.prop(tool_settings, "use_gpencil_vertex_select_mask_segment", text="")
if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode or gpd.is_stroke_vertex_mode:
row = layout.row(align=True)
row.prop(gpd, "use_multiedit", text="", icon='GP_MULTIFRAME_EDITING')
@@ -812,7 +862,8 @@ class VIEW3D_MT_editor_menus(Menu):
obj = context.active_object
mode_string = context.mode
edit_object = context.edit_object
gp_edit = obj and obj.mode in {'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}
gp_edit = obj and obj.mode in {'EDIT_GPENCIL', 'PAINT_GPENCIL', 'SCULPT_GPENCIL',
'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'}
ts = context.scene.tool_settings
layout.menu("VIEW3D_MT_view")
@@ -827,6 +878,8 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_select_gpencil")
elif mode_string == 'EDIT_GPENCIL':
layout.menu("VIEW3D_MT_select_gpencil")
elif mode_string == 'VERTEX_GPENCIL':
layout.menu("VIEW3D_MT_select_gpencil")
elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
mesh = obj.data
if mesh.use_paint_mask:
@@ -4650,6 +4703,10 @@ class VIEW3D_MT_paint_gpencil(Menu):
layout = self.layout
layout.menu("GPENCIL_MT_layer_active", text="Active Layer")
layout.separator()
layout.menu("VIEW3D_MT_gpencil_animation")
layout.menu("VIEW3D_MT_edit_gpencil_interpolate")
@@ -4708,6 +4765,10 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.separator()
layout.menu("GPENCIL_MT_layer_active", text="Active Layer")
layout.separator()
layout.menu("VIEW3D_MT_gpencil_animation")
layout.menu("VIEW3D_MT_edit_gpencil_interpolate")
@@ -4742,6 +4803,7 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
def draw(self, _context):
layout = self.layout
settings = _context.tool_settings.gpencil_sculpt
layout.operator("gpencil.stroke_subdivide", text="Subdivide").only_selected = False
layout.menu("VIEW3D_MT_gpencil_simplify")
@@ -4767,6 +4829,10 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
layout.operator_menu_enum("gpencil.stroke_caps_set", text="Toggle Caps", property="type")
layout.operator("gpencil.stroke_flip", text="Switch Direction")
layout.prop(settings, "use_scale_thickness")
layout.separator()
layout.operator("gpencil.reset_transform_fill", text="Reset Fill Transform")
class VIEW3D_MT_edit_gpencil_point(Menu):
@@ -4811,6 +4877,22 @@ class VIEW3D_MT_weight_gpencil(Menu):
layout.menu("VIEW3D_MT_gpencil_autoweights")
class VIEW3D_MT_vertex_gpencil(Menu):
bl_label = "Paint"
def draw(self, _context):
layout = self.layout
layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors")
layout.separator()
layout.operator("gpencil.vertex_color_invert", text="Invert")
layout.operator("gpencil.vertex_color_levels", text="Levels")
layout.operator("gpencil.vertex_color_hsv", text="Hue Saturation Value")
layout.operator("gpencil.vertex_color_brightness_contrast", text="Bright/Contrast")
layout.separator()
layout.menu("VIEW3D_MT_join_palette")
class VIEW3D_MT_gpencil_animation(Menu):
bl_label = "Animation"
@@ -6473,6 +6555,7 @@ class VIEW3D_PT_overlay_gpencil_options(Panel):
'EDIT_GPENCIL': "Edit Grease Pencil",
'SCULPT_GPENCIL': "Sculpt Grease Pencil",
'WEIGHT_GPENCIL': "Weight Grease Pencil",
'VERTEX_GPENCIL': "Vertex Grease Pencil",
'OBJECT': "Grease Pencil",
}[context.mode])
@@ -6497,17 +6580,32 @@ 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'}:
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'}:
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")
layout.prop(overlay, "vertex_opacity", text="Vertex Opacity", slider=True)
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)
class VIEW3D_PT_quad_view(Panel):
bl_space_type = 'VIEW_3D'
@@ -6783,77 +6881,127 @@ class VIEW3D_MT_gpencil_edit_context_menu(Menu):
col.operator("gpencil.reproject", text="Reproject Strokes")
def draw_gpencil_layer_active(context, layout):
gpl = context.active_gpencil_layer
if gpl:
layout.label(text="Active Layer")
row = layout.row(align=True)
row.operator_context = 'EXEC_REGION_WIN'
row.operator_menu_enum("gpencil.layer_change", "layer", text="", icon='GREASEPENCIL')
row.prop(gpl, "info", text="")
row.operator("gpencil.layer_remove", text="", icon='X')
class VIEW3D_PT_gpencil_sculpt_context_menu(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_label = "Sculpt Context Menu"
bl_ui_units_x = 12
def draw(self, context):
brush = context.tool_settings.gpencil_sculpt.brush
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
layout = self.layout
if context.mode == 'WEIGHT_GPENCIL':
layout.prop(brush, "weight")
layout.prop(brush, "size", slider=True)
layout.prop(brush, "strength")
layout.separator()
# Layers
draw_gpencil_layer_active(context, layout)
# Frames
layout.label(text="Frames:")
layout.operator_context = 'INVOKE_REGION_WIN'
class VIEW3D_PT_gpencil_weight_context_menu(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_label = "Weight Paint Context Menu"
bl_ui_units_x = 12
layout.operator("gpencil.blank_frame_add", text="Insert Blank in Active Layer", icon='ADD')
layout.operator("gpencil.blank_frame_add", text="Insert Blank in All Layers", icon='ADD').all_layers = True
def draw(self, context):
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
layout.separator()
layout = self.layout
layout.operator("gpencil.frame_duplicate", text="Duplicate Active Layer", icon='DUPLICATE')
layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers", icon='DUPLICATE').mode = 'ALL'
layout.prop(brush, "size", slider=True)
layout.prop(brush, "strength")
layout.prop(brush, "weight")
layout.separator()
layout.operator("gpencil.delete", text="Delete Active Layer", icon='REMOVE').type = 'FRAME'
layout.operator("gpencil.active_frames_delete_all", text="Delete All Layers", icon='REMOVE')
# Layers
draw_gpencil_layer_active(context, layout)
class VIEW3D_PT_gpencil_draw_context_menu(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_label = "Draw Context Menu"
bl_ui_units_x = 12
def draw(self, context):
brush = context.tool_settings.gpencil_paint.brush
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
gp_settings = brush.gpencil_settings
layout = self.layout
if brush.gpencil_tool not in {'ERASE', 'CUTTER', 'EYEDROPPER'} and settings.color_mode == 'VERTEXCOLOR':
split = layout.split(factor=0.1)
split.prop(brush, "color", text="")
split.template_color_picker(brush, "color", value_slider=True)
col = layout.column()
col.separator()
col.prop_menu_enum(gp_settings, "vertex_mode", text="Mode")
col.separator()
if brush.gpencil_tool not in {'FILL', 'CUTTER'}:
layout.prop(brush, "size", slider=True)
if brush.gpencil_tool not in {'ERASE', 'FILL', 'CUTTER'}:
layout.prop(gp_settings, "pen_strength")
layout.separator()
# Layers
draw_gpencil_layer_active(context, layout)
# Frames
layout.label(text="Frames:")
layout.operator_context = 'INVOKE_REGION_WIN'
class VIEW3D_PT_gpencil_vertex_context_menu(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_label = "Vertex Paint Context Menu"
bl_ui_units_x = 12
layout.operator("gpencil.blank_frame_add", text="Insert Blank in Active Layer", icon='ADD')
layout.operator("gpencil.blank_frame_add", text="Insert Blank in All Layers", icon='ADD').all_layers = True
def draw(self, context):
layout = self.layout
ts = context.tool_settings
settings = ts.gpencil_vertex_paint
brush = settings.brush
gp_settings = brush.gpencil_settings
layout.separator()
col = layout.column()
layout.operator("gpencil.frame_duplicate", text="Duplicate Active Layer", icon='DUPLICATE')
layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers", icon='DUPLICATE').mode = 'ALL'
if brush.gpencil_vertex_tool in {'DRAW', 'REPLACE'}:
split = layout.split(factor=0.1)
split.prop(brush, "color", text="")
split.template_color_picker(brush, "color", value_slider=True)
layout.separator()
col = layout.column()
col.separator()
col.prop_menu_enum(gp_settings, "vertex_mode", text="Mode")
col.separator()
layout.operator("gpencil.delete", text="Delete Active Layer", icon='REMOVE').type = 'FRAME'
layout.operator("gpencil.active_frames_delete_all", text="Delete All Layers", icon='REMOVE')
row = col.row(align=True)
row.prop(brush, "size", text="Radius")
row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
if brush.gpencil_vertex_tool in {'DRAW', 'BLUR', 'SMEAR'}:
row = layout.row(align=True)
row.prop(gp_settings, "pen_strength", slider=True)
row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
# Layers
draw_gpencil_layer_active(context, layout)
class VIEW3D_PT_paint_vertex_context_menu(Panel):
@@ -7037,6 +7185,17 @@ class TOPBAR_PT_gpencil_materials(GreasePencilMaterialsPanel, Panel):
return ob and ob.type == 'GPENCIL'
class TOPBAR_PT_gpencil_vertexcolor(GreasePencilVertexcolorPanel, Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Vertex Color"
bl_ui_units_x = 10
@classmethod
def poll(cls, context):
ob = context.object
return ob and ob.type == 'GPENCIL'
classes = (
VIEW3D_HT_header,
VIEW3D_HT_tool_header,
@@ -7163,6 +7322,7 @@ classes = (
VIEW3D_MT_edit_gpencil_delete,
VIEW3D_MT_edit_gpencil_showhide,
VIEW3D_MT_weight_gpencil,
VIEW3D_MT_vertex_gpencil,
VIEW3D_MT_gpencil_animation,
VIEW3D_MT_gpencil_simplify,
VIEW3D_MT_gpencil_copy_layer,
@@ -7249,10 +7409,13 @@ classes = (
VIEW3D_PT_paint_vertex_context_menu,
VIEW3D_PT_paint_texture_context_menu,
VIEW3D_PT_paint_weight_context_menu,
VIEW3D_PT_gpencil_vertex_context_menu,
VIEW3D_PT_gpencil_sculpt_context_menu,
VIEW3D_PT_gpencil_weight_context_menu,
VIEW3D_PT_gpencil_draw_context_menu,
VIEW3D_PT_sculpt_context_menu,
TOPBAR_PT_gpencil_materials,
TOPBAR_PT_gpencil_vertexcolor,
TOPBAR_PT_annotation_layers,
)
@@ -21,6 +21,7 @@ from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
GreasePencilSculptOptionsPanel,
GreasePencilDisplayPanel,
GreasePencilBrushFalloff,
)
from bl_ui.properties_paint_common import (
UnifiedPaintPanel,
@@ -71,6 +72,33 @@ class VIEW3D_MT_brush_context_menu(Menu):
layout.operator("brush.reset")
class VIEW3D_MT_brush_gpencil_context_menu(Menu):
bl_label = "Brush Specials"
def draw(self, context):
layout = self.layout
ts = context.tool_settings
settings = None
if context.mode == 'PAINT_GPENCIL':
settings = ts.gpencil_paint
if context.mode == 'SCULPT_GPENCIL':
settings = ts.gpencil_sculpt_paint
elif context.mode == 'WEIGHT_GPENCIL':
settings = ts.gpencil_weight_paint
elif context.mode == 'VERTEX_GPENCIL':
settings = ts.gpencil_vertex_paint
brush = getattr(settings, "brush", None)
# skip if no active brush
if not brush:
layout.label(text="No Brushes currently available", icon='INFO')
return
layout.operator("gpencil.brush_reset")
layout.operator("gpencil.brush_reset_all")
class VIEW3D_MT_brush_context_menu_paint_modes(Menu):
bl_label = "Enabled Modes"
@@ -1339,7 +1367,7 @@ class VIEW3D_PT_tools_particlemode_options_display(View3DPanel, Panel):
# Grease Pencil drawing brushes
class GreasePencilPanel:
class GreasePencilPaintPanel:
bl_context = ".greasepencil_paint"
bl_category = "Tool"
@@ -1355,7 +1383,7 @@ class GreasePencilPanel:
return True
class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePencilPanel):
class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePencilPaintPanel):
bl_label = "Brushes"
def draw(self, context):
@@ -1370,7 +1398,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePenci
row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8)
col = row.column()
col.operator("gpencil.brush_presets_create", icon='PRESET_NEW', text="")
col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="")
if context.mode == 'PAINT_GPENCIL':
brush = tool_settings.gpencil_paint.brush
@@ -1383,7 +1411,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_select(Panel, View3DPanel, GreasePenci
layout.row().prop(brush, "icon_filepath", text="")
class VIEW3D_PT_tools_grease_pencil_brush_settings(Panel, View3DPanel, GreasePencilPanel):
class VIEW3D_PT_tools_grease_pencil_brush_settings(Panel, View3DPanel, GreasePencilPaintPanel):
bl_label = "Brush Settings"
# What is the point of brush presets? Seems to serve the exact same purpose as brushes themselves??
@@ -1431,7 +1459,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
@classmethod
def poll(cls, context):
brush = context.tool_settings.gpencil_paint.brush
return brush is not None and brush.gpencil_tool != 'ERASE'
return brush is not None and brush.gpencil_tool not in {'ERASE', 'TINT'}
def draw(self, context):
layout = self.layout
@@ -1463,11 +1491,11 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
ma = brush.gpencil_settings.material
col.separator()
col.prop(gp_settings, "hardeness", slider=True)
subcol = col.column(align=True)
if ma and ma.grease_pencil.mode == 'LINE':
subcol.enabled = False
subcol.prop(gp_settings, "gradient_factor", slider=True)
subcol.prop(gp_settings, "gradient_shape")
subcol.prop(gp_settings, "aspect")
elif brush.gpencil_tool == 'FILL':
row = col.row(align=True)
@@ -1479,6 +1507,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_advanced(View3DPanel, Panel):
col.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes")
col.prop(gp_settings, "fill_threshold", text="Threshold")
class VIEW3D_PT_tools_grease_pencil_brush_stroke(Panel, View3DPanel):
bl_context = ".greasepencil_paint"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_settings'
@@ -1545,7 +1574,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_post_processing(View3DPanel, Panel):
@classmethod
def poll(cls, context):
brush = context.tool_settings.gpencil_paint.brush
return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL', 'TINT'}
def draw_header(self, context):
if self.is_popover:
@@ -1575,13 +1604,8 @@ class VIEW3D_PT_tools_grease_pencil_brush_post_processing(View3DPanel, Panel):
col1.prop(gp_settings, "pen_smooth_factor")
col1.prop(gp_settings, "pen_smooth_steps")
col1 = col.column(align=True)
col1.prop(gp_settings, "pen_thick_smooth_factor")
col1.prop(gp_settings, "pen_thick_smooth_steps", text="Iterations")
col1 = col.column(align=True)
col1.prop(gp_settings, "pen_subdivision_steps")
col1.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
col1 = col.column(align=True)
col1.prop(gp_settings, "simplify_factor")
@@ -1600,7 +1624,7 @@ class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
@classmethod
def poll(cls, context):
brush = context.tool_settings.gpencil_paint.brush
return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL', 'TINT'}
def draw_header(self, context):
if self.is_popover:
@@ -1646,7 +1670,7 @@ class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel):
@classmethod
def poll(cls, context):
brush = context.tool_settings.gpencil_paint.brush
return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL'}
return brush is not None and brush.gpencil_tool not in {'ERASE', 'FILL', 'TINT'}
def draw(self, context):
pass
@@ -1703,6 +1727,24 @@ class VIEW3D_PT_tools_grease_pencil_brushcurves_jitter(View3DPanel, Panel):
use_negative_slope=True)
class VIEW3D_PT_tools_grease_pencil_brush_paint_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel):
bl_context = ".greasepencil_paint"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
if brush is None:
return False
tool = brush.gpencil_tool
return (settings and settings.brush and settings.brush.curve and tool == 'TINT')
# Grease Pencil stroke interpolation tools
class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
bl_space_type = 'VIEW_3D'
@@ -1751,25 +1793,49 @@ class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
# Grease Pencil stroke sculpting tools
class VIEW3D_PT_tools_grease_pencil_sculpt_select(Panel, View3DPanel):
class GreasePencilSculptPanel:
bl_context = ".greasepencil_sculpt"
bl_label = "Brushes"
bl_category = "Tool"
@classmethod
def poll(cls, context):
if context.space_data.type in ('VIEW_3D', 'PROPERTIES'):
if context.gpencil_data is None:
return False
gpd = context.gpencil_data
return bool(gpd.is_stroke_sculpt_mode)
else:
return True
class VIEW3D_PT_tools_grease_pencil_sculpt_select(Panel, View3DPanel, GreasePencilSculptPanel):
bl_label = "Brushes"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
tool_settings = context.scene.tool_settings
gpencil_paint = tool_settings.gpencil_sculpt_paint
layout.template_icon_view(settings, "sculpt_tool", show_labels=True)
row = layout.row()
row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8)
col = row.column()
col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="")
if context.mode == 'SCULPT_GPENCIL':
brush = tool_settings.gpencil_sculpt_paint.brush
if brush is not None:
col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="")
if(brush.use_custom_icon):
layout.row().prop(brush, "icon_filepath", text="")
class VIEW3D_PT_tools_grease_pencil_sculpt_settings(Panel, View3DPanel):
bl_context = ".greasepencil_sculpt"
bl_category = "Tool"
class VIEW3D_PT_tools_grease_pencil_sculpt_settings(Panel, View3DPanel, GreasePencilSculptPanel):
bl_label = "Brush Settings"
def draw(self, context):
@@ -1777,7 +1843,8 @@ class VIEW3D_PT_tools_grease_pencil_sculpt_settings(Panel, View3DPanel):
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_sculpt_paint
brush = settings.brush
if not self.is_popover:
@@ -1786,27 +1853,63 @@ class VIEW3D_PT_tools_grease_pencil_sculpt_settings(Panel, View3DPanel):
)
brush_basic_gpencil_sculpt_settings(layout, context, brush)
class VIEW3D_PT_tools_grease_pencil_brush_sculpt_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel):
bl_context = ".greasepencil_sculpt"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ts = context.tool_settings
settings = ts.gpencil_sculpt_paint
return (settings and settings.brush and settings.brush.curve)
# Grease Pencil weight painting tools
class VIEW3D_PT_tools_grease_pencil_weight_paint_select(View3DPanel, Panel):
class GreasePencilWeightPanel:
bl_context = ".greasepencil_weight"
bl_label = "Brushes"
bl_category = "Tool"
@classmethod
def poll(cls, context):
if context.space_data.type in ('VIEW_3D', 'PROPERTIES'):
if context.gpencil_data is None:
return False
gpd = context.gpencil_data
return bool(gpd.is_stroke_weight_mode)
else:
return True
class VIEW3D_PT_tools_grease_pencil_weight_paint_select(View3DPanel, Panel, GreasePencilWeightPanel):
bl_label = "Brushes"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
tool_settings = context.scene.tool_settings
gpencil_paint = tool_settings.gpencil_weight_paint
layout.template_icon_view(settings, "weight_tool", show_labels=True)
row = layout.row()
row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8)
col = row.column()
col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="")
if context.mode == 'WEIGHT_GPENCIL':
brush = tool_settings.gpencil_weight_paint.brush
if brush is not None:
col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="")
if(brush.use_custom_icon):
layout.row().prop(brush, "icon_filepath", text="")
class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel):
bl_context = ".greasepencil_weight"
bl_category = "Tool"
class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, GreasePencilWeightPanel):
bl_label = "Brush Settings"
def draw(self, context):
@@ -1814,7 +1917,8 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel):
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.tool_settings.gpencil_sculpt
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_weight_paint
brush = settings.brush
if not self.is_popover:
@@ -1824,6 +1928,272 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel):
brush_basic_gpencil_weight_settings(layout, context, brush)
class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel):
bl_context = ".greasepencil_weight"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ts = context.tool_settings
settings = ts.gpencil_weight_paint
brush = settings.brush
return (settings and settings.brush and settings.brush.curve)
# Grease Pencil vertex painting tools
class GreasePencilVertexPanel:
bl_context = ".greasepencil_vertex"
bl_category = "Tool"
@classmethod
def poll(cls, context):
if context.space_data.type in ('VIEW_3D', 'PROPERTIES'):
if context.gpencil_data is None:
return False
gpd = context.gpencil_data
return bool(gpd.is_stroke_vertex_mode)
else:
return True
class VIEW3D_PT_tools_grease_pencil_vertex_paint_select(View3DPanel, Panel, GreasePencilVertexPanel):
bl_label = "Brushes"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
tool_settings = context.scene.tool_settings
gpencil_paint = tool_settings.gpencil_vertex_paint
row = layout.row()
row.column().template_ID_preview(gpencil_paint, "brush", new="brush.add_gpencil", rows=3, cols=8)
col = row.column()
col.menu("VIEW3D_MT_brush_gpencil_context_menu", icon='DOWNARROW_HLT', text="")
if context.mode == 'VERTEX_GPENCIL':
brush = tool_settings.gpencil_vertex_paint.brush
if brush is not None:
col.prop(brush, "use_custom_icon", toggle=True, icon='FILE_IMAGE', text="")
if(brush.use_custom_icon):
layout.row().prop(brush, "icon_filepath", text="")
class VIEW3D_PT_tools_grease_pencil_vertex_paint_settings(Panel, View3DPanel, GreasePencilVertexPanel):
bl_label = "Brush Settings"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
tool_settings = context.scene.tool_settings
settings = tool_settings.gpencil_vertex_paint
brush = settings.brush
if not self.is_popover:
from bl_ui.properties_paint_common import (
brush_basic_gpencil_vertex_settings,
)
brush_basic_gpencil_vertex_settings(layout, context, brush)
class VIEW3D_PT_tools_grease_pencil_brush_vertex_color(View3DPanel, Panel):
bl_context = ".greasepencil_vertex"
bl_label = "Color"
bl_category = "Tool"
@classmethod
def poll(cls, context):
ob = context.object
ts = context.tool_settings
settings = ts.gpencil_vertex_paint
brush = settings.brush
if ob is None or brush is None:
return False
if context.region.type == 'TOOL_HEADER' or brush.gpencil_vertex_tool in {'BLUR', 'AVERAGE', 'SMEAR'}:
return False
return True
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
ts = context.tool_settings
settings = ts.gpencil_vertex_paint
brush = settings.brush
gp_settings = brush.gpencil_settings
col = layout.column()
col.template_color_picker(brush, "color", value_slider=True)
sub_row = col.row(align=True)
sub_row.prop(brush, "color", text="")
sub_row.prop(brush, "secondary_color", text="")
sub_row.operator("gpencil.tint_flip", icon='FILE_REFRESH', text="")
col.prop(gp_settings, "vertex_mode", text="Mode")
class VIEW3D_PT_tools_grease_pencil_brush_vertex_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel):
bl_context = ".greasepencil_vertex"
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ts = context.tool_settings
settings = ts.gpencil_vertex_paint
return (settings and settings.brush and settings.brush.curve)
class VIEW3D_PT_tools_grease_pencil_brush_vertex_palette(View3DPanel, Panel):
bl_context = ".greasepencil_vertex"
bl_label = "Palette"
bl_category = "Tool"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_vertex_color'
@classmethod
def poll(cls, context):
ob = context.object
ts = context.tool_settings
settings = ts.gpencil_vertex_paint
brush = settings.brush
if ob is None or brush is None:
return False
if brush.gpencil_vertex_tool in {'BLUR', 'AVERAGE', 'SMEAR'}:
return False
return True
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
ts = context.tool_settings
settings = ts.gpencil_vertex_paint
col = layout.column()
row = col.row(align=True)
row.template_ID(settings, "palette", new="palette.new")
if settings.palette:
col.template_palette(settings, "palette", color=True)
class VIEW3D_PT_tools_grease_pencil_brush_mixcolor(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Color"
bl_category = "Tool"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.object
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
if ob is None or brush is None:
return False
if context.region.type == 'TOOL_HEADER':
return False
if brush.gpencil_tool == 'TINT':
return True
if brush.gpencil_tool not in {'DRAW', 'FILL'}:
return False
return True
def draw(self, context):
layout = self.layout
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
gp_settings = brush.gpencil_settings
if brush.gpencil_tool != 'TINT':
row = layout.row()
row.prop(settings, "color_mode", expand=True)
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column()
col.enabled = settings.color_mode == 'VERTEXCOLOR' or brush.gpencil_tool == 'TINT'
col.template_color_picker(brush, "color", value_slider=True)
sub_row = col.row(align=True)
sub_row.prop(brush, "color", text="")
sub_row.prop(brush, "secondary_color", text="")
sub_row.operator("gpencil.tint_flip", icon='FILE_REFRESH', text="")
if brush.gpencil_tool in {'DRAW', 'FILL'}:
col.prop(gp_settings, "vertex_mode", text="Mode")
col.prop(gp_settings, "vertex_color_factor", slider=True, text="Mix Factor")
if brush.gpencil_tool == 'TINT':
col.prop(gp_settings, "vertex_mode", text="Mode")
class VIEW3D_PT_tools_grease_pencil_brush_mix_palette(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Palette"
bl_category = "Tool"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_mixcolor'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
ob = context.object
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
if ob is None or brush is None:
return False
if brush.gpencil_tool == 'TINT':
return True
if brush.gpencil_tool not in {'DRAW', 'FILL'}:
return False
return True
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
ts = context.tool_settings
settings = ts.gpencil_paint
brush = settings.brush
col = layout.column()
col.enabled = settings.color_mode == 'VERTEXCOLOR' or brush.gpencil_tool == 'TINT'
row = col.row(align=True)
row.template_ID(settings, "palette", new="palette.new")
if settings.palette:
col.template_palette(settings, "palette", color=True)
class VIEW3D_PT_tools_grease_pencil_sculpt_options(GreasePencilSculptOptionsPanel, Panel, View3DPanel):
bl_context = ".greasepencil_sculpt"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_sculpt_settings'
@@ -1852,6 +2222,11 @@ class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilDisplayPanel,
bl_category = "Tool"
bl_label = "Cursor"
class VIEW3D_PT_tools_grease_pencil_vertex_appearance(GreasePencilDisplayPanel, Panel, View3DPanel):
bl_context = ".greasepencil_vertex"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_vertex_paint_settings'
bl_category = "Tool"
bl_label = "Cursor"
class VIEW3D_PT_gpencil_brush_presets(Panel, PresetPanel):
"""Brush settings"""
@@ -1863,6 +2238,7 @@ class VIEW3D_PT_gpencil_brush_presets(Panel, PresetPanel):
classes = (
VIEW3D_MT_brush_context_menu,
VIEW3D_MT_brush_gpencil_context_menu,
VIEW3D_MT_brush_context_menu_paint_modes,
VIEW3D_PT_tools_object_options,
VIEW3D_PT_tools_object_options_transform,
@@ -1940,7 +2316,19 @@ classes = (
VIEW3D_PT_tools_grease_pencil_weight_paint_select,
VIEW3D_PT_tools_grease_pencil_weight_paint_settings,
VIEW3D_PT_tools_grease_pencil_weight_appearance,
VIEW3D_PT_tools_grease_pencil_vertex_paint_select,
VIEW3D_PT_tools_grease_pencil_vertex_paint_settings,
VIEW3D_PT_tools_grease_pencil_vertex_appearance,
VIEW3D_PT_tools_grease_pencil_interpolate,
VIEW3D_PT_tools_grease_pencil_brush_mixcolor,
VIEW3D_PT_tools_grease_pencil_brush_mix_palette,
VIEW3D_PT_tools_grease_pencil_brush_paint_falloff,
VIEW3D_PT_tools_grease_pencil_brush_sculpt_falloff,
VIEW3D_PT_tools_grease_pencil_brush_weight_falloff,
VIEW3D_PT_tools_grease_pencil_brush_vertex_color,
VIEW3D_PT_tools_grease_pencil_brush_vertex_palette,
VIEW3D_PT_tools_grease_pencil_brush_vertex_falloff,
)
if __name__ == "__main__": # only for live edit.
@@ -27,7 +27,7 @@
* \note Use #STRINGIFY() rather than defining with quotes.
*/
#define BLENDER_VERSION 283
#define BLENDER_SUBVERSION 6
#define BLENDER_SUBVERSION 7
/** Several breakages with 280, e.g. collections vs layers. */
#define BLENDER_MINVERSION 280
#define BLENDER_MINSUBVERSION 0
+11 -2
View File
@@ -46,13 +46,22 @@ void BKE_brush_system_exit(void);
/* datablock functions */
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name);
struct Brush *BKE_brush_add_gpencil(struct Main *bmain,
struct ToolSettings *ts,
const char *name,
eObjectMode mode);
bool BKE_brush_delete(struct Main *bmain, struct Brush *brush);
void BKE_brush_init_gpencil_settings(struct Brush *brush);
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
void BKE_brush_gpencil_presets(struct Main *bmain, struct ToolSettings *ts);
void BKE_brush_gpencil_paint_presets(struct Main *bmain, struct ToolSettings *ts);
void BKE_brush_gpencil_vertex_presets(struct Main *bmain, struct ToolSettings *ts);
void BKE_brush_gpencil_sculpt_presets(struct Main *bmain, struct ToolSettings *ts);
void BKE_brush_gpencil_weight_presets(struct Main *bmain, struct ToolSettings *ts);
void BKE_gpencil_brush_preset_set(struct Main *bmain, struct Brush *brush, const short type);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);
+2 -1
View File
@@ -115,8 +115,9 @@ typedef enum eContextObjectMode {
CTX_MODE_EDIT_GPENCIL,
CTX_MODE_SCULPT_GPENCIL,
CTX_MODE_WEIGHT_GPENCIL,
CTX_MODE_VERTEX_GPENCIL,
} eContextObjectMode;
#define CTX_MODE_NUM (CTX_MODE_WEIGHT_GPENCIL + 1)
#define CTX_MODE_NUM (CTX_MODE_VERTEX_GPENCIL + 1)
/* Context */
+113 -46
View File
@@ -32,19 +32,22 @@ struct BoundBox;
struct Brush;
struct CurveMapping;
struct Depsgraph;
struct GHash;
struct ListBase;
struct Main;
struct Material;
struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
struct bDeformGroup;
struct bGPDframe;
struct bGPDlayer;
struct bGPDlayer_Mask;
struct bGPDspoint;
struct bGPDstroke;
struct bGPdata;
struct MaterialGPencilStyle;
struct MDeformVert;
#define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
@@ -54,18 +57,33 @@ 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) \
((toolsettings->gp_paint->mode == GPPAINT_FLAG_USE_VERTEXCOLOR))
#define GPENCIL_USE_VERTEX_COLOR_STROKE(toolsettings, brush) \
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
(brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
#define GPENCIL_USE_VERTEX_COLOR_FILL(toolsettings, brush) \
((GPENCIL_USE_VERTEX_COLOR(toolsettings) && \
((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
(brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))))
#define GPENCIL_TINT_VERTEX_COLOR_STROKE(brush) \
((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_STROKE) || \
(brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
#define GPENCIL_TINT_VERTEX_COLOR_FILL(brush) \
((brush->gpencil_settings->vertex_mode == GPPAINT_MODE_FILL) || \
(brush->gpencil_settings->vertex_mode == GPPAINT_MODE_BOTH))
/* ------------ Grease-Pencil API ------------------ */
@@ -75,8 +93,9 @@ 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_free_layer_masks(struct bGPDlayer *gpl);
void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
@@ -91,10 +110,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);
@@ -109,6 +129,11 @@ bool BKE_gpencil_material_index_used(struct bGPdata *gpd, int index);
void BKE_gpencil_material_remap(struct bGPdata *gpd,
const unsigned int *remap,
unsigned int remap_len);
bool BKE_gpencil_merge_materials_table_get(struct Object *ob,
const float hue_threshold,
const float sat_threshold,
const float val_threshold,
struct GHash *r_mat_table);
/* statistics functions */
void BKE_gpencil_stats_update(struct bGPdata *gpd);
@@ -124,12 +149,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,
@@ -139,7 +163,7 @@ struct bGPDstroke *BKE_gpencil_add_stroke_existing_style(struct bGPDframe *gpf,
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
#define GPENCIL_STRENGTH_MIN 0.003f
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.
@@ -154,17 +178,25 @@ 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_named_get(struct bGPdata *gpd, const char *name);
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);
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_add(struct bGPDlayer *gpl, const char *name);
void BKE_gpencil_layer_mask_remove(struct bGPDlayer *gpl, struct bGPDlayer_Mask *mask);
void BKE_gpencil_layer_mask_remove_ref(struct bGPdata *gpd, const char *name);
struct bGPDlayer_Mask *BKE_gpencil_layer_mask_named_get(struct bGPDlayer *gpl, const char *name);
void BKE_gpencil_layer_mask_sort(struct bGPdata *gpd, struct bGPDlayer *gpl);
void BKE_gpencil_layer_mask_sort_all(struct bGPdata *gpd);
/* Brush */
struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
@@ -183,9 +215,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);
@@ -206,22 +238,23 @@ 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_boundingbox_calc(struct bGPDstroke *gps);
/* vertex groups */
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps);
void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
/* GPencil geometry evaluation */
void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd);
/* Set active frame by layer. */
void BKE_gpencil_frame_active_set(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_adaptive(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 type);
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);
@@ -237,31 +270,33 @@ 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);
void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
void BKE_gpencil_frame_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
float BKE_gpencil_multiframe_falloff_calc(
struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
@@ -273,9 +308,41 @@ void BKE_gpencil_convert_curve(struct Main *bmain,
const bool use_collections,
const bool only_stroke);
void BKE_gpencil_palette_ensure(struct Main *bmain, struct Scene *scene);
bool BKE_gpencil_from_image(struct SpaceImage *sima,
struct bGPDframe *gpf,
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);
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
@@ -141,20 +141,10 @@ typedef struct GpencilModifierTypeInfo {
/**
* Callback for GP "geometry" modifiers that create extra geometry
* in the frame (e.g. Array)
*
* The gpf parameter contains the GP frame/strokes to operate on. This is
* usually a copy of the original (unmodified and saved to files) stroke data.
* Modifiers should only add any generated strokes to this frame (and not one accessed
* via the gpl parameter).
*
* The modifier_index parameter indicates where the modifier is
* in the modifier stack in relation to other modifiers.
*/
void (*generateStrokes)(struct GpencilModifierData *md,
struct Depsgraph *depsgraph,
struct Object *ob,
struct bGPDlayer *gpl,
struct bGPDframe *gpf);
struct Object *ob);
/**
* Bake-down GP modifier's effects into the GP data-block.
@@ -297,24 +287,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);
@@ -322,6 +294,15 @@ 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);
struct bGPDframe *BKE_gpencil_frame_retime_get(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob,
struct bGPDlayer *gpl);
#ifdef __cplusplus
}
#endif
+16 -1
View File
@@ -34,6 +34,7 @@ struct Brush;
struct CurveMapping;
struct Depsgraph;
struct EnumPropertyItem;
struct GHash;
struct GridPaintMask;
struct ImagePool;
struct MLoop;
@@ -55,6 +56,7 @@ struct SubdivCCG;
struct SubdivCCG;
struct Tex;
struct ToolSettings;
struct tPaletteColorHSV;
struct UnifiedPaintSettings;
struct View3D;
struct ViewLayer;
@@ -82,9 +84,13 @@ typedef enum ePaintMode {
PAINT_MODE_TEXTURE_2D = 4,
PAINT_MODE_SCULPT_UV = 5,
PAINT_MODE_GPENCIL = 6,
/* Grease Pencil Vertex Paint */
PAINT_MODE_VERTEX_GPENCIL = 7,
PAINT_MODE_SCULPT_GPENCIL = 8,
PAINT_MODE_WEIGHT_GPENCIL = 9,
/** Keep last. */
PAINT_MODE_INVALID = 7,
PAINT_MODE_INVALID = 10,
} ePaintMode;
#define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PAINT_MODE_SCULPT_UV)
@@ -143,6 +149,15 @@ bool BKE_palette_is_empty(const struct Palette *palette);
void BKE_palette_color_remove(struct Palette *palette, struct PaletteColor *color);
void BKE_palette_clear(struct Palette *palette);
void BKE_palette_sort_hsv(struct tPaletteColorHSV *color_array, const int totcol);
void BKE_palette_sort_svh(struct tPaletteColorHSV *color_array, const int totcol);
void BKE_palette_sort_vhs(struct tPaletteColorHSV *color_array, const int totcol);
void BKE_palette_sort_luminance(struct tPaletteColorHSV *color_array, const int totcol);
bool BKE_palette_from_hash(struct Main *bmain,
struct GHash *color_table,
const char *name,
const bool linear);
/* paint curves */
struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
struct PaintCurve *BKE_paint_curve_copy(struct Main *bmain, const struct PaintCurve *pc);
File diff suppressed because it is too large Load Diff
+8 -19
View File
@@ -1124,6 +1124,9 @@ enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
else if (object_mode & OB_MODE_WEIGHT_GPENCIL) {
return CTX_MODE_WEIGHT_GPENCIL;
}
else if (object_mode & OB_MODE_VERTEX_GPENCIL) {
return CTX_MODE_VERTEX_GPENCIL;
}
}
}
@@ -1140,25 +1143,11 @@ enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
/* would prefer if we can use the enum version below over this one - Campbell */
/* must be aligned with above enum */
static const char *data_mode_strings[] = {
"mesh_edit",
"curve_edit",
"surface_edit",
"text_edit",
"armature_edit",
"mball_edit",
"lattice_edit",
"posemode",
"sculpt_mode",
"weightpaint",
"vertexpaint",
"imagepaint",
"particlemode",
"objectmode",
"greasepencil_paint",
"greasepencil_edit",
"greasepencil_sculpt",
"greasepencil_weight",
NULL,
"mesh_edit", "curve_edit", "surface_edit", "text_edit",
"armature_edit", "mball_edit", "lattice_edit", "posemode",
"sculpt_mode", "weightpaint", "vertexpaint", "imagepaint",
"particlemode", "objectmode", "greasepencil_paint", "greasepencil_edit",
"greasepencil_sculpt", "greasepencil_weight", "greasepencil_vertex", NULL,
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1,
"Must have a string for each context mode")
File diff suppressed because it is too large Load Diff
@@ -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_adaptive(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;
@@ -454,14 +389,14 @@ int BKE_gpencil_time_modifier(
}
/* *************************************************** */
void BKE_gpencil_eval_geometry(Depsgraph *depsgraph, bGPdata *gpd)
void BKE_gpencil_frame_active_set(Depsgraph *depsgraph, bGPdata *gpd)
{
DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
int ctime = (int)DEG_get_ctime(depsgraph);
/* update active frame */
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
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 type)
{
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,6 +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->vert_color, pt->vert_color);
if (gps->dvert != NULL) {
dvert = &temp_dverts[i];
@@ -749,6 +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->vert_color, pt->vert_color, next->vert_color, 0.5f);
if (gps->dvert != NULL) {
dvert = &temp_dverts[i];
@@ -775,8 +710,8 @@ void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
MEM_SAFE_FREE(temp_points);
MEM_SAFE_FREE(temp_dverts);
/* move points to smooth stroke (not simple flag )*/
if ((flag & GP_SUBDIV_SIMPLE) == 0) {
/* move points to smooth stroke (not simple type )*/
if (type != GP_SUBDIV_SIMPLE) {
/* duplicate points in a temp area with the new subdivide data */
temp_points = MEM_dupallocN(gps->points);
@@ -793,145 +728,186 @@ 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;
}
/* Get the current frame retimed with time modifiers. */
bGPDframe *BKE_gpencil_frame_retime_get(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
bGPDlayer *gpl)
{
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);
BLI_addtail(&gpf_eval->strokes, gps_dst);
return gpf;
}
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;
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);
}
static bGPdata *gpencil_copy_for_eval(bGPdata *gpd)
{
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;
/* 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;
}
}
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;
}
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;
}
/* 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)
{
/* use original data to set reference pointers to original data */
Object *ob_orig = DEG_get_original_object(ob);
bGPdata *gpd = (bGPdata *)ob_orig->data;
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 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);
/* 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);
}
}
/* 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__);
}
else {
ob->runtime.gpencil_evaluated_frames = MEM_recallocN(ob->runtime.gpencil_evaluated_frames,
sizeof(struct bGPDframe) *
ob->runtime.gpencil_tot_layers);
const bool do_modifiers = (bool)((!is_multiedit) && (ob->greasepencil_modifiers.first != NULL) &&
(!GPENCIL_SIMPLIFY_MODIF(scene)));
if (!do_modifiers) {
return;
}
/* Init general modifiers data. */
if (ob->greasepencil_modifiers.first) {
BKE_gpencil_lattice_init(ob);
}
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) {
/* 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);
const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
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;
}
/* Apply geometry modifiers (add new geometry). */
if (mti && mti->generateStrokes) {
mti->generateStrokes(md, depsgraph, ob);
}
/* Apply deform modifiers and Time remap (only change geometry). */
if ((time_remap) || (mti && mti->deformStroke)) {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
if (gpf == NULL) {
continue;
}
if (mti->deformStroke) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
mti->deformStroke(md, depsgraph, ob, gpl, gpf, gps);
}
}
}
}
}
bGPDframe *gpf = BKE_gpencil_layer_getframe(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);
/* Skip all if some disable flag is enabled. */
if ((ob->greasepencil_modifiers.first == NULL) || (is_multiedit) || (simplify_modif)) {
idx++;
continue;
}
/* Apply geometry modifiers (create new geometry). */
if (BKE_gpencil_has_geometry_modifiers(ob)) {
BKE_gpencil_geometry_modifiers(depsgraph, ob, gpl, gpf_eval, is_render);
}
/* 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);
}
idx++;
}
/* Clear any lattice data. */
if (ob->greasepencil_modifiers.first) {
BKE_gpencil_lattice_clear(ob);
}
BKE_gpencil_lattice_clear(ob);
}
@@ -738,6 +738,15 @@ static void library_foreach_ID_link(Main *bmain,
if (toolsett->gp_paint) {
library_foreach_paint(&data, &toolsett->gp_paint->paint);
}
if (toolsett->gp_vertexpaint) {
library_foreach_paint(&data, &toolsett->gp_vertexpaint->paint);
}
if (toolsett->gp_sculptpaint) {
library_foreach_paint(&data, &toolsett->gp_sculptpaint->paint);
}
if (toolsett->gp_weightpaint) {
library_foreach_paint(&data, &toolsett->gp_weightpaint->paint);
}
CALLBACK_INVOKE(toolsett->gp_sculpt.guide.reference_object, IDWALK_CB_NOP);
}
+1 -4
View File
@@ -168,15 +168,12 @@ 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);
ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
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;
}
}
+12 -3
View File
@@ -729,8 +729,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 */
DRW_gpencil_freecache(ob);
/* Clear grease pencil data. */
if (ob->runtime.gpd_eval != NULL) {
BKE_gpencil_eval_delete(ob->runtime.gpd_eval);
ob->runtime.gpd_eval = NULL;
}
}
void BKE_object_free_caches(Object *object)
@@ -803,6 +806,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;
}
@@ -1034,6 +1040,10 @@ static void object_init(Object *ob, const short ob_type)
ob->trackflag = OB_NEGZ;
ob->upflag = OB_POSY;
}
if (ob->type == OB_GPENCIL) {
ob->dtx |= OB_USE_GPENCIL_LIGHTS;
}
}
void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
@@ -3963,7 +3973,6 @@ void BKE_object_runtime_reset_on_copy(Object *object, const int UNUSED(flag))
runtime->data_eval = NULL;
runtime->mesh_deform_eval = NULL;
runtime->curve_cache = NULL;
runtime->gpencil_cache = NULL;
}
/*
@@ -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 */
+270
View File
@@ -215,6 +215,15 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, ePaintMode mode)
case PAINT_MODE_GPENCIL:
paint_ptr = (Paint **)&ts->gp_paint;
break;
case PAINT_MODE_VERTEX_GPENCIL:
paint_ptr = (Paint **)&ts->gp_vertexpaint;
break;
case PAINT_MODE_SCULPT_GPENCIL:
paint_ptr = (Paint **)&ts->gp_sculptpaint;
break;
case PAINT_MODE_WEIGHT_GPENCIL:
paint_ptr = (Paint **)&ts->gp_weightpaint;
break;
case PAINT_MODE_INVALID:
break;
}
@@ -244,6 +253,12 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return &ts->uvsculpt->paint;
case PAINT_MODE_GPENCIL:
return &ts->gp_paint->paint;
case PAINT_MODE_VERTEX_GPENCIL:
return &ts->gp_vertexpaint->paint;
case PAINT_MODE_SCULPT_GPENCIL:
return &ts->gp_sculptpaint->paint;
case PAINT_MODE_WEIGHT_GPENCIL:
return &ts->gp_weightpaint->paint;
case PAINT_MODE_INVALID:
return NULL;
default:
@@ -270,6 +285,12 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode)
return rna_enum_brush_uv_sculpt_tool_items;
case PAINT_MODE_GPENCIL:
return rna_enum_brush_gpencil_types_items;
case PAINT_MODE_VERTEX_GPENCIL:
return rna_enum_brush_gpencil_vertex_types_items;
case PAINT_MODE_SCULPT_GPENCIL:
return rna_enum_brush_gpencil_sculpt_types_items;
case PAINT_MODE_WEIGHT_GPENCIL:
return rna_enum_brush_gpencil_weight_types_items;
case PAINT_MODE_INVALID:
break;
}
@@ -292,6 +313,12 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode)
return "uv_sculpt_tool";
case PAINT_MODE_GPENCIL:
return "gpencil_tool";
case PAINT_MODE_VERTEX_GPENCIL:
return "gpencil_vertex_tool";
case PAINT_MODE_SCULPT_GPENCIL:
return "gpencil_sculpt_tool";
case PAINT_MODE_WEIGHT_GPENCIL:
return "gpencil_weight_tool";
default:
/* invalid paint mode */
return NULL;
@@ -315,6 +342,12 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
return &ts->imapaint.paint;
case OB_MODE_PAINT_GPENCIL:
return &ts->gp_paint->paint;
case OB_MODE_VERTEX_GPENCIL:
return &ts->gp_vertexpaint->paint;
case OB_MODE_SCULPT_GPENCIL:
return &ts->gp_sculptpaint->paint;
case OB_MODE_WEIGHT_GPENCIL:
return &ts->gp_weightpaint->paint;
case OB_MODE_EDIT:
return &ts->uvsculpt->paint;
default:
@@ -429,6 +462,12 @@ ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref)
return PAINT_MODE_GPENCIL;
case CTX_MODE_PAINT_TEXTURE:
return PAINT_MODE_TEXTURE_3D;
case CTX_MODE_VERTEX_GPENCIL:
return PAINT_MODE_VERTEX_GPENCIL;
case CTX_MODE_SCULPT_GPENCIL:
return PAINT_MODE_SCULPT_GPENCIL;
case CTX_MODE_WEIGHT_GPENCIL:
return PAINT_MODE_WEIGHT_GPENCIL;
}
}
else if (tref->space_type == SPACE_IMAGE) {
@@ -485,6 +524,18 @@ void BKE_paint_runtime_init(const ToolSettings *ts, Paint *paint)
paint->runtime.tool_offset = offsetof(Brush, gpencil_tool);
paint->runtime.ob_mode = OB_MODE_PAINT_GPENCIL;
}
else if (paint == &ts->gp_vertexpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_vertex_tool);
paint->runtime.ob_mode = OB_MODE_VERTEX_GPENCIL;
}
else if (paint == &ts->gp_sculptpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_sculpt_tool);
paint->runtime.ob_mode = OB_MODE_SCULPT_GPENCIL;
}
else if (paint == &ts->gp_weightpaint->paint) {
paint->runtime.tool_offset = offsetof(Brush, gpencil_weight_tool);
paint->runtime.ob_mode = OB_MODE_WEIGHT_GPENCIL;
}
else {
BLI_assert(0);
}
@@ -506,6 +557,12 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode)
return offsetof(Brush, uv_sculpt_tool);
case PAINT_MODE_GPENCIL:
return offsetof(Brush, gpencil_tool);
case PAINT_MODE_VERTEX_GPENCIL:
return offsetof(Brush, gpencil_vertex_tool);
case PAINT_MODE_SCULPT_GPENCIL:
return offsetof(Brush, gpencil_sculpt_tool);
case PAINT_MODE_WEIGHT_GPENCIL:
return offsetof(Brush, gpencil_weight_tool);
case PAINT_MODE_INVALID:
break; /* We don't use these yet. */
}
@@ -639,6 +696,204 @@ bool BKE_palette_is_empty(const struct Palette *palette)
return BLI_listbase_is_empty(&palette->colors);
}
/* helper function to sort using qsort */
static int palettecolor_compare_hsv(const void *a1, const void *a2)
{
const tPaletteColorHSV *ps1 = a1, *ps2 = a2;
/* Hue */
if (ps1->h > ps2->h) {
return 1;
}
else if (ps1->h < ps2->h) {
return -1;
}
/* Saturation. */
if (ps1->s > ps2->s) {
return 1;
}
else if (ps1->s < ps2->s) {
return -1;
}
/* Value. */
if (1.0f - ps1->v > 1.0f - ps2->v) {
return 1;
}
else if (1.0f - ps1->v < 1.0f - ps2->v) {
return -1;
}
return 0;
}
/* helper function to sort using qsort */
static int palettecolor_compare_svh(const void *a1, const void *a2)
{
const tPaletteColorHSV *ps1 = a1, *ps2 = a2;
/* Saturation. */
if (ps1->s > ps2->s) {
return 1;
}
else if (ps1->s < ps2->s) {
return -1;
}
/* Value. */
if (1.0f - ps1->v > 1.0f - ps2->v) {
return 1;
}
else if (1.0f - ps1->v < 1.0f - ps2->v) {
return -1;
}
/* Hue */
if (ps1->h > ps2->h) {
return 1;
}
else if (ps1->h < ps2->h) {
return -1;
}
return 0;
}
static int palettecolor_compare_vhs(const void *a1, const void *a2)
{
const tPaletteColorHSV *ps1 = a1, *ps2 = a2;
/* Value. */
if (1.0f - ps1->v > 1.0f - ps2->v) {
return 1;
}
else if (1.0f - ps1->v < 1.0f - ps2->v) {
return -1;
}
/* Hue */
if (ps1->h > ps2->h) {
return 1;
}
else if (ps1->h < ps2->h) {
return -1;
}
/* Saturation. */
if (ps1->s > ps2->s) {
return 1;
}
else if (ps1->s < ps2->s) {
return -1;
}
return 0;
}
static int palettecolor_compare_luminance(const void *a1, const void *a2)
{
const tPaletteColorHSV *ps1 = a1, *ps2 = a2;
float lumi1 = (ps1->rgb[0] + ps1->rgb[1] + ps1->rgb[2]) / 3.0f;
float lumi2 = (ps2->rgb[0] + ps2->rgb[1] + ps2->rgb[2]) / 3.0f;
if (lumi1 > lumi2) {
return -1;
}
else if (lumi1 < lumi2) {
return 1;
}
return 0;
}
void BKE_palette_sort_hsv(tPaletteColorHSV *color_array, const int totcol)
{
/* Sort by Hue , Saturation and Value. */
qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_hsv);
}
void BKE_palette_sort_svh(tPaletteColorHSV *color_array, const int totcol)
{
/* Sort by Saturation, Value and Hue. */
qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_svh);
}
void BKE_palette_sort_vhs(tPaletteColorHSV *color_array, const int totcol)
{
/* Sort by Saturation, Value and Hue. */
qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_vhs);
}
void BKE_palette_sort_luminance(tPaletteColorHSV *color_array, const int totcol)
{
/* Sort by Luminance (calculated with the average, enough for sorting). */
qsort(color_array, totcol, sizeof(tPaletteColorHSV), palettecolor_compare_luminance);
}
bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, const bool linear)
{
tPaletteColorHSV *color_array = NULL;
tPaletteColorHSV *col_elm = NULL;
bool done = false;
const int totpal = BLI_ghash_len(color_table);
if (totpal > 0) {
color_array = MEM_calloc_arrayN(totpal, sizeof(tPaletteColorHSV), __func__);
/* Put all colors in an array. */
GHashIterator gh_iter;
int t = 0;
GHASH_ITER (gh_iter, color_table) {
const uint col = POINTER_AS_INT(BLI_ghashIterator_getValue(&gh_iter));
float r, g, b;
float h, s, v;
cpack_to_rgb(col, &r, &g, &b);
rgb_to_hsv(r, g, b, &h, &s, &v);
col_elm = &color_array[t];
col_elm->rgb[0] = r;
col_elm->rgb[1] = g;
col_elm->rgb[2] = b;
col_elm->h = h;
col_elm->s = s;
col_elm->v = v;
t++;
}
}
/* Create the Palette. */
if (totpal > 0) {
/* Sort by Hue and saturation. */
BKE_palette_sort_hsv(color_array, totpal);
Palette *palette = BKE_palette_add(bmain, name);
if (palette) {
for (int i = 0; i < totpal; i++) {
col_elm = &color_array[i];
PaletteColor *palcol = BKE_palette_color_add(palette);
if (palcol) {
copy_v3_v3(palcol->rgb, col_elm->rgb);
if (linear) {
linearrgb_to_srgb_v3_v3(palcol->rgb, palcol->rgb);
}
}
}
done = true;
}
}
else {
done = false;
}
if (totpal > 0) {
MEM_SAFE_FREE(color_array);
}
return done;
}
/* are we in vertex paint or weight paint face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
@@ -720,6 +975,9 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
BLI_assert(ELEM(*r_paint,
/* Cast is annoying, but prevent NULL-pointer access. */
(Paint *)ts->gp_paint,
(Paint *)ts->gp_vertexpaint,
(Paint *)ts->gp_sculptpaint,
(Paint *)ts->gp_weightpaint,
(Paint *)ts->sculpt,
(Paint *)ts->vpaint,
(Paint *)ts->wpaint,
@@ -755,6 +1013,18 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
GpPaint *data = MEM_callocN(sizeof(*data), __func__);
paint = &data->paint;
}
else if ((GpVertexPaint **)r_paint == &ts->gp_vertexpaint) {
GpVertexPaint *data = MEM_callocN(sizeof(*data), __func__);
paint = &data->paint;
}
else if ((GpSculptPaint **)r_paint == &ts->gp_sculptpaint) {
GpSculptPaint *data = MEM_callocN(sizeof(*data), __func__);
paint = &data->paint;
}
else if ((GpWeightPaint **)r_paint == &ts->gp_weightpaint) {
GpWeightPaint *data = MEM_callocN(sizeof(*data), __func__);
paint = &data->paint;
}
else if ((UvSculpt **)r_paint == &ts->uvsculpt) {
UvSculpt *data = MEM_callocN(sizeof(*data), __func__);
paint = &data->paint;
@@ -82,6 +82,15 @@ void BKE_paint_toolslots_init_from_main(struct Main *bmain)
if (ts->gp_paint) {
paint_toolslots_init(bmain, &ts->gp_paint->paint);
}
if (ts->gp_vertexpaint) {
paint_toolslots_init(bmain, &ts->gp_vertexpaint->paint);
}
if (ts->gp_sculptpaint) {
paint_toolslots_init(bmain, &ts->gp_sculptpaint->paint);
}
if (ts->gp_weightpaint) {
paint_toolslots_init(bmain, &ts->gp_weightpaint->paint);
}
}
}
+24 -66
View File
@@ -201,72 +201,6 @@ static void scene_init_data(ID *id)
BKE_color_managed_view_settings_init_render(
&scene->r.bake.im_format.view_settings, &scene->r.bake.im_format.display_settings, "Filmic");
/* GP Sculpt brushes */
{
GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
GP_Sculpt_Data *gp_brush;
float curcolor_add[3], curcolor_sub[3];
ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE |
GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_SCULPT_TYPE_STRENGTH];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_SCULPT_TYPE_GRAB];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_SCULPT_TYPE_PUSH];
gp_brush->size = 25;
gp_brush->strength = 0.3f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_SCULPT_TYPE_TWIST];
gp_brush->size = 50;
gp_brush->strength = 0.3f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_SCULPT_TYPE_PINCH];
gp_brush->size = 50;
gp_brush->strength = 0.5f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
gp_brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE];
gp_brush->size = 25;
gp_brush->strength = 0.5f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
/* Curve Profile */
scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
@@ -560,6 +494,18 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag)
ts->gp_paint = MEM_dupallocN(ts->gp_paint);
BKE_paint_copy(&ts->gp_paint->paint, &ts->gp_paint->paint, flag);
}
if (ts->gp_vertexpaint) {
ts->gp_vertexpaint = MEM_dupallocN(ts->gp_vertexpaint);
BKE_paint_copy(&ts->gp_vertexpaint->paint, &ts->gp_vertexpaint->paint, flag);
}
if (ts->gp_sculptpaint) {
ts->gp_sculptpaint = MEM_dupallocN(ts->gp_sculptpaint);
BKE_paint_copy(&ts->gp_sculptpaint->paint, &ts->gp_sculptpaint->paint, flag);
}
if (ts->gp_weightpaint) {
ts->gp_weightpaint = MEM_dupallocN(ts->gp_weightpaint);
BKE_paint_copy(&ts->gp_weightpaint->paint, &ts->gp_weightpaint->paint, flag);
}
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint, flag);
ts->imapaint.paintcursor = NULL;
@@ -602,6 +548,18 @@ void BKE_toolsettings_free(ToolSettings *toolsettings)
BKE_paint_free(&toolsettings->gp_paint->paint);
MEM_freeN(toolsettings->gp_paint);
}
if (toolsettings->gp_vertexpaint) {
BKE_paint_free(&toolsettings->gp_vertexpaint->paint);
MEM_freeN(toolsettings->gp_vertexpaint);
}
if (toolsettings->gp_sculptpaint) {
BKE_paint_free(&toolsettings->gp_sculptpaint->paint);
MEM_freeN(toolsettings->gp_sculptpaint);
}
if (toolsettings->gp_weightpaint) {
BKE_paint_free(&toolsettings->gp_weightpaint->paint);
MEM_freeN(toolsettings->gp_weightpaint);
}
BKE_paint_free(&toolsettings->imapaint.paint);
/* free Grease Pencil interpolation curve */
+10 -1
View File
@@ -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]);
+137 -82
View File
@@ -3609,23 +3609,23 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
}
#if 0
if (ntree->previews) {
bNodeInstanceHash *new_previews = BKE_node_instance_hash_new("node previews");
bNodeInstanceHashIterator iter;
if (ntree->previews) {
bNodeInstanceHash* new_previews = BKE_node_instance_hash_new("node previews");
bNodeInstanceHashIterator iter;
NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
bNodePreview *preview = BKE_node_instance_hash_iterator_get_value(&iter);
if (preview) {
bNodePreview *new_preview = newimaadr(fd, preview);
if (new_preview) {
bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
BKE_node_instance_hash_insert(new_previews, key, new_preview);
}
}
}
BKE_node_instance_hash_free(ntree->previews, NULL);
ntree->previews = new_previews;
}
NODE_INSTANCE_HASH_ITER(iter, ntree->previews) {
bNodePreview* preview = BKE_node_instance_hash_iterator_get_value(&iter);
if (preview) {
bNodePreview* new_preview = newimaadr(fd, preview);
if (new_preview) {
bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
BKE_node_instance_hash_insert(new_previews, key, new_preview);
}
}
}
BKE_node_instance_hash_free(ntree->previews, NULL);
ntree->previews = new_previews;
}
#else
/* XXX TODO */
ntree->previews = NULL;
@@ -4084,10 +4084,10 @@ static void direct_link_text(FileData *fd, Text *text)
text->compiled = NULL;
#if 0
if (text->flags & TXT_ISEXT) {
BKE_text_reload(text);
}
/* else { */
if (text->flags & TXT_ISEXT) {
BKE_text_reload(text);
}
/* else { */
#endif
link_list(fd, &text->lines);
@@ -5071,7 +5071,7 @@ static void lib_link_object(FileData *fd, Main *bmain, Object *ob)
* some leaked memory rather then crashing immediately
* while bad this _is_ an exceptional case - campbell */
#if 0
BKE_pose_free(ob->pose);
BKE_pose_free(ob->pose);
#else
MEM_freeN(ob->pose);
#endif
@@ -5540,15 +5540,15 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob)
else if (md->type == eModifierType_Collision) {
CollisionModifierData *collmd = (CollisionModifierData *)md;
#if 0
// TODO: CollisionModifier should use pointcache
// + have proper reset events before enabling this
collmd->x = newdataadr(fd, collmd->x);
collmd->xnew = newdataadr(fd, collmd->xnew);
collmd->mfaces = newdataadr(fd, collmd->mfaces);
// TODO: CollisionModifier should use pointcache
// + have proper reset events before enabling this
collmd->x = newdataadr(fd, collmd->x);
collmd->xnew = newdataadr(fd, collmd->xnew);
collmd->mfaces = newdataadr(fd, collmd->mfaces);
collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
collmd->current_x = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_x");
collmd->current_xnew = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_xnew");
collmd->current_v = MEM_calloc_arrayN(collmd->numverts, sizeof(MVert), "current_v");
#endif
collmd->x = NULL;
@@ -5752,16 +5752,66 @@ static void direct_link_gpencil_modifiers(FileData *fd, ListBase *lb)
direct_link_curvemapping(fd, hmd->curfalloff);
}
}
else if (md->type == eGpencilModifierType_Noise) {
NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
if (gpmd->curve_intensity) {
direct_link_curvemapping(fd, gpmd->curve_intensity);
/* initialize the curve. Maybe this could be moved to modififer logic */
BKE_curvemapping_initialize(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Thick) {
ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md;
gpmd->curve_thickness = newdataadr(fd, gpmd->curve_thickness);
if (gpmd->curve_thickness) {
direct_link_curvemapping(fd, gpmd->curve_thickness);
/* initialize the curve. Maybe this could be moved to modififer logic */
BKE_curvemapping_initialize(gpmd->curve_thickness);
}
}
else if (md->type == eGpencilModifierType_Vertexcolor) {
VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md;
gpmd->colorband = newdataadr(fd, gpmd->colorband);
gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
if (gpmd->curve_intensity) {
direct_link_curvemapping(fd, gpmd->curve_intensity);
BKE_curvemapping_initialize(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Smooth) {
SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
if (gpmd->curve_intensity) {
direct_link_curvemapping(fd, gpmd->curve_intensity);
BKE_curvemapping_initialize(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Color) {
ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
if (gpmd->curve_intensity) {
direct_link_curvemapping(fd, gpmd->curve_intensity);
BKE_curvemapping_initialize(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Tint) {
TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
if (gpmd->curve_intensity) {
direct_link_curvemapping(fd, gpmd->curve_intensity);
BKE_curvemapping_initialize(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Opacity) {
OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
gpmd->curve_intensity = newdataadr(fd, gpmd->curve_intensity);
if (gpmd->curve_intensity) {
direct_link_curvemapping(fd, gpmd->curve_intensity);
BKE_curvemapping_initialize(gpmd->curve_intensity);
}
}
}
}
@@ -6333,6 +6383,15 @@ static void lib_link_scene(FileData *fd, Main *UNUSED(bmain), Scene *sce)
if (sce->toolsettings->gp_paint) {
link_paint(fd, sce, &sce->toolsettings->gp_paint->paint);
}
if (sce->toolsettings->gp_vertexpaint) {
link_paint(fd, sce, &sce->toolsettings->gp_vertexpaint->paint);
}
if (sce->toolsettings->gp_sculptpaint) {
link_paint(fd, sce, &sce->toolsettings->gp_sculptpaint->paint);
}
if (sce->toolsettings->gp_weightpaint) {
link_paint(fd, sce, &sce->toolsettings->gp_weightpaint->paint);
}
if (sce->toolsettings->sculpt) {
sce->toolsettings->sculpt->gravity_object = newlibadr(
@@ -6615,6 +6674,9 @@ static void direct_link_scene(FileData *fd, Scene *sce)
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->wpaint);
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->uvsculpt);
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_paint);
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_vertexpaint);
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_sculptpaint);
direct_link_paint_helper(fd, sce, (Paint **)&sce->toolsettings->gp_weightpaint);
direct_link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
@@ -6895,7 +6957,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);
}
@@ -6909,9 +6971,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! */
@@ -6929,6 +6988,7 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gpd->flag &= ~GP_DATA_STROKE_EDITMODE;
gpd->flag &= ~GP_DATA_STROKE_SCULPTMODE;
gpd->flag &= ~GP_DATA_STROKE_WEIGHTMODE;
gpd->flag &= ~GP_DATA_STROKE_VERTEXMODE;
}
/* init stroke buffer */
@@ -6952,7 +7012,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);
@@ -6960,24 +7020,24 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd)
gpl->runtime.icon_id = 0;
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
/* Relink masks. */
link_list(fd, &gpl->mask_layers);
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;
}
}
}
@@ -7198,10 +7258,10 @@ static void direct_link_area(FileData *fd, ScrArea *area)
* so sacrifice a few old files for now to avoid crashes with new files!
* committed: r28002 */
#if 0
sima->gpd = newdataadr(fd, sima->gpd);
if (sima->gpd) {
direct_link_gpencil(fd, sima->gpd);
}
sima->gpd = newdataadr(fd, sima->gpd);
if (sima->gpd) {
direct_link_gpencil(fd, sima->gpd);
}
#endif
}
else if (sl->spacetype == SPACE_NODE) {
@@ -7232,10 +7292,10 @@ static void direct_link_area(FileData *fd, ScrArea *area)
* simple return NULL here (sergey)
*/
#if 0
if (sseq->gpd) {
sseq->gpd = newdataadr(fd, sseq->gpd);
direct_link_gpencil(fd, sseq->gpd);
}
if (sseq->gpd) {
sseq->gpd = newdataadr(fd, sseq->gpd);
direct_link_gpencil(fd, sseq->gpd);
}
#endif
sseq->scopes.reference_ibuf = NULL;
sseq->scopes.zebra_ibuf = NULL;
@@ -7906,11 +7966,11 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
sima->iuser.scene = NULL;
#if 0
/* Those are allocated and freed by space code, no need to handle them here. */
MEM_SAFE_FREE(sima->scopes.waveform_1);
MEM_SAFE_FREE(sima->scopes.waveform_2);
MEM_SAFE_FREE(sima->scopes.waveform_3);
MEM_SAFE_FREE(sima->scopes.vecscope);
/* Those are allocated and freed by space code, no need to handle them here. */
MEM_SAFE_FREE(sima->scopes.waveform_1);
MEM_SAFE_FREE(sima->scopes.waveform_2);
MEM_SAFE_FREE(sima->scopes.waveform_3);
MEM_SAFE_FREE(sima->scopes.vecscope);
#endif
sima->scopes.ok = 0;
@@ -8281,8 +8341,8 @@ static void direct_link_speaker(FileData *fd, Speaker *spk)
direct_link_animdata(fd, spk->adt);
#if 0
spk->sound = newdataadr(fd, spk->sound);
direct_link_sound(fd, spk->sound);
spk->sound = newdataadr(fd, spk->sound);
direct_link_sound(fd, spk->sound);
#endif
}
@@ -8905,12 +8965,12 @@ static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, const char *a
while (bhead && bhead->code == DATA) {
void *data;
#if 0
/* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
short *sp = fd->filesdna->structs[bhead->SDNAnr];
char *tmp = malloc(100);
allocname = fd->filesdna->types[sp[0]];
strcpy(tmp, allocname);
data = read_struct(fd, bhead, tmp);
/* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */
short* sp = fd->filesdna->structs[bhead->SDNAnr];
char* tmp = malloc(100);
allocname = fd->filesdna->types[sp[0]];
strcpy(tmp, allocname);
data = read_struct(fd, bhead, tmp);
#else
data = read_struct(fd, bhead, allocname);
#endif
@@ -9309,11 +9369,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;
@@ -9722,7 +9777,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath)
bhead = read_libblock(fd, libmain, bhead, 0, true, NULL);
}
break;
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
/* in 2.50+ files, the file identifier for screens is patched, forward compatibility */
case ID_SCRN:
bhead->code = ID_SCR;
/* pass on to default */
@@ -9877,7 +9932,7 @@ static BHead *find_previous_lib(FileData *fd, BHead *bhead)
static BHead *find_bhead(FileData *fd, void *old)
{
#if 0
BHead *bhead;
BHead* bhead;
#endif
struct BHeadSort *bhs, bhs_s;
@@ -9897,11 +9952,11 @@ static BHead *find_bhead(FileData *fd, void *old)
}
#if 0
for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
if (bhead->old == old) {
return bhead;
}
}
for (bhead = blo_bhead_first(fd); bhead; bhead = blo_bhead_next(fd, bhead)) {
if (bhead->old == old) {
return bhead;
}
}
#endif
return NULL;
@@ -10032,9 +10087,9 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
/* Commented because this can print way too much. */
#if 0
if (G.debug & G_DEBUG) {
printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
}
if (G.debug & G_DEBUG) {
printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
}
#endif
}
@@ -10870,7 +10925,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);
}
@@ -11813,9 +11868,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
/* Does this library have any more linked data-blocks we need to read? */
if (has_linked_ids_to_read(mainptr)) {
#if 0
printf("Reading linked data-blocks from %s (%s)\n",
mainptr->curlib->id.name,
mainptr->curlib->name);
printf("Reading linked data-blocks from %s (%s)\n",
mainptr->curlib->id.name,
mainptr->curlib->name);
#endif
/* Open file if it has not been done yet. */
@@ -1116,80 +1116,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 276, 4)) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
if (ts->gp_sculpt.brush[0].size == 0) {
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
GP_Sculpt_Data *brush;
brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
brush->size = 25;
brush->strength = 0.3f;
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_SMOOTH_PRESSURE;
brush = &gset->brush[GP_SCULPT_TYPE_THICKNESS];
brush->size = 25;
brush->strength = 0.5f;
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
brush = &gset->brush[GP_SCULPT_TYPE_GRAB];
brush->size = 50;
brush->strength = 0.3f;
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
brush = &gset->brush[GP_SCULPT_TYPE_PUSH];
brush->size = 25;
brush->strength = 0.3f;
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
brush = &gset->brush[GP_SCULPT_TYPE_TWIST];
brush->size = 50;
brush->strength = 0.3f; // XXX?
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
brush = &gset->brush[GP_SCULPT_TYPE_PINCH];
brush->size = 50;
brush->strength = 0.5f; // XXX?
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
brush = &gset->brush[GP_SCULPT_TYPE_RANDOMIZE];
brush->size = 25;
brush->strength = 0.5f;
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
brush = &gset->brush[GP_SCULPT_TYPE_CLONE];
brush->size = 50;
brush->strength = 1.0f;
}
if (!DNA_struct_elem_find(fd->filesdna, "ToolSettings", "char", "gpencil_v3d_align")) {
#if 0 /* XXX: Cannot do this, as we get random crashes... */
if (scene->gpd) {
bGPdata *gpd = scene->gpd;
/* Copy over the settings stored in the GP data-block linked to the scene,
* for minimal disruption. */
ts->gpencil_v3d_align = 0;
if (gpd->flag & GP_DATA_VIEWALIGN) {
ts->gpencil_v3d_align |= GP_PROJECT_VIEWSPACE;
}
if (gpd->flag & GP_DATA_DEPTH_VIEW) {
ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_VIEW;
}
if (gpd->flag & GP_DATA_DEPTH_STROKE) {
ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_STROKE;
}
if (gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS) {
ts->gpencil_v3d_align |= GP_PROJECT_DEPTH_STROKE_ENDPOINTS;
}
}
else {
/* Default to cursor for all standard 3D views */
ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
}
#endif
ts->gpencil_v3d_align = GP_PROJECT_VIEWSPACE;
ts->gpencil_v2d_align = GP_PROJECT_VIEWSPACE;
ts->gpencil_seq_align = GP_PROJECT_VIEWSPACE;
@@ -1203,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;
}
@@ -1424,22 +1351,6 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 277, 3)) {
/* ------- init of grease pencil initialization --------------- */
if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "bGPDpalettecolor", "*palcolor")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
/* initialize use position for sculpt brushes */
ts->gp_sculpt.flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
/* new strength sculpt brush */
if (ts->gp_sculpt.brush[0].size >= 11) {
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
GP_Sculpt_Data *brush;
brush = &gset->brush[GP_SCULPT_TYPE_STRENGTH];
brush->size = 25;
brush->strength = 0.5f;
brush->flag = GP_SCULPT_FLAG_USE_FALLOFF;
}
}
/* Convert Grease Pencil to new palettes/brushes
* Loop all strokes and create the palette and all colors
*/
@@ -1447,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) {
@@ -1475,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;
+359 -88
View File
@@ -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"
@@ -63,6 +64,7 @@
#include "DNA_world_types.h"
#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_cloth.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -71,6 +73,8 @@
#include "BKE_fcurve.h"
#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_lib_id.h"
@@ -573,7 +577,7 @@ 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) {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* unlock/unhide layer */
gpl->flag &= ~GP_LAYER_LOCKED;
gpl->flag &= ~GP_LAYER_HIDE;
@@ -582,8 +586,8 @@ static void do_versions_fix_annotations(bGPdata *gpd)
/* 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);
@@ -1057,6 +1061,48 @@ static void do_version_curvemapping_walker(Main *bmain, void (*callback)(CurveMa
callback(gpmd->curfalloff);
}
}
else if (md->type == eGpencilModifierType_Noise) {
NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
if (gpmd->curve_intensity) {
callback(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Vertexcolor) {
VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md;
if (gpmd->curve_intensity) {
callback(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Smooth) {
SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
if (gpmd->curve_intensity) {
callback(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Color) {
ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
if (gpmd->curve_intensity) {
callback(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Opacity) {
OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
if (gpmd->curve_intensity) {
callback(gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Tint) {
TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
if (gpmd->curve_intensity) {
callback(gpmd->curve_intensity);
}
}
}
}
@@ -1554,7 +1600,7 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (gpd == NULL) {
continue;
}
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (STREQ(gpl->info, "RulerData3D")) {
gpl->flag |= GP_LAYER_IS_RULER;
break;
@@ -1588,6 +1634,34 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
}
}
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. */
if (brush != NULL) {
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.
*
@@ -1774,36 +1848,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
#endif
{
/* Grease pencil sculpt and paint cursors */
if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "weighttype")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
/* sculpt brushes */
GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
if (gset) {
gset->weighttype = GP_SCULPT_TYPE_WEIGHT;
}
}
}
{
float curcolor_add[3], curcolor_sub[3];
ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
GP_Sculpt_Data *gp_brush;
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
ToolSettings *ts = scene->toolsettings;
/* sculpt brushes */
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
gp_brush = &gset->brush[i];
gp_brush->flag |= GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
}
}
/* Init grease pencil edit line color */
if (!DNA_struct_elem_find(fd->filesdna, "bGPdata", "float", "line_color[4]")) {
for (bGPdata *gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
@@ -1866,8 +1910,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 3)) {
/* init grease pencil grids and paper */
if (!DNA_struct_elem_find(
fd->filesdna, "gp_paper_opacity", "float", "gpencil_paper_color[3]")) {
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) {
@@ -2621,7 +2664,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
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) {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
gpl->line_change = gpl->thickness;
if ((gpl->thickness < 1) || (gpl->thickness > 10)) {
gpl->thickness = 3;
@@ -2953,34 +2996,13 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* 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;
mat->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
mat->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
}
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 33)) {
/* Grease pencil reset sculpt brushes after struct rename */
if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "int", "weighttype")) {
float curcolor_add[3], curcolor_sub[3];
ARRAY_SET_ITEMS(curcolor_add, 1.0f, 0.6f, 0.6f);
ARRAY_SET_ITEMS(curcolor_sub, 0.6f, 0.6f, 1.0f);
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
/* sculpt brushes */
GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
if (gset) {
for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
GP_Sculpt_Data *gp_brush = &gset->brush[i];
gp_brush->size = 30;
gp_brush->strength = 0.5f;
gp_brush->flag = GP_SCULPT_FLAG_USE_FALLOFF | GP_SCULPT_FLAG_ENABLE_CURSOR;
copy_v3_v3(gp_brush->curcolor_add, curcolor_add);
copy_v3_v3(gp_brush->curcolor_sub, curcolor_sub);
}
}
}
}
if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "overscan")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
@@ -3214,7 +3236,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* 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) {
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);
}
@@ -3420,20 +3442,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
/* Grease pencil target weight */
if (!DNA_struct_elem_find(fd->filesdna, "GP_Sculpt_Settings", "float", "weight")) {
for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
/* sculpt brushes */
GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
if (gset) {
for (int i = 0; i < GP_SCULPT_TYPE_MAX; i++) {
GP_Sculpt_Data *gp_brush = &gset->brush[i];
gp_brush->weight = 1.0f;
}
}
}
}
/* 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) {
@@ -3653,7 +3661,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (gpd->flag & GP_DATA_ANNOTATIONS) {
continue;
}
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* default channel color */
ARRAY_SET_ITEMS(gpl->color, 0.2f, 0.2f, 0.2f);
}
@@ -3744,26 +3752,24 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
/* init grease pencil brush gradients */
if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "gradient_f")) {
if (!DNA_struct_elem_find(fd->filesdna, "BrushGpencilSettings", "float", "hardeness")) {
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;
gp->hardeness = 1.0f;
copy_v2_fl(gp->aspect_ratio, 1.0f);
}
}
}
/* init grease pencil stroke gradients */
if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "gradient_f")) {
if (!DNA_struct_elem_find(fd->filesdna, "bGPDstroke", "float", "hardeness")) {
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;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
gps->hardeness = 1.0f;
copy_v2_fl(gps->aspect_ratio, 1.0f);
}
}
}
@@ -4217,7 +4223,6 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
/* Fix wrong 3D viewport copying causing corrupt pointers (T69974). */
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) {
@@ -4507,6 +4512,272 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
if (!MAIN_VERSION_ATLEAST(bmain, 283, 7)) {
/* Init default Grease Pencil Vertex paint mix factor for Viewport. */
if (!DNA_struct_elem_find(
fd->filesdna, "View3DOverlay", "float", "gpencil_vertex_paint_opacity")) {
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
v3d->overlay.gpencil_vertex_paint_opacity = 1.0f;
}
}
}
}
}
/* Update Grease Pencil after drawing engine and code refactor.
* It uses the seed variable of Array modifier to avoid double patching for
* files created with a development version. */
if (!DNA_struct_elem_find(fd->filesdna, "ArrayGpencilModifierData", "int", "seed")) {
/* Init new Grease Pencil Paint tools. */
{
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
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);
}
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);
vfx->glow_color[3] = 1.0f;
srgb_to_linearrgb_v3_v3(vfx->select_color, vfx->select_color);
vfx->blur[1] = vfx->blur[0];
break;
}
default:
break;
}
}
/* Modifiers. */
LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) {
switch ((GpencilModifierType)md->type) {
case eGpencilModifierType_Array: {
ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md;
mmd->seed = 1;
if ((mmd->offset[0] != 0.0f) || (mmd->offset[1] != 0.0f) ||
(mmd->offset[2] != 0.0f)) {
mmd->flag |= GP_ARRAY_USE_OFFSET;
}
if ((mmd->shift[0] != 0.0f) || (mmd->shift[1] != 0.0f) || (mmd->shift[2] != 0.0f)) {
mmd->flag |= GP_ARRAY_USE_OFFSET;
}
if (mmd->object != NULL) {
mmd->flag |= GP_ARRAY_USE_OB_OFFSET;
}
break;
}
case eGpencilModifierType_Noise: {
NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md;
mmd->factor /= 25.0f;
mmd->factor_thickness = mmd->factor;
mmd->factor_strength = mmd->factor;
mmd->factor_uvs = mmd->factor;
mmd->noise_scale = (mmd->flag & GP_NOISE_FULL_STROKE) ? 0.0f : 1.0f;
if (mmd->curve_intensity == NULL) {
mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (mmd->curve_intensity) {
BKE_curvemapping_initialize(mmd->curve_intensity);
}
}
break;
}
case eGpencilModifierType_Tint: {
TintGpencilModifierData *mmd = (TintGpencilModifierData *)md;
srgb_to_linearrgb_v3_v3(mmd->rgb, mmd->rgb);
if (mmd->curve_intensity == NULL) {
mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (mmd->curve_intensity) {
BKE_curvemapping_initialize(mmd->curve_intensity);
}
}
break;
}
case eGpencilModifierType_Smooth: {
SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md;
if (mmd->curve_intensity == NULL) {
mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (mmd->curve_intensity) {
BKE_curvemapping_initialize(mmd->curve_intensity);
}
}
break;
}
case eGpencilModifierType_Opacity: {
OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md;
if (mmd->curve_intensity == NULL) {
mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (mmd->curve_intensity) {
BKE_curvemapping_initialize(mmd->curve_intensity);
}
}
break;
}
case eGpencilModifierType_Color: {
ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md;
if (mmd->curve_intensity == NULL) {
mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (mmd->curve_intensity) {
BKE_curvemapping_initialize(mmd->curve_intensity);
}
}
break;
}
case eGpencilModifierType_Thick: {
if (!DNA_struct_elem_find(
fd->filesdna, "ThickGpencilModifierData", "float", "thickness_fac")) {
ThickGpencilModifierData *mmd = (ThickGpencilModifierData *)md;
mmd->thickness_fac = mmd->thickness;
}
break;
}
case eGpencilModifierType_Multiply: {
MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md;
mmd->fading_opacity = 1.0 - mmd->fading_opacity;
break;
}
case eGpencilModifierType_Subdiv: {
const short simple = (1 << 0);
SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md;
if (mmd->flag & simple) {
mmd->flag &= ~simple;
mmd->type = GP_SUBDIV_SIMPLE;
}
break;
}
case eGpencilModifierType_Vertexcolor: {
VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md;
if (mmd->curve_intensity == NULL) {
mmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
if (mmd->curve_intensity) {
BKE_curvemapping_initialize(mmd->curve_intensity);
}
}
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);
/* Z-depth Offset. */
gpd->zdepth_offset = 0.150f;
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
gpl->flag |= GP_LAYER_USE_LIGHTS;
srgb_to_linearrgb_v4(gpl->tintcolor, gpl->tintcolor);
gpl->vertex_paint_opacity = 1.0f;
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.
*
@@ -44,10 +44,12 @@
#include "BKE_appdir.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
@@ -235,6 +237,13 @@ static void blo_update_defaults_screen(bScreen *screen,
/* Enable Sliders. */
saction->flag |= SACTION_SLIDERS;
}
else if (sa->spacetype == SPACE_VIEW3D) {
View3D *v3d = sa->spacedata.first;
/* Set Material Color by default. */
v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
/* Enable Annotations. */
v3d->flag2 |= V3D_SHOW_ANNOTATION;
}
}
}
}
@@ -583,7 +592,8 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
}
}
if (app_template && STREQ(app_template, "2D_Animation")) {
/* New grease pencil brushes and vertex paint setup. */
{
/* Update Grease Pencil brushes. */
Brush *brush;
@@ -617,8 +627,49 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
BKE_id_delete(bmain, brush);
}
/* Rename and fix materials. */
if (app_template && STREQ(app_template, "2D_Animation")) {
Material *ma = NULL;
rename_id_for_versioning(bmain, ID_MA, "Black", "Solid Stroke");
rename_id_for_versioning(bmain, ID_MA, "Red", "Squares Stroke");
rename_id_for_versioning(bmain, ID_MA, "Grey", "Solid Fill");
rename_id_for_versioning(bmain, ID_MA, "Black Dots", "Dots Stroke");
/* Dots Stroke. */
ma = BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2);
if (ma == NULL) {
ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
}
ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
/* Squares Stroke. */
ma = BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2);
if (ma == NULL) {
ma = BKE_gpencil_material_add(bmain, "Squares Stroke");
}
ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE;
/* Change Solid Fill settings. */
ma = BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2);
if (ma != NULL) {
ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
}
}
/* Reset all grease pencil brushes. */
Scene *scene = bmain->scenes.first;
BKE_brush_gpencil_presets(bmain, scene->toolsettings);
BKE_brush_gpencil_paint_presets(bmain, scene->toolsettings);
/* Ensure new Paint modes. */
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);
/* Enable cursor. */
GpPaint *gp_paint = scene->toolsettings->gp_paint;
gp_paint->paint.flags |= PAINT_SHOW_BRUSH;
/* Ensure Palette by default. */
BKE_gpencil_palette_ensure(bmain, scene);
}
}
+58 -3
View File
@@ -1830,6 +1830,13 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase)
write_curvemapping(wd, gpmd->curve_thickness);
}
}
else if (md->type == eGpencilModifierType_Noise) {
NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md;
if (gpmd->curve_intensity) {
write_curvemapping(wd, gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Hook) {
HookGpencilModifierData *gpmd = (HookGpencilModifierData *)md;
@@ -1837,6 +1844,39 @@ static void write_gpencil_modifiers(WriteData *wd, ListBase *modbase)
write_curvemapping(wd, gpmd->curfalloff);
}
}
else if (md->type == eGpencilModifierType_Vertexcolor) {
VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md;
if (gpmd->colorband) {
writestruct(wd, DATA, ColorBand, 1, gpmd->colorband);
}
if (gpmd->curve_intensity) {
write_curvemapping(wd, gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Smooth) {
SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md;
if (gpmd->curve_intensity) {
write_curvemapping(wd, gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Color) {
ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md;
if (gpmd->curve_intensity) {
write_curvemapping(wd, gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Opacity) {
OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md;
if (gpmd->curve_intensity) {
write_curvemapping(wd, gpmd->curve_intensity);
}
}
else if (md->type == eGpencilModifierType_Tint) {
TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md;
if (gpmd->curve_intensity) {
write_curvemapping(wd, gpmd->curve_intensity);
}
}
}
}
@@ -2546,6 +2586,18 @@ static void write_scene(WriteData *wd, Scene *sce)
writestruct(wd, DATA, GpPaint, 1, tos->gp_paint);
write_paint(wd, &tos->gp_paint->paint);
}
if (tos->gp_vertexpaint) {
writestruct(wd, DATA, GpVertexPaint, 1, tos->gp_vertexpaint);
write_paint(wd, &tos->gp_vertexpaint->paint);
}
if (tos->gp_sculptpaint) {
writestruct(wd, DATA, GpSculptPaint, 1, tos->gp_sculptpaint);
write_paint(wd, &tos->gp_sculptpaint->paint);
}
if (tos->gp_weightpaint) {
writestruct(wd, DATA, GpWeightPaint, 1, tos->gp_weightpaint);
write_paint(wd, &tos->gp_weightpaint->paint);
}
/* write grease-pencil custom ipo curve to file */
if (tos->gp_interpolate.custom_ipo) {
write_curvemapping(wd, tos->gp_interpolate.custom_ipo);
@@ -2741,14 +2793,17 @@ 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 mask list. */
writelist(wd, DATA, bGPDlayer_Mask, &gpl->mask_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);
}
}
@@ -1310,7 +1310,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
obdata,
NodeType::GEOMETRY,
OperationCode::GEOMETRY_EVAL,
function_bind(BKE_gpencil_eval_geometry, _1, (bGPdata *)obdata_cow));
function_bind(BKE_gpencil_frame_active_set, _1, (bGPdata *)obdata_cow));
op_node->set_as_entry();
break;
}
@@ -2123,6 +2123,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:
@@ -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_lib_id.h"
#include "BKE_scene.h"
@@ -791,6 +792,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);
+18 -32
View File
@@ -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
@@ -111,12 +112,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
@@ -129,6 +131,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
@@ -277,36 +280,16 @@ 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_layer_blend_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_mask_invert_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)
@@ -340,6 +323,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)
-1
View File
@@ -129,7 +129,6 @@ void DRW_draw_select_id(struct Depsgraph *depsgraph,
/* grease pencil render */
bool DRW_render_check_grease_pencil(struct Depsgraph *depsgraph);
void DRW_render_gpencil(struct RenderEngine *engine, struct Depsgraph *depsgraph);
void DRW_gpencil_freecache(struct Object *ob);
/* This is here because GPUViewport needs it */
struct DRWInstanceDataList *DRW_instance_data_list_create(void);
@@ -0,0 +1,169 @@
/*
* 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;
const float *size = DRW_viewport_size_get();
const float *sizeinv = DRW_viewport_invert_size_get();
float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]};
if (pd->simplify_antialias) {
/* No AA fallback. */
DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
GPUShader *sh = GPENCIL_shader_antialiasing(2);
grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps);
DRW_shgroup_uniform_texture(grp, "blendTex", pd->color_tx);
DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", false);
DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe);
DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
return;
}
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);
}
{
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. */
DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
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_bool_copy(grp, "doAntiAliasing", true);
DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe);
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;
if (!pd->simplify_antialias) {
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(pd->scene_fb);
DRW_draw_pass(psl->smaa_resolve_ps);
}
@@ -33,324 +33,368 @@
#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)
/* -------------------------------------------------------------------- */
/** \name Object
* \{ */
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;
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) || pd->draw_depth_only;
tgp_ob->object_scale = mat4_to_scale(ob->obmat);
/* 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 tgp_ob;
}
#define SORT_IMPL_LINKTYPE GPENCIL_tObject
#define SORT_IMPL_FUNC gpencil_tobject_sort_fn_r
#include "../../blenlib/intern/list_sort_impl.h"
#undef SORT_IMPL_FUNC
#undef SORT_IMPL_LINKTYPE
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;
}
else if (ob_a->camera_z < ob_b->camera_z) {
return -1;
}
else {
return 0;
}
}
void gpencil_object_cache_sort(GPENCIL_PrivateData *pd)
{
/* 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) {
pd->tobjects.last = pd->tobjects.last->next;
}
/* 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;
}
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) {
pd->tobjects_infront.last = pd->tobjects_infront.last->next;
}
}
/* 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;
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Layer
* \{ */
static float gpencil_layer_final_opacity_get(const GPENCIL_PrivateData *pd,
const Object *ob,
const bGPDlayer *gpl)
{
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. */
if (!pd->is_render) {
if (is_obact && is_fade) {
return gpl->opacity * pd->fade_layer_opacity;
}
else if (!is_obact && (pd->fade_gp_object_opacity > -1.0f)) {
return gpl->opacity * pd->fade_gp_object_opacity;
}
}
return gpl->opacity;
}
static void gpencil_layer_final_tint_and_alpha_get(const GPENCIL_PrivateData *pd,
const bGPdata *gpd,
const bGPDlayer *gpl,
const bGPDframe *gpf,
float r_tint[4],
float *r_alpha)
{
const bool use_onion = (gpf != NULL) && (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;
const float *onion_col_custom = (use_onion_custom_col) ?
(use_next_col ? gpd->gcolor_next : gpd->gcolor_prev) :
U.gpencil_new_layer_col;
copy_v4_fl4(r_tint, UNPACK3(onion_col_custom), 1.0f);
*r_alpha = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f;
*r_alpha *= gpd->onion_factor;
*r_alpha = (gpd->onion_factor > 0.0f) ? clamp_f(*r_alpha, 0.1f, 1.0f) :
clamp_f(*r_alpha, 0.01f, 1.0f);
}
else {
copy_v4_v4(r_tint, gpl->tintcolor);
if (GPENCIL_SIMPLIFY_TINT(pd->scene)) {
r_tint[3] = 0.0f;
}
*r_alpha = 1.0f;
}
*r_alpha *= pd->xray_alpha;
}
GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
const Object *ob,
const bGPDlayer *gpl,
const bGPDframe *gpf,
GPENCIL_tObject *tgp_ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_in_front = (ob->dtx & OB_DRAWXRAY);
const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
const bool overide_vertcol = (pd->v3d_color_type != -1);
const bool is_vert_col_mode = (pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) ||
GPENCIL_VERTEX_MODE(gpd) || pd->is_render;
bool is_masked = (gpl->flag & GP_LAYER_USE_MASK) && !BLI_listbase_is_empty(&gpl->mask_layers);
float vert_col_opacity = (overide_vertcol) ? (is_vert_col_mode ? 1.0f : 0.0f) :
gpl->vertex_paint_opacity;
/* 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);
float layer_opacity = gpencil_layer_final_opacity_get(pd, ob, gpl);
float layer_tint[4];
float layer_alpha;
gpencil_layer_final_tint_and_alpha_get(pd, gpd, gpl, gpf, layer_tint, &layer_alpha);
/* Create the new layer descriptor. */
GPENCIL_tLayer *tgp_layer = BLI_memblock_alloc(pd->gp_layer_pool);
BLI_LINKS_APPEND(&tgp_ob->layers, tgp_layer);
tgp_layer->layer_id = BLI_findindex(&gpd->layers, gpl);
tgp_layer->mask_bits = NULL;
tgp_layer->mask_invert_bits = NULL;
tgp_layer->blend_ps = NULL;
/* Masking: Go through mask list and extract valid masks in a bitmap. */
if (is_masked) {
bool valid_mask = false;
/* Warning: only GP_MAX_MASKBITS amount of bits.
* TODO(fclem) Find a better system without any limitation. */
tgp_layer->mask_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
tgp_layer->mask_invert_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
BLI_bitmap_set_all(tgp_layer->mask_bits, false, GP_MAX_MASKBITS);
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
bGPDlayer *gpl_mask = BKE_gpencil_layer_named_get(gpd, mask->name);
if (gpl_mask && (gpl_mask != gpl) && ((gpl_mask->flag & GP_LAYER_HIDE) == 0) &&
((mask->flag & GP_MASK_HIDE) == 0)) {
int index = BLI_findindex(&gpd->layers, gpl_mask);
if (index < GP_MAX_MASKBITS) {
const bool invert = (mask->flag & GP_MASK_INVERT) != 0;
BLI_BITMAP_SET(tgp_layer->mask_bits, index, true);
BLI_BITMAP_SET(tgp_layer->mask_invert_bits, index, invert);
valid_mask = true;
}
}
}
}
return false;
}
/* 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)
{
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;
if (valid_mask) {
pd->use_mask_fb = true;
}
else {
*gp_cache_size += GP_CACHE_BLOCK_SIZE;
p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size);
tgp_layer->mask_bits = NULL;
}
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;
is_masked = valid_mask;
}
cache_elem->scale = mat4_to_scale(ob->obmat);
/* Blending: Force blending for masked layer. */
if (is_masked || (gpl->blend_mode != eGplBlendMode_Regular) || (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;
}
/* save FXs */
cache_elem->pixfactor = cache_elem->gpd->pixfactor;
cache_elem->shader_fx = ob->shader_fx;
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;
}
/* save wire mode (object mode is always primary option) */
if (ob->dt == OB_WIRE) {
cache_elem->shading_type[0] = (int)OB_WIRE;
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", 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_uniform_texture_ref(grp, "maskBuf", (is_masked) ? &pd->mask_tx : &pd->dummy_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);
}
pd->use_layer_fb = true;
}
else {
if (v3d) {
cache_elem->shading_type[0] = (int)v3d->shading.type;
/* Geometry pass */
{
GPUTexture *depth_tex = (is_in_front) ? pd->dummy_tx : pd->scene_depth_tx;
GPUTexture **mask_tex = (is_masked) ? &pd->mask_tx : &pd->dummy_tx;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND_ALPHA_PREMUL;
/* For 2D mode, we render all strokes with uniform depth (increasing with stroke id). */
state |= tgp_ob->is_drawmode3d ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_GREATER;
/* Always write stencil. Only used as optimization for blending. */
state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
tgp_layer->geom_ps = DRW_pass_create("GPencil Layer", state);
struct GPUShader *sh = GPENCIL_shader_geometry_get();
DRWShadingGroup *grp = tgp_layer->base_shgrp = DRW_shgroup_create(sh, tgp_layer->geom_ps);
DRW_shgroup_uniform_texture_persistent(grp, "gpSceneDepthTexture", depth_tex);
DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex);
DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal);
DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", tgp_ob->is_drawmode3d);
DRW_shgroup_uniform_float_copy(grp, "thicknessScale", tgp_ob->object_scale);
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, "thicknessOffset", (float)gpl->line_change);
DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
DRW_shgroup_uniform_float_copy(grp, "vertexColorOpacity", vert_col_opacity);
DRW_shgroup_uniform_vec4_copy(grp, "layerTint", layer_tint);
DRW_shgroup_uniform_float_copy(grp, "layerOpacity", layer_alpha);
DRW_shgroup_stencil_mask(grp, 0xFF);
}
return tgp_layer;
}
GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number)
{
if (number >= 0) {
GPENCIL_tLayer *layer = tgp_ob->layers.first;
while (layer != NULL) {
if (layer->layer_id == number) {
return layer;
}
layer = layer->next;
}
}
/* 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);
}
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);
}
}
cache_elem->zdepth = zdepth;
/* increase slots used in cache */
(*gp_cache_used)++;
return cache_array;
return NULL;
}
/* 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;
}
else {
*grp_size += GPENCIL_GROUPS_BLOCK_SIZE;
p = MEM_recallocN(cache_array, sizeof(struct GpencilBatchGroup) * *grp_size);
}
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);
}
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;
}
/* 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;
}
}
/* 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);
}
ob->runtime.gpencil_tot_layers = 0;
MEM_SAFE_FREE(ob->runtime.gpencil_evaluated_frames);
}
/** \} */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,502 @@
/*
* 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"
/* -------------------------------------------------------------------- */
/** \name Material
* \{ */
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;
}
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];
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Lights
* \{ */
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;
}
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(fclem) Light linking. */
// 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);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name View Layer Data
* \{ */
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_maskbit_pool, NULL);
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_maskbit_pool = BLI_memblock_create(BLI_BITMAP_SIZE(GP_MAX_MASKBITS));
(*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;
}
/** \} */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -23,6 +23,10 @@
#ifndef __GPENCIL_ENGINE_H__
#define __GPENCIL_ENGINE_H__
#include "DNA_gpencil_types.h"
#include "BLI_bitmap.h"
#include "GPU_batch.h"
extern DrawEngineType draw_engine_gpencil_type;
@@ -34,204 +38,201 @@ struct Object;
struct RenderEngine;
struct RenderLayer;
struct bGPDstroke;
struct View3D;
struct GpencilBatchCache;
struct GPUBatch;
struct GPUVertBuf;
struct GPUVertFormat;
#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_MAX_MASKBITS 256
/* *********** 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;
/* 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;
/* 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;
/* 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)
/* 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;
#define GPENCIL_LIGHT_BUFFER_LEN 128
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;
/* 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;
/* shading type */
int shading_type[2];
/* 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
/* GPU data size */
int tot_vertex;
int tot_triangles;
BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16)
BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
/* Save shader groups by layer */
int tot_layers;
tGPencilObjectCache_shgrp *shgrp_array;
/* *********** 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;
} tGPencilObjectCache;
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;
/* BLI_bitmap */
struct BLI_memblock *gp_maskbit_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;
/** First shading group created for this layer. Contains all uniforms. */
DRWShadingGroup *base_shgrp;
/** Layer id of the mask. */
BLI_bitmap *mask_bits;
BLI_bitmap *mask_invert_bits;
/** Index in the layer list. Used as id for masking. */
int layer_id;
} 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;
/* Used for stroke thickness scaling. */
float object_scale;
/* 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;
/* Invert mask buffer content. */
struct DRWPass *mask_invert_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 *mask_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 {
@@ -240,248 +241,175 @@ 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;
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;
struct BLI_memblock *gp_maskbit_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;
/* Revealage is 1 - alpha */
GPUTexture *reveal_tx;
GPUTexture *reveal_layer_tx;
GPUTexture *reveal_object_tx;
/* Mask texture */
GPUTexture *mask_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;
/* If we are in viewport display (used for VFX). */
bool is_viewport;
/* True in selection and auto_depth drawing */
bool draw_depth_only;
/* Is shading set to wireframe. */
bool draw_wireframe;
/* 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;
/* Copy of draw_ctx->scene for convenience. */
struct Scene *scene;
int gp_cache_used; /* total objects in cache */
int gp_cache_size; /* size of the cache */
struct tGPencilObjectCache *gp_object_cache;
/* 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;
/* 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 bGPDstroke *gps,
short thickness,
const float ink[4],
const int follow_mode);
void gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be,
struct bGPDstroke *gps,
short thickness,
const float ink[4]);
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);
/* 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);
/* 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;
/* Mask opacity uniform. */
float mask_opacity;
/* Xray transparency in solid mode. */
float xray_alpha;
/* Mask invert uniform. */
int mask_invert;
} 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);
void gpencil_object_cache_sort(GPENCIL_PrivateData *pd);
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);
GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
const Object *ob,
const bGPDlayer *gpl,
const bGPDframe *gpf,
GPENCIL_tObject *tgp_ob);
GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number);
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);
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);
/* 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_mask_invert_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);
@@ -493,43 +421,17 @@ 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,
const rcti *rect);
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_stats_query_end(); \
} \
} \
((void)0)
#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)))
/* Draw Data. */
void gpencil_light_pool_free(void *storage);
void gpencil_material_pool_free(void *storage);
GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void);
#endif /* __GPENCIL_ENGINE_H__ */
@@ -33,66 +33,22 @@
#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,
const rcti *rect)
{
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 +61,101 @@ 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) {
RE_engine_set_error_message(engine,
"Warning: To render grease pencil, enable Combined and Z passes.");
}
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);
}
}
}
const bool do_region = (scene->r.mode & R_BORDER) != 0;
const bool do_clear_z = !pix_z || do_region;
const bool do_clear_col = !pix_col || do_region;
/* 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, do_region ? NULL : pix_z);
txl->render_color_tx = DRW_texture_create_2d(
size[0], size[1], GPU_RGBA16F, 0, do_region ? NULL : pix_col);
GPU_framebuffer_ensure_config(&fbl->render_fb,
{
GPU_ATTACHMENT_TEXTURE(txl->render_depth_tx),
GPU_ATTACHMENT_TEXTURE(txl->render_color_tx),
});
if (do_clear_z || do_clear_col) {
/* To avoid unpredictable result, clear buffers that have not be initialized. */
GPU_framebuffer_bind(fbl->render_fb);
if (do_clear_col) {
float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->render_fb, clear_col);
}
if (do_clear_z) {
GPU_framebuffer_clear_depth(fbl->render_fb, 1.0f);
}
}
if (do_region) {
int x = rect->xmin;
int y = rect->ymin;
int w = BLI_rcti_size_x(rect);
int h = BLI_rcti_size_y(rect);
if (pix_col) {
GPU_texture_update_sub(txl->render_color_tx, GPU_DATA_FLOAT, pix_col, x, y, 0, w, h, 0);
}
if (pix_z) {
GPU_texture_update_sub(txl->render_depth_tx, GPU_DATA_FLOAT, pix_z, x, y, 0, w, h, 0);
}
}
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 +163,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 +217,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 +228,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, rect);
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);
}
}
@@ -0,0 +1,311 @@
/*
* 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_layer_blend_frag_glsl[];
extern char datatoc_gpencil_mask_invert_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;
/* Merge the final object depth to the depth buffer. */
GPUShader *depth_merge_sh;
/* Invert the content of the mask buffer. */
GPUShader *mask_invert_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_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_mask_invert_get(void)
{
if (!g_shaders.mask_invert_sh) {
g_shaders.mask_invert_sh = DRW_shader_create_fullscreen(datatoc_gpencil_mask_invert_frag_glsl,
NULL);
}
return g_shaders.mask_invert_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 = 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 GLOW\n",
NULL,
},
});
}
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;
}
File diff suppressed because it is too large Load Diff
@@ -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;
}
}
@@ -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;
}
@@ -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;
}
@@ -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);
}
@@ -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;
}
@@ -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);
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
}
@@ -0,0 +1,64 @@
uniform sampler2D edgesTex;
uniform sampler2D areaTex;
uniform sampler2D searchTex;
uniform sampler2D blendTex;
uniform sampler2D colorTex;
uniform sampler2D revealTex;
uniform bool onlyAlpha;
uniform bool doAntiAliasing;
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
/* Reminder: Blending func is fragRevealage * DST + fragColor .*/
layout(location = 0, index = 0) out vec4 outColor;
layout(location = 0, index = 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. */
if (doAntiAliasing) {
outColor = SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex);
outReveal = SMAANeighborhoodBlendingPS(uvs, offset[0], revealTex, blendTex);
}
else {
outColor = texture(colorTex, uvs);
outReveal = texture(revealTex, uvs);
}
/* Revealage, how much light passes through. */
/* Average for alpha channel. */
outReveal.a = clamp(dot(outReveal.rgb, vec3(0.333334)), 0.0, 1.0);
/* Color buf is already premultiplied. Just add it to the color. */
/* Add the alpha. */
outColor.a = 1.0 - outReveal.a;
if (onlyAlpha) {
/* Special case in wireframe xray mode. */
outColor = vec4(0.0);
outReveal.rgb = outReveal.aaa;
}
#endif
}
@@ -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
}
@@ -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);
}
@@ -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);
}
@@ -0,0 +1,593 @@
/* 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 / max(vec4(1e-6), 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;
noperspective IN_OUT float strokeHardeness;
flat IN_OUT vec2 strokeAspect;
flat IN_OUT vec2 strokePt1;
flat IN_OUT vec2 strokePt2;
flat IN_OUT int matFlag;
flat IN_OUT float depth;
#ifdef GPU_FRAGMENT_SHADER
# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
float stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac)
{
/* 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;
uv_end *= aspect;
float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0);
if (hardfac > 0.999) {
return step(1e-8, dist);
}
else {
/* Modulate the falloff profile */
float hardness = 1.0 - hardfac;
dist = pow(dist, mix(0.01, 10.0, hardness));
return smoothstep(0.0, 1.0, dist);
}
}
#endif
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;
/* All of these attribs are quad loaded the same way
* as GL_LINES_ADJACENCY would feed a geometry shader:
* - ma reference the previous adjacency point.
* - ma1 reference the current line first point.
* - ma2 reference the current line second point.
* - ma3 reference the next adjacency point.
* Note that we are rendering quad instances and not using any index buffer (except for fills).
*/
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;
/* hard.x is aspect. */
in vec2 hard1;
in vec2 hard2;
# define aspect1 hard1.x
# define aspect2 hard2.x
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;
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;
strokeHardeness = (use_curr) ? hard1.y : hard2.y;
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);
strokeAspect.x = aspect1;
if (strokeAspect.x > 1.0) {
strokeAspect.y = strokeAspect.x;
strokeAspect.x = 1.0;
}
else {
strokeAspect.x = 1.0 / strokeAspect.x;
strokeAspect.y = 1.0;
}
x /= strokeAspect.x;
y /= strokeAspect.y;
gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * thickness;
strokePt1 = ss1;
strokePt2 = ss1 + x_axis * 0.5;
strokeThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w);
}
else {
bool is_stroke_start = (ma.x == -1.0 && x == -1.0);
bool is_stroke_end = (ma3.x == -1.0 && x == 1.0);
/* 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) || is_stroke_start || is_stroke_end;
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;
strokeAspect = vec2(1.0);
vec2 screen_ofs = miter * y;
/* Reminder: we packed the cap flag into the sign of stength and thickness sign. */
if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) ||
miter_break) {
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 + strokeIndexOffset + 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;
strokeAspect = vec2(1.0);
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
@@ -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;
}
}
@@ -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);
}
@@ -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;
}
@@ -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();
}
@@ -1,19 +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;
/* Dirty fix waiting for new GPencil engine. */
finalColor.rgb = pow(finalColor.rgb, vec3(2.2));
}
@@ -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);
}
}
@@ -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;
}
@@ -0,0 +1,126 @@
uniform sampler2D gpFillTexture;
uniform sampler2D gpStrokeTexture;
uniform sampler2D gpSceneDepthTexture;
uniform sampler2D gpMaskTexture;
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, strokeAspect, strokeThickness, strokeHardeness);
/* 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;
}
/* FIXME(fclem) Grrr. This is bad for performance but it's the easiest way to not get
* depth written where the mask obliterate the layer. */
float mask = texture(gpMaskTexture, uvs).r;
if (mask < 0.001) {
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;
}
}
@@ -0,0 +1,31 @@
uniform sampler2D colorBuf;
uniform sampler2D revealBuf;
uniform sampler2D maskBuf;
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;
float mask = textureLod(maskBuf, uvcoordsvar.xy, 0).r;
mask *= blendOpacity;
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, mask, fragColor, fragRevealage);
}
@@ -0,0 +1,11 @@
in vec4 uvcoordsvar;
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 fragRevealage;
void main()
{
/* Blend mode does the inversion. */
fragRevealage = fragColor = vec4(1.0);
}
@@ -1,9 +0,0 @@
uniform vec3 color;
uniform float opacity;
out vec4 FragColor;
void main()
{
FragColor = vec4(color, 1.0 - opacity);
}
@@ -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);
}
}
@@ -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();
}
@@ -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;
}
@@ -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;
}
@@ -1,110 +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 */
/* keep this disabled while the line glitch bug exists
if (gradient_f < 1.0) {
float d = abs(mTexCoord.y - 0.5) * (1.1 - gradient_f);
float alpha = 1.0 - clamp((fragColor.a - (d * 2.0)), 0.03, 1.0);
fragColor.a = smoothstep(fragColor.a, 0.0, alpha);
}
*/
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);
}
}
@@ -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();
}
@@ -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;
}
@@ -0,0 +1,5 @@
void main()
{
gpencil_vertex();
}
@@ -0,0 +1,354 @@
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 vec4 glowColor;
uniform vec2 offset;
uniform int sampCount;
uniform vec3 threshold;
uniform bool firstPass;
uniform bool glowUnder;
uniform int blendMode;
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);
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;
vec3 rev = texture(revealBuf, 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;
fragRevealage.rgb += (1.0 - rev) * weight;
}
if (weight_accum > 0.0) {
fragColor *= glowColor.rgbb / weight_accum;
fragRevealage = fragRevealage / weight_accum;
}
fragRevealage = 1.0 - fragRevealage;
if (glowUnder) {
if (firstPass) {
/* In first pass we copy the revealage buffer in the alpha channel.
* This let us do the alpha under in second pass. */
vec3 original_revealage = texture(revealBuf, uvcoordsvar.xy).rgb;
fragRevealage.a = clamp(dot(original_revealage.rgb, vec3(0.333334)), 0.0, 1.0);
}
else {
/* Recover original revealage. */
fragRevealage.a = texture(revealBuf, uvcoordsvar.xy).a;
}
}
if (!firstPass) {
fragColor.a = clamp(1.0 - dot(fragRevealage.rgb, vec3(0.333334)), 0.0, 1.0);
fragRevealage.a *= glowColor.a;
blend_mode_output(blendMode, fragColor, fragRevealage.a, fragColor, fragRevealage);
}
}
#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
@@ -1,76 +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;
/* Dirty fix waiting for new GPencil engine. */
FragColor.rgb = pow(FragColor.rgb, vec3(2.2));
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More