New Grease Pencil object for 2D animation

This commit merge the full development done in greasepencil-object branch and include mainly the following features.

- New grease pencil object.
- New drawing engine.
- New grease pencil modes Draw/Sculpt/Edit and Weight Paint.
- New brushes for grease pencil.
- New modifiers for grease pencil.
- New shaders FX.
- New material system (replace old palettes and colors).
- Split of annotations (old grease pencil) and new grease pencil object.
- UI adapted to blender 2.8.

You can get more info here:

https://code.blender.org/2017/12/drawing-2d-animation-in-blender-2-8/
https://code.blender.org/2018/07/grease-pencil-status-update/

This is the result of nearly two years of development and I want thanks firstly the other members of the grease pencil team: Daniel M. Lara, Matias Mendiola and Joshua Leung for their support, ideas and to keep working in the project all the time, without them this project had been impossible.

Also, I want thanks other Blender developers for their help, advices and to be there always to help me, and specially to Clément Foucault, Dalai Felinto, Pablo Vázquez and Campbell Barton.
master
Antonioya 6 years ago
parent 27496cc46b
commit 66da2f537a

@ -598,12 +598,12 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_editor_util
bf_editor_uvedit
bf_editor_curve
bf_editor_gpencil
bf_editor_interface
bf_editor_gizmo_library
bf_editor_mesh
bf_editor_metaball
bf_editor_object
bf_editor_gpencil
bf_editor_lattice
bf_editor_armature
bf_editor_physics
@ -626,12 +626,15 @@ function(SETUP_BLENDER_SORTED_LIBS)
bf_freestyle
bf_ikplugin
bf_modifiers
bf_gpencil_modifiers
bf_alembic
bf_bmesh
bf_gpu
bf_draw
bf_blenloader
bf_blenkernel
bf_shader_fx
bf_gpencil_modifiers
bf_physics
bf_nodes
bf_rna

@ -895,7 +895,10 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
return (context.material or context.object) and CyclesButtonsPanel.poll(context)
if context.active_object and context.active_object.type == 'GPENCIL':
return False
else:
return (context.material or context.object) and CyclesButtonsPanel.poll(context)
def draw(self, context):
layout = self.layout

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -1,8 +1,8 @@
/*
* Generated by 'source/tools/utils/blender_theme_as_c.py'
*
* Do not hand edit this file!
*/
* Generated by 'source/tools/utils/blender_theme_as_c.py'
*
* Do not hand edit this file!
*/
#include "DNA_userdef_types.h"
@ -1040,5 +1040,5 @@ const bTheme U_theme_default = {
.select = RGBA(0x000000ff),
.active = RGBA(0x000000ff),
},
},
},
};

@ -1 +1 @@
Subproject commit c87ee4d46f16d60a2e1db7514c8d5ab42c5d93df
Subproject commit 371960484a38fc64e0a2635170a41a0d8ab2f6bd

@ -1 +1 @@
Subproject commit 15b25a42783d1e516b5298d70b582fae2559ae17
Subproject commit 474702157831f1a58bb50f5240ab8b1b02b6ba37

@ -121,6 +121,12 @@ KM_HIERARCHY = [
('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region)
('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []),
('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 Mode', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Sculpt Mode', 'EMPTY', 'WINDOW', []),
('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []),
]),
('Mask Editing', 'EMPTY', 'WINDOW', []),
('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)

@ -670,6 +670,42 @@ class AddPresetUnitsLength(AddPresetBase, Operator):
preset_subdir = "units_length"
class AddPresetGpencilBrush(AddPresetBase, Operator):
"""Add or remove grease pencil brush preset"""
bl_idname = "scene.gpencil_brush_preset_add"
bl_label = "Add Grease Pencil Brush Preset"
preset_menu = "VIEW3D_PT_gpencil_brush_presets"
preset_defines = [
"brush = bpy.context.active_gpencil_brush",
"settings = brush.gpencil_settings"
]
preset_values = [
"settings.input_samples",
"settings.active_smooth_factor",
"settings.angle",
"settings.angle_factor",
"settings.use_stabilizer",
"brush.smooth_stroke_radius",
"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.enable_random",
"settings.random_pressure",
"settings.random_strength",
"settings.uv_random",
"settings.pen_jitter",
"settings.use_jitter_pressure",
]
preset_subdir = "gpencil_brush"
classes = (
AddPresetCamera,
AddPresetCloth,
@ -686,6 +722,7 @@ classes = (
AddPresetTrackingSettings,
AddPresetTrackingTrackColor,
AddPresetUnitsLength,
AddPresetGpencilBrush,
ExecutePreset,
WM_MT_operator_presets,
)

@ -34,16 +34,19 @@ _modules = [
"properties_data_camera",
"properties_data_curve",
"properties_data_empty",
"properties_data_gpencil",
"properties_data_light",
"properties_data_lattice",
"properties_data_mesh",
"properties_data_metaball",
"properties_data_modifier",
"properties_data_shaderfx",
"properties_data_lightprobe",
"properties_data_speaker",
"properties_data_workspace",
"properties_mask_common",
"properties_material",
"properties_material_gpencil",
"properties_object",
"properties_paint_common",
"properties_grease_pencil_common",

@ -0,0 +1,402 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
from .properties_grease_pencil_common import (
GreasePencilDataPanel,
GreasePencilOnionPanel,
)
###############################
# Base-Classes (for shared stuff - e.g. poll, attributes, etc.)
class DataButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'GPENCIL'
class LayerDataButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
@classmethod
def poll(cls, context):
return (context.object and
context.object.type == 'GPENCIL' and
context.active_gpencil_layer)
###############################
# GP Object Properties Panels and Helper Classes
class DATA_PT_gpencil(DataButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
def draw(self, context):
layout = self.layout
# Grease Pencil data selector
gpd_owner = context.gpencil_data_owner
gpd = context.gpencil_data
layout.template_ID(gpd_owner, "data")
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)
gpl = item
gpd = context.gpencil_data
if self.layout_type in {'DEFAULT', 'COMPACT'}:
if gpl.lock:
layout.active = False
row = layout.row(align=True)
if gpl.is_parented:
icon = 'BONE_DATA'
else:
icon = 'BLANK1'
row.label(text="", icon=icon)
row.prop(gpl, "info", text="", emboss=False)
row = layout.row(align=True)
row.prop(gpl, "lock", text="", emboss=False)
row.prop(gpl, "hide", text="", emboss=False)
row.prop(gpl, "unlock_color", text="", emboss=False)
if gpl.use_onion_skinning is False:
icon = 'GHOST_DISABLED'
else:
icon = 'GHOST_ENABLED'
subrow = row.row(align=True)
subrow.prop(gpl, "use_onion_skinning", text="", icon=icon, emboss=False)
subrow.active = gpd.use_onion_skinning
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
class GPENCIL_MT_layer_specials(Menu):
bl_label = "Layer"
def draw(self, context):
layout = self.layout
layout.operator("gpencil.layer_duplicate", icon='COPY_ID') # XXX: needs a dedicated icon
layout.separator()
layout.operator("gpencil.reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
layout.operator("gpencil.hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
layout.separator()
layout.operator("gpencil.lock_all", icon='LOCKED', text="Lock All")
layout.operator("gpencil.unlock_all", icon='UNLOCKED', text="UnLock All")
layout.separator()
layout.operator("gpencil.layer_merge", icon='NLA', text="Merge Down")
class DATA_PT_gpencil_datapanel(Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
bl_label = "Layers"
@classmethod
def poll(cls, context):
if context.gpencil_data is None:
return False
ob = context.object
if ob is not None and ob.type == 'GPENCIL':
return True
return False
@staticmethod
def draw(self, context):
layout = self.layout
#layout.use_property_split = True
layout.use_property_decorate = False
gpd = context.gpencil_data
# Grease Pencil data...
if (gpd is None) or (not gpd.layers):
layout.operator("gpencil.layer_add", text="New Layer")
else:
self.draw_layers(context, layout, gpd)
def draw_layers(self, context, layout, gpd):
row = layout.row()
col = row.column()
if len(gpd.layers) >= 2:
layer_rows = 5
else:
layer_rows = 2
col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=layer_rows)
col = row.column()
sub = col.column(align=True)
sub.operator("gpencil.layer_add", icon='ZOOMIN', text="")
sub.operator("gpencil.layer_remove", icon='ZOOMOUT', text="")
gpl = context.active_gpencil_layer
if gpl:
sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="")
if len(gpd.layers) > 1:
col.separator()
sub = col.column(align=True)
sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
col.separator()
sub = col.column(align=True)
sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
row = layout.row(align=True)
if gpl:
row.prop(gpl, "opacity", text="Opacity", slider=True)
class DATA_PT_gpencil_layer_optionpanel(LayerDataButtonsPanel, Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
bl_label = "Adjustments"
bl_parent_id = 'DATA_PT_gpencil_datapanel'
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
gpl = context.active_gpencil_layer
layout.active = not gpl.lock
# Layer options
# Offsets - Color Tint
layout.enabled = not gpl.lock
col = layout.column(align=True)
col.prop(gpl, "tint_color")
col.prop(gpl, "tint_factor", slider=True)
# Offsets - Thickness
col = layout.row(align=True)
col.prop(gpl, "line_change", text="Stroke Thickness")
class DATA_PT_gpencil_parentpanel(LayerDataButtonsPanel, Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
bl_label = "Relations"
bl_parent_id = 'DATA_PT_gpencil_datapanel'
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
gpl = context.active_gpencil_layer
col = layout.column(align=True)
col.active = not gpl.lock
col.prop(gpl, "parent", text="Parent")
col.prop(gpl, "parent_type", text="Parent Type")
parent = gpl.parent
if parent and gpl.parent_type == 'BONE' and parent.type == 'ARMATURE':
col.prop_search(gpl, "parent_bone", parent.data, "bones", text="Bone")
class DATA_PT_gpencil_onionpanel(Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
bl_label = "Onion Skinning"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return bool(context.active_gpencil_layer)
@staticmethod
def draw_header(self, context):
self.layout.prop(context.gpencil_data, "use_onion_skinning", text="")
def draw(self, context):
gpd = context.gpencil_data
layout = self.layout
layout.use_property_split = True
layout.enabled = gpd.use_onion_skinning
GreasePencilOnionPanel.draw_settings(layout, gpd)
class GPENCIL_MT_gpencil_vertex_group(Menu):
bl_label = "GP Vertex Groups"
def draw(self, context):
layout = self.layout
layout.operator_context = 'EXEC_AREA'
layout.operator("object.vertex_group_add")
ob = context.active_object
if ob.vertex_groups.active:
layout.separator()
layout.operator("gpencil.vertex_group_assign", text="Assign to Active Group")
layout.operator("gpencil.vertex_group_remove_from", text="Remove from Active Group")
layout.separator()
layout.operator_menu_enum("object.vertex_group_set_active", "group", text="Set Active Group")
layout.operator("object.vertex_group_remove", text="Remove Active Group").all = False
layout.operator("object.vertex_group_remove", text="Remove All Groups").all = True
layout.separator()
layout.operator("gpencil.vertex_group_select", text="Select Points")
layout.operator("gpencil.vertex_group_deselect", text="Deselect Points")
class GPENCIL_UL_vgroups(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
vgroup = item
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(vgroup, "name", text="", emboss=False, icon_value=icon)
# icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
# layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
class DATA_PT_gpencil_vertexpanel(DataButtonsPanel, Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
bl_label = "Vertex Groups"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
ob = context.object
group = ob.vertex_groups.active
rows = 2
if group:
rows = 4
row = layout.row()
row.template_list("GPENCIL_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows)
col = row.column(align=True)
col.operator("object.vertex_group_add", icon='ZOOMIN', text="")
col.operator("object.vertex_group_remove", icon='ZOOMOUT', text="").all = False
if ob.vertex_groups:
row = layout.row()
sub = row.row(align=True)
sub.operator("gpencil.vertex_group_assign", text="Assign")
sub.operator("gpencil.vertex_group_remove_from", text="Remove")
sub = row.row(align=True)
sub.operator("gpencil.vertex_group_select", text="Select")
sub.operator("gpencil.vertex_group_deselect", text="Deselect")
layout.prop(context.tool_settings, "vertex_group_weight", text="Weight")
class DATA_PT_gpencil_display(DataButtonsPanel, Panel):
bl_label = "Viewport Display"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ob = context.object
gpd = context.gpencil_data
gpl = context.active_gpencil_layer
layout.prop(gpd, "xray_mode", text="Depth Ordering")
layout.prop(gpd, "edit_line_color", text="Edit Line Color")
layout.prop(ob, "empty_draw_size", text="Marker Size")
col = layout.column(align=True)
col.prop(gpd, "show_constant_thickness")
sub = col.column()
sub.active = not gpd.show_constant_thickness
sub.prop(gpd, "pixfactor", text="Thickness Scale")
if gpl:
layout.prop(gpd, "show_stroke_direction", text="Show Stroke Directions")
class DATA_PT_custom_props_gpencil(DataButtonsPanel, PropertyPanel, Panel):
_context_path = "object.data"
_property_type = bpy.types.GreasePencil
###############################
classes = (
DATA_PT_gpencil,
DATA_PT_gpencil_datapanel,
DATA_PT_gpencil_onionpanel,
DATA_PT_gpencil_layer_optionpanel,
DATA_PT_gpencil_parentpanel,
DATA_PT_gpencil_vertexpanel,
DATA_PT_gpencil_display,
DATA_PT_custom_props_gpencil,
GPENCIL_UL_layer,
GPENCIL_UL_vgroups,
GPENCIL_MT_layer_specials,
GPENCIL_MT_gpencil_vertex_group,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)

@ -28,10 +28,14 @@ class ModifierButtonsPanel:
bl_context = "modifier"
bl_options = {'HIDE_HEADER'}
class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
bl_label = "Modifiers"
@classmethod
def poll(cls, context):
ob = context.object
return ob and ob.type != 'GPENCIL'
def draw(self, context):
layout = self.layout
@ -1563,8 +1567,447 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.operator("object.correctivesmooth_bind", text="Unbind" if is_bind else "Bind")
class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel):
bl_label = "Modifiers"
@classmethod
def poll(cls, context):
ob = context.object
return ob and ob.type == 'GPENCIL'
def draw(self, context):
layout = self.layout
ob = context.object
layout.operator_menu_enum("object.gpencil_modifier_add", "type")
for md in ob.grease_pencil_modifiers:
box = layout.template_greasepencil_modifier(md)
if box:
# match enum type to our functions, avoids a lookup table.
getattr(self, md.type)(box, ob, md)
# the mt.type enum is (ab)used for a lookup on function names
# ...to avoid lengthy if statements
# so each type must have a function here.
def GP_NOISE(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
row = col.row(align=True)
row.prop(md, "factor")
row.prop(md, "random", text="", icon="TIME", toggle=True)
row = col.row()
row.enabled = md.random
row.prop(md, "step")
col.prop(md, "full_stroke")
col.prop(md, "move_extreme")
col = split.column()
col.label("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")
col.label("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")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
row = layout.row(align=True)
row.label("Affect:")
row = layout.row(align=True)
row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True)
row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True)
def GP_SMOOTH(self, layout, ob, md):
gpd = ob.data
row = layout.row(align=False)
row.prop(md, "factor")
row.prop(md, "step")
split = layout.split()
col = split.column()
col.label("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")
col = split.column()
col.label("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")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
row = layout.row(align=True)
row.label("Affect:")
row = layout.row(align=True)
row.prop(md, "affect_position", text="Position", icon='MESH_DATA', toggle=True)
row.prop(md, "affect_strength", text="Strength", icon='COLOR', toggle=True)
row.prop(md, "affect_thickness", text="Thickness", icon='LINE_DATA', toggle=True)
row.prop(md, "affect_uv", text="UV", icon='MOD_UVPROJECT', toggle=True)
def GP_SUBDIV(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
row = col.row(align=True)
row.prop(md, "level")
row.prop(md, "simple", text="", icon="PARTICLE_POINT")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
col = split.column()
col.label("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")
def GP_SIMPLIFY(self, layout, ob, md):
gpd = ob.data
row = layout.row()
row.prop(md, "mode")
split = layout.split()
col = split.column()
col.label("Settings:")
row = col.row(align=True)
row.enabled = md.mode == 'FIXED'
row.prop(md, "step")
row = col.row(align=True)
row.enabled = not md.mode == 'FIXED'
row.prop(md, "factor")
col = split.column()
col.label("Layer:")
row = col.row(align=True)
row.prop_search(md, "layer", gpd, "layers", text="", icon='GREASEPENCIL')
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
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")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
col.prop(md, "normalize_thickness")
col = split.column()
col.label("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")
col.label("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")
if not md.normalize_thickness:
split = layout.split()
col = split.column()
col.prop(md, "use_custom_curve")
if md.use_custom_curve:
col.template_curve_mapping(md, "curve")
def GP_TINT(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.prop(md, "color")
col.prop(md, "factor")
col = split.column()
col.label("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 = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
row = layout.row()
row.prop(md, "create_colors")
def GP_COLOR(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.label("Color:")
col.prop(md, "hue", text="H")
col.prop(md, "saturation", text="S")
col.prop(md, "value", text="V")
col = split.column()
col.label("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 = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
row = layout.row()
row.prop(md, "create_colors")
def GP_OPACITY(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.label("Opacity:")
col.prop(md, "factor")
col = split.column()
col.label("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")
col.label("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")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
def GP_INSTANCE(self, layout, ob, md):
gpd = ob.data
col = layout.column()
col.prop(md, "count")
col.prop(md, "use_make_objects")
split = layout.split()
col = split.column()
col.label("Offset:")
col.prop(md, "offset", text="")
col = split.column()
col.label("Shift:")
col.prop(md, "shift", text="")
row = col.row(align=True)
row.prop(md, "lock_axis", expand=True)
split = layout.split()
col = split.column()
col.label("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 = split.column()
col.label("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="")
split = layout.split()
col = split.column()
col.label("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 = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
def GP_BUILD(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.prop(md, "mode")
if md.mode == 'CONCURRENT':
col.prop(md, "concurrent_time_alignment")
else:
col.separator() # For spacing
col.separator()
col.separator()
col.prop(md, "transition")
sub = col.column(align=True)
sub.prop(md, "start_delay")
sub.prop(md, "length")
col = split.column(align=True)
col.prop(md, "use_restrict_frame_range")
sub = col.column(align=True)
sub.active = md.use_restrict_frame_range
sub.prop(md, "frame_start", text="Start")
sub.prop(md, "frame_end", text="End")
col.separator()
col.label("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")
def GP_LATTICE(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.label(text="Object:")
col.prop(md, "object", text="")
col = split.column()
col.label("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")
col.label("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")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
layout.separator()
layout.prop(md, "strength", slider=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")
# GPXX: Not implemented yet
# layout.separator()
# layout.prop(md, "clip")
layout.label("Layer:")
row = layout.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, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
layout.label(text="Object:")
layout.prop(md, "object", text="")
def GP_HOOK(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.label(text="Object:")
col.prop(md, "object", text="")
if md.object and md.object.type == 'ARMATURE':
col.label(text="Bone:")
col.prop_search(md, "subtarget", md.object.data, "bones", text="")
col = split.column()
col.label("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")
col.label("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")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
use_falloff = (md.falloff_type != 'NONE')
split = layout.split()
layout.separator()
row = layout.row(align=True)
if use_falloff:
row.prop(md, "falloff_radius")
row.prop(md, "strength", slider=True)
layout.prop(md, "falloff_type")
col = layout.column()
if use_falloff:
if md.falloff_type == 'CURVE':
col.template_curve_mapping(md, "falloff_curve")
split = layout.split()
col = split.column()
col.prop(md, "use_falloff_uniform")
def GP_OFFSET(self, layout, ob, md):
gpd = ob.data
split = layout.split()
col = split.column()
col.prop(md, "location")
col.prop(md, "scale")
col = split.column()
col.prop(md, "rotation")
col.label("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")
col.label("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")
row = col.row(align=True)
row.prop(md, "pass_index", text="Pass")
row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT")
classes = (
DATA_PT_modifiers,
DATA_PT_gpencil_modifiers,
)
if __name__ == "__main__": # only for live edit.

@ -0,0 +1,134 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
from bpy.types import Panel
from bpy.app.translations import pgettext_iface as iface_
class ShaderFxButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "shaderfx"
bl_options = {'HIDE_HEADER'}
class DATA_PT_shader_fx(ShaderFxButtonsPanel, Panel):
bl_label = "Effects"
@classmethod
def poll(cls, context):
return True
ob = context.object
return ob and ob.type == 'GPENCIL'
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ob = context.object
layout.operator_menu_enum("object.shaderfx_add", "type")
for fx in ob.shader_effects:
box = layout.template_shaderfx(fx)
if box:
# match enum type to our functions, avoids a lookup table.
getattr(self, fx.type)(box, fx)
# the mt.type enum is (ab)used for a lookup on function names
# ...to avoid lengthy if statements
# so each type must have a function here.
def FX_BLUR(self, layout, fx):
layout.prop(fx, "factor", text="Factor")
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':
layout.prop(fx, "low_color", text="Low Color")
if fx.mode == 'CUSTOM':
layout.prop(fx, "low_color", text="Color")
if fx.mode == 'BITONE':
layout.prop(fx, "high_color", text="High Color")
if fx.mode in {'BITONE', 'CUSTOM', 'TRANSPARENT'}:
layout.prop(fx, "factor")
def FX_WAVE(self, layout,fx):
layout.prop(fx, "orientation", expand=True)
layout.separator()
layout.prop(fx, "amplitude")
layout.prop(fx, "period")
layout.prop(fx, "phase")
def FX_PIXEL(self, layout, fx):
layout.prop(fx, "size", text="Size")
layout.prop(fx, "use_lines", text="Display Lines")
col = layout.column()
col.enabled = fx.use_lines
col.prop(fx, "color")
def FX_RIM(self, layout, fx):
layout.prop(fx, "offset", text="Offset")
layout.prop(fx, "rim_color")
layout.prop(fx, "mask_color")
layout.prop(fx, "mode")
layout.prop(fx, "blur")
layout.prop(fx, "samples")
def FX_SWIRL(self, layout, fx):
layout.prop(fx, "object", text="Object")
layout.prop(fx, "radius")
layout.prop(fx, "angle")
layout.prop(fx, "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,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)

@ -86,8 +86,11 @@ class EEVEE_MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
@classmethod
def poll(cls, context):
engine = context.engine
return (context.material or context.object) and (engine in cls.COMPAT_ENGINES)
if context.active_object and context.active_object.type == 'GPENCIL':
return False
else:
engine = context.engine
return (context.material or context.object) and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout

@ -0,0 +1,322 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
class GPENCIL_MT_color_specials(Menu):
bl_label = "Layer"
def draw(self, context):
layout = self.layout
layout.operator("gpencil.color_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
layout.operator("gpencil.color_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True
layout.separator()
layout.operator("gpencil.color_lock_all", icon='LOCKED', text="Lock All")
layout.operator("gpencil.color_unlock_all", icon='UNLOCKED', text="UnLock All")
layout.separator()
layout.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="Lock Unselected")
layout.operator("gpencil.lock_layer", icon='COLOR', text="Lock Unused")
class GPENCIL_UL_matslots(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
slot = item
ma = slot.material
if (ma is not None) and (ma.grease_pencil is not None):
gpcolor = ma.grease_pencil
if self.layout_type in {'DEFAULT', 'COMPACT'}:
if gpcolor.lock:
layout.active = False
row = layout.row(align=True)
row.enabled = not gpcolor.lock
row.prop(ma, "name", text="", emboss=False, icon_value=icon)
row = layout.row(align=True)
row.prop(gpcolor, "lock", text="", emboss=False)
row.prop(gpcolor, "hide", text="", emboss=False)
if gpcolor.ghost is True:
icon = 'GHOST_DISABLED'
else:
icon = 'GHOST_ENABLED'
row.prop(gpcolor, "ghost", text="", icon=icon, emboss=False)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.label(text="", icon_value=icon)
class GPMaterialButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "material"
@classmethod
def poll(cls, context):
ob = context.object
return (ob and ob.type == 'GPENCIL' and
ob.active_material and
ob.active_material.grease_pencil)
class MATERIAL_PT_gpencil_slots(Panel):
bl_label = "Grease Pencil Material Slots"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "material"
bl_options = {'HIDE_HEADER'}
@classmethod
def poll(cls, context):
ob = context.object
return ob and ob.type == 'GPENCIL'
@staticmethod
def draw(self, context):
layout = self.layout
gpd = context.gpencil_data
mat = context.object.active_material
ob = context.object
slot = context.material_slot
space = context.space_data
if ob:
is_sortable = len(ob.material_slots) > 1
rows = 1
if (is_sortable):
rows = 4
row = layout.row()
row.template_list("GPENCIL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=rows)
col = row.column(align=True)
col.operator("object.material_slot_add", icon='ZOOMIN', text="")
col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
col.menu("GPENCIL_MT_color_specials", icon='DOWNARROW_HLT', text="")
if is_sortable:
col.separator()
col.operator("object.material_slot_move", icon='TRIA_UP', text="").direction = 'UP'
col.operator("object.material_slot_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
col.separator()
sub = col.column(align=True)
sub.operator("gpencil.color_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.color_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
row = layout.row()
if ob:
row.template_ID(ob, "active_material", new="material.new", live_icon=True)
if slot:
icon_link = 'MESH_DATA' if slot.link == 'DATA' else 'OBJECT_DATA'
row.prop(slot, "link", icon=icon_link, icon_only=True)
if gpd.use_stroke_edit_mode:
row = layout.row(align=True)
row.operator("gpencil.stroke_change_color", text="Assign")
row.operator("gpencil.color_select", text="Select")
elif mat:
row.template_ID(space, "pin_id")
# Used as parent for "Stroke" and "Fill" panels
class MATERIAL_PT_gpencil_surface(GPMaterialButtonsPanel, Panel):
bl_label = "Surface"
@classmethod
def poll(cls, context):
ob = context.object
ma = context.object.active_material
if ma is None or ma.grease_pencil is None:
return False
return ob and ob.type == 'GPENCIL'
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
class MATERIAL_PT_gpencil_strokecolor(GPMaterialButtonsPanel, Panel):
bl_label = "Stroke"
bl_parent_id = 'MATERIAL_PT_gpencil_surface'
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ma = context.object.active_material
if ma is not None and ma.grease_pencil is not None:
gpcolor = ma.grease_pencil
col = layout.column()
col.active = not gpcolor.lock
col.prop(gpcolor, "mode")
col.prop(gpcolor, "stroke_style", text="Style")
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")
col.prop(gpcolor, "pixel_size", text="UV Factor")
col.prop(gpcolor, "use_stroke_pattern", text="Use As Pattern")
if gpcolor.stroke_style == 'SOLID' or gpcolor.use_stroke_pattern is True:
col.prop(gpcolor, "color", text="Color")
class MATERIAL_PT_gpencil_fillcolor(GPMaterialButtonsPanel, Panel):
bl_label = "Fill"
bl_parent_id = 'MATERIAL_PT_gpencil_surface'
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ma = context.object.active_material
if ma is not None and ma.grease_pencil:
gpcolor = ma.grease_pencil
# color settings
col = layout.column()
col.active = not gpcolor.lock
col.prop(gpcolor, "fill_style", text="Style")
if gpcolor.fill_style == 'GRADIENT':
col.prop(gpcolor, "gradient_type")
if gpcolor.fill_style != 'TEXTURE':
col.prop(gpcolor, "fill_color", text="Color")
if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'):
col.prop(gpcolor, "mix_color", text="Secondary Color")
if gpcolor.fill_style == 'GRADIENT':
col.prop(gpcolor, "mix_factor", text="Mix Factor", slider=True)
if gpcolor.fill_style in ('GRADIENT', 'CHESSBOARD'):
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', 'CHESSBOARD'):
col.prop(gpcolor, "pattern_radius", text="Radius")
else:
if gpcolor.fill_style != 'SOLID':
col.prop(gpcolor, "pattern_angle", text="Angle")
if gpcolor.fill_style == 'CHESSBOARD':
col.prop(gpcolor, "pattern_gridsize", text="Box Size")
# Texture
if gpcolor.fill_style == 'TEXTURE' or (gpcolor.texture_mix is True and gpcolor.fill_style == 'SOLID'):
col.template_ID(gpcolor, "fill_image", open="image.open")
if gpcolor.fill_style == 'TEXTURE':
col.prop(gpcolor, "use_fill_pattern", text="Use As Pattern")
if gpcolor.use_fill_pattern is True:
col.prop(gpcolor, "fill_color", text="Color")
col.prop(gpcolor, "texture_offset", text="Offset")
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, "texture_mix", text="Mix With Color")
if gpcolor.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"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
ma = context.object.active_material
self.layout.label(ma.name)
self.layout.template_preview(ma)
class MATERIAL_PT_gpencil_custom_props(GPMaterialButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_OPENGL'}
_context_path = "object.active_material"
_property_type = bpy.types.Material
class MATERIAL_PT_gpencil_options(GPMaterialButtonsPanel, Panel):
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ma = context.object.active_material
if ma is not None and ma.grease_pencil is not None:
gpcolor = ma.grease_pencil
layout.prop(gpcolor, "pass_index")
classes = (
GPENCIL_UL_matslots,
GPENCIL_MT_color_specials,
MATERIAL_PT_gpencil_slots,
MATERIAL_PT_gpencil_preview,
MATERIAL_PT_gpencil_surface,
MATERIAL_PT_gpencil_strokecolor,
MATERIAL_PT_gpencil_fillcolor,
MATERIAL_PT_gpencil_options,
MATERIAL_PT_gpencil_custom_props,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)

@ -28,9 +28,9 @@ from rna_prop_ui import PropertyPanel
from bl_operators.presets import PresetMenu
from .properties_physics_common import (
point_cache_ui,
effector_weights_ui,
)
point_cache_ui,
effector_weights_ui,
)
class SCENE_PT_units_length_presets(PresetMenu):
@ -104,7 +104,6 @@ class SCENE_PT_unit(SceneButtonsPanel, Panel):
col.prop(unit, "scale_length")
col.prop(unit, "use_separate")
class SceneKeyingSetsPanel:
@staticmethod
@ -568,6 +567,33 @@ class SCENE_PT_simplify_render(SceneButtonsPanel, Panel):
col.prop(rd, "simplify_child_particles_render", text="Max Child Particles")
class SCENE_PT_simplify_greasepencil(SceneButtonsPanel, Panel):
bl_label = "Simplify Grease Pencil"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME', 'BLENDER_CLAY', 'BLENDER_EEVEE'}
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
rd = context.scene.render
self.layout.prop(rd, "simplify_gpencil", text="")
def draw(self, context):
layout = self.layout
rd = context.scene.render
layout.active = rd.simplify_gpencil
row = layout.row()
row.prop(rd, "simplify_gpencil_onplay", text="Only on Play")
split = layout.split()
col = split.column()
col.prop(rd, "simplify_gpencil_view_fill", text="Fill")
col.prop(rd, "simplify_gpencil_remove_lines", text="Remove Fill Lines")
col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers")
class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
_context_path = "scene"
@ -593,6 +619,7 @@ classes = (
SCENE_PT_simplify,
SCENE_PT_simplify_viewport,
SCENE_PT_simplify_render,
SCENE_PT_simplify_greasepencil,
SCENE_PT_custom_props,
)

@ -23,14 +23,8 @@ from bpy.types import Panel, Header, Menu, UIList
from bpy.app.translations import pgettext_iface as iface_
from bl_operators.presets import PresetMenu
from .properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
GreasePencilStrokeSculptPanel,
GreasePencilBrushPanel,
GreasePencilBrushCurvesPanel,
GreasePencilDataPanel,
GreasePencilPaletteColorPanel,
)
GreasePencilDrawingToolsPanel,
GreasePencilDataPanel)
class CLIP_UL_tracking_objects(UIList):
@ -1154,40 +1148,12 @@ class CLIP_PT_grease_pencil(GreasePencilDataPanel, CLIP_PT_clip_view_panel, Pane
# But, this should only be visible in "clip" view
# Grease Pencil palette colors
class CLIP_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, CLIP_PT_clip_view_panel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'UI'
bl_options = {'DEFAULT_CLOSED'}
# NOTE: this is just a wrapper around the generic GP Panel
# But, this should only be visible in "clip" view
# Grease Pencil drawing tools
class CLIP_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
bl_region_type = 'TOOLS'
# Grease Pencil stroke editing tools
class CLIP_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
# Grease Pencil stroke sculpting tools
class CLIP_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
# Grease Pencil drawing brushes
class CLIP_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
# Grease Pencil drawing curves
class CLIP_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
bl_space_type = 'CLIP_EDITOR'
class CLIP_MT_view(Menu):
bl_label = "View"
@ -1515,12 +1481,7 @@ classes = (
CLIP_PT_footage_info,
CLIP_PT_tools_scenesetup,
CLIP_PT_grease_pencil,
CLIP_PT_grease_pencil_palettecolor,
CLIP_PT_tools_grease_pencil_draw,
CLIP_PT_tools_grease_pencil_edit,
CLIP_PT_tools_grease_pencil_sculpt,
CLIP_PT_tools_grease_pencil_brush,
CLIP_PT_tools_grease_pencil_brushcurves,
CLIP_MT_view,
CLIP_MT_clip,
CLIP_MT_proxy,

@ -21,20 +21,15 @@ import bpy
import math
from bpy.types import Header, Menu, Panel, UIList
from .properties_paint_common import (
UnifiedPaintPanel,
brush_texture_settings,
brush_texpaint_common,
brush_mask_texture_settings,
)
UnifiedPaintPanel,
brush_texture_settings,
brush_texpaint_common,
brush_mask_texture_settings,
)
from .properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
GreasePencilStrokeSculptPanel,
GreasePencilBrushPanel,
GreasePencilBrushCurvesPanel,
GreasePencilDataPanel,
GreasePencilPaletteColorPanel,
)
GreasePencilDrawingToolsPanel,
GreasePencilDataPanel
)
from bpy.app.translations import pgettext_iface as iface_
@ -1346,39 +1341,12 @@ class IMAGE_PT_grease_pencil(GreasePencilDataPanel, Panel):
# NOTE: this is just a wrapper around the generic GP Panel
# Grease Pencil palette colors
class IMAGE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'UI'
# NOTE: this is just a wrapper around the generic GP Panel
# Grease Pencil drawing tools
class IMAGE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
bl_region_type = 'TOOLS'
# Grease Pencil stroke editing tools
class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
# Grease Pencil stroke sculpting tools
class IMAGE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
# Grease Pencil drawing brushes
class IMAGE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
# Grease Pencil drawing curves
class IMAGE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
bl_space_type = 'IMAGE_EDITOR'
classes = (
IMAGE_MT_view,
@ -1430,12 +1398,7 @@ classes = (
IMAGE_PT_sample_line,
IMAGE_PT_scope_sample,
IMAGE_PT_grease_pencil,
IMAGE_PT_grease_pencil_palettecolor,
IMAGE_PT_tools_grease_pencil_draw,
IMAGE_PT_tools_grease_pencil_edit,
IMAGE_PT_tools_grease_pencil_sculpt,
IMAGE_PT_tools_grease_pencil_brush,
IMAGE_PT_tools_grease_pencil_brushcurves,
)
if __name__ == "__main__": # only for live edit.

@ -23,15 +23,10 @@ from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
from bl_operators.presets import PresetMenu
from .properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
GreasePencilStrokeSculptPanel,
GreasePencilBrushPanel,
GreasePencilBrushCurvesPanel,
GreasePencilDataPanel,
GreasePencilPaletteColorPanel,
GreasePencilToolsPanel
)
GreasePencilDrawingToolsPanel,
GreasePencilDataPanel,
GreasePencilToolsPanel
)
class NODE_HT_header(Header):
@ -539,19 +534,6 @@ class NODE_PT_grease_pencil(GreasePencilDataPanel, Panel):
return snode is not None and snode.node_tree is not None
# Grease Pencil palette colors
class NODE_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
# NOTE: this is just a wrapper around the generic GP Panel
@classmethod
def poll(cls, context):
snode = context.space_data
return snode is not None and snode.node_tree is not None
class NODE_PT_grease_pencil_tools(GreasePencilToolsPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
@ -571,31 +553,6 @@ class NODE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
bl_region_type = 'TOOLS'
# Grease Pencil stroke editing tools
class NODE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
# Grease Pencil stroke sculpting tools
class NODE_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
# Grease Pencil drawing brushes
class NODE_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
# Grease Pencil drawing curves
class NODE_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'TOOLS'
# -----------------------------
@ -620,13 +577,8 @@ classes = (
NODE_PT_quality,
NODE_UL_interface_sockets,
NODE_PT_grease_pencil,
NODE_PT_grease_pencil_palettecolor,
NODE_PT_grease_pencil_tools,
NODE_PT_tools_grease_pencil_draw,
NODE_PT_tools_grease_pencil_edit,
NODE_PT_tools_grease_pencil_sculpt,
NODE_PT_tools_grease_pencil_brush,
NODE_PT_tools_grease_pencil_brushcurves,
)

@ -22,7 +22,6 @@ from bpy.types import Header, Menu, Panel
from rna_prop_ui import PropertyPanel
from .properties_grease_pencil_common import (
GreasePencilDataPanel,
GreasePencilPaletteColorPanel,
GreasePencilToolsPanel,
)
from bpy.app.translations import pgettext_iface as iface_
@ -1281,14 +1280,6 @@ class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, SequencerButtonsPanel_Ou
# But, it should only show up when there are images in the preview region
class SEQUENCER_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, SequencerButtonsPanel_Output, Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'UI'
# NOTE: this is just a wrapper around the generic GP Panel
# But, it should only show up when there are images in the preview region
class SEQUENCER_PT_grease_pencil_tools(GreasePencilToolsPanel, SequencerButtonsPanel_Output, Panel):
bl_space_type = 'SEQUENCE_EDITOR'
bl_region_type = 'UI'
@ -1333,7 +1324,6 @@ classes = (
SEQUENCER_PT_view_safe_areas,
SEQUENCER_PT_modifiers,
SEQUENCER_PT_grease_pencil,
SEQUENCER_PT_grease_pencil_palettecolor,
SEQUENCER_PT_grease_pencil_tools,
SEQUENCER_PT_custom_props,
)

@ -24,6 +24,7 @@
# For now keep this in a single file since it's an area that may change,
# so avoid making changes all over the place.
import bpy
from bpy.types import Panel
from .space_toolsystem_common import (
@ -39,21 +40,77 @@ def generate_from_brushes_ex(
brush_category_attr,
brush_category_layout,
):
def draw_settings(context, layout, tool):
_defs_gpencil_paint.draw_settings_common(context, layout, tool)
# Categories
brush_categories = {}
for brush in context.blend_data.brushes:
if getattr(brush, brush_test_attr):
category = getattr(brush, brush_category_attr)
name = brush.name
brush_categories.setdefault(category, []).append(
ToolDef.from_dict(
dict(
text=name,
icon=icon_prefix + category.lower(),
data_block=name,
if context.mode != 'GPENCIL_PAINT':
for brush in context.blend_data.brushes:
if getattr(brush, brush_test_attr) and brush.gpencil_settings is None:
category = getattr(brush, brush_category_attr)
name = brush.name
brush_categories.setdefault(category, []).append(
ToolDef.from_dict(
dict(
text=name,
icon=icon_prefix + category.lower(),
data_block=name,
)
)
)
)
else:
for brush_type in brush_category_layout:
for brush in context.blend_data.brushes:
if getattr(brush, brush_test_attr) and brush.gpencil_settings.gp_icon == brush_type[0]:
category = brush_type[0]
name = brush.name
# rename default brushes for tool bar
if name.startswith("Draw "):
text = name.replace("Draw ", "")
elif name.startswith("Eraser "):
text = name.replace("Eraser ", "")
elif name.startswith("Fill "):
text = name.replace(" Area", "")
else:
text = name
# define icon
gp_icon = brush.gpencil_settings.gp_icon
if gp_icon == 'PENCIL':
icon_name = 'draw_pencil'
elif gp_icon == 'PEN':
icon_name = 'draw_pen'
elif gp_icon == 'INK':
icon_name = 'draw_ink'
elif gp_icon == 'INKNOISE':
icon_name = 'draw_noise'
elif gp_icon == 'BLOCK':
icon_name = 'draw_block'
elif gp_icon == 'MARKER':
icon_name = 'draw_marker'
elif gp_icon == 'FILL':
icon_name = 'draw_fill'
elif gp_icon == 'SOFT':
icon_name = 'draw.eraser_soft'
elif gp_icon == 'HARD':
icon_name = 'draw.eraser_hard'
elif gp_icon == 'STROKE':
icon_name = 'draw.eraser_stroke'
brush_categories.setdefault(category, []).append(
ToolDef.from_dict(
dict(
text=text,
icon=icon_prefix + icon_name,
data_block=name,
widget=None,
operator="gpencil.draw",
draw_settings=draw_settings,
)
)
)
def tools_from_brush_group(groups):
assert(type(groups) is tuple)
@ -61,6 +118,7 @@ def generate_from_brushes_ex(
tool_defs = tuple(brush_categories.pop(groups[0], ()))
else:
tool_defs = tuple(item for g in groups for item in brush_categories.pop(g, ()))
if len(tool_defs) > 1:
return (tool_defs,)
else:
@ -125,6 +183,112 @@ class _defs_view3d_generic:
)
class _defs_annotate:
@classmethod
def draw_settings_common(cls, context, layout, tool):
user_prefs = context.user_preferences
ts = context.tool_settings
# XXX: These context checks are needed for layer-dependent settings,
# but this breaks for using topbar for 2D editor active tools, etc.
if type(context.gpencil_data_owner) is bpy.types.Object:
gpd = context.scene.grease_pencil
else:
gpd = context.gpencil_data
gpl = gpd.layers.active if gpd else None
if gpd and gpl:
layout.prop(gpd.layers, "active_note", text="")
layout.prop(gpl, "thickness", text="Thickness")
else:
layout.prop(user_prefs.edit, "grease_pencil_default_color", text="Color")
layout.prop(ts, "annotation_thickness", text="Thickness")
# For 3D view, show the stroke placement settings
# XXX: How to tell what editor the active tool comes from?
is_3d_view = True
if is_3d_view:
layout.separator()
row = layout.row(align=True)
row.prop(ts, "annotation_stroke_placement_view3d", text="Orientation")
if ts.gpencil_stroke_placement_view3d == 'CURSOR':
row.prop(ts.gpencil_sculpt, "lockaxis")
elif ts.gpencil_stroke_placement_view3d in {'SURFACE', 'STROKE'}:
row.prop(ts, "use_gpencil_stroke_endpoints")
@ToolDef.from_fn
def scribble():
def draw_settings(context, layout, tool):
_defs_annotate.draw_settings_common(context, layout, tool)
return dict(
text="Annotate",
icon="ops.gpencil.draw",
cursor='PAINT_BRUSH',
keymap=(
("gpencil.annotate",
dict(mode='DRAW', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def line():
def draw_settings(context, layout, tool):
_defs_annotate.draw_settings_common(context, layout, tool)
return dict(
text="Draw Line",
icon="ops.gpencil.draw.line",
cursor='CROSSHAIR',
keymap=(
("gpencil.annotate",
dict(mode='DRAW_STRAIGHT', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def poly():
def draw_settings(context, layout, tool):
_defs_annotate.draw_settings_common(context, layout, tool)
return dict(
text="Draw Polygon",
icon="ops.gpencil.draw.poly",
cursor='CROSSHAIR',
keymap=(
("gpencil.annotate",
dict(mode='DRAW_POLY', wait_for_input=False),
dict(type='ACTIONMOUSE', value='PRESS')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def eraser():
def draw_settings(context, layout, tool):
# TODO: Move this setting to toolsettings
user_prefs = context.user_preferences
layout.prop(user_prefs.edit, "grease_pencil_eraser_radius", text="Radius")
return dict(
text="Eraser",
icon="ops.gpencil.draw.eraser",
cursor='CROSSHAIR', # XXX: Always show brush circle when enabled
keymap=(
("gpencil.annotate",
dict(mode='ERASER', wait_for_input=False),
dict(type='ACTIONMOUSE', value='PRESS')),
),
draw_settings=draw_settings,
)
class _defs_transform:
@ToolDef.from_fn
@ -865,6 +1029,331 @@ class _defs_uv_select:
),
)
class _defs_gpencil_paint:
@classmethod
def draw_color_selector(cls, context, layout):
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
ts = context.tool_settings
row = layout.row(align=True)
row.prop(ts, "use_gpencil_thumbnail_list", text="", icon="IMGDISPLAY")
if ts.use_gpencil_thumbnail_list is False:
row.template_ID(gp_settings, "material", live_icon=True)
else:
row.template_greasepencil_color(gp_settings, "material", rows=3, cols=8, scale=0.8)
@classmethod
def draw_settings_common(cls, context, layout, tool):
ob = context.active_object
if ob and ob.mode == 'GPENCIL_PAINT':
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
tool_settings= context.tool_settings
if gp_settings.gpencil_brush_type == 'ERASE':
row = layout.row()
row.prop(brush, "size", text="Radius")
elif gp_settings.gpencil_brush_type == 'FILL':
row = layout.row()
row.prop(gp_settings, "gpencil_fill_leak", text="Leak Size")
row.prop(brush, "size", text="Thickness")
row.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify")
_defs_gpencil_paint.draw_color_selector(context, layout)
row = layout.row(align=True)
row.prop(gp_settings, "gpencil_fill_draw_mode", text="")
row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID')
else: # bgpsettings.gpencil_brush_type == 'DRAW':
row = layout.row(align=True)
row.prop(brush, "size", text="Radius")
row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
row = layout.row(align=True)
row.prop(gp_settings, "pen_strength", slider=True)
row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
_defs_gpencil_paint.draw_color_selector(context, layout)
@staticmethod
def generate_from_brushes(context):
return generate_from_brushes_ex(
context,
icon_prefix="brush.gpencil.",
brush_test_attr="use_paint_grease_pencil",
brush_category_attr="grease_pencil_tool",
brush_category_layout=(
('PENCIL',),
('PEN',),
('INK',),
('INKNOISE',),
('BLOCK',),
('MARKER',),
('FILL',),
('SOFT',),
('HARD',),
('STROKE',),
)
)
class _defs_gpencil_edit:
@ToolDef.from_fn
def bend():
return dict(
text="Bend",
icon="ops.gpencil.edit_bend",
widget=None,
keymap=(
("transform.bend",
dict(),
dict(type='EVT_TWEAK_A', value='ANY')),
),
)
@ToolDef.from_fn
def mirror():
return dict(
text="Mirror",
icon="ops.gpencil.edit_mirror",
widget=None,
keymap=(
("transform.mirror",
dict(),
dict(type='EVT_TWEAK_A', value='ANY')),
),
)
@ToolDef.from_fn
def shear():
return dict(
text="Shear",
icon="ops.gpencil.edit_shear",
widget=None,
keymap=(
("transform.shear",
dict(),
dict(type='EVT_TWEAK_A', value='ANY')),
),
)
@ToolDef.from_fn
def tosphere():
return dict(
text="To Sphere",
icon="ops.gpencil.edit_to_sphere",
widget=None,
keymap=(
("transform.tosphere",
dict(),
dict(type='EVT_TWEAK_A', value='ANY')),
),
)
class _defs_gpencil_sculpt:
@classmethod
def draw_settings_common(cls, context, layout, tool):
ob = context.active_object
if ob and ob.mode == 'GPENCIL_SCULPT':
ts = context.tool_settings
settings = ts.gpencil_sculpt
brush = settings.brush
layout.prop(brush, "size", slider=True)
row = layout.row(align=True)
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
row.separator()
row.prop(ts.gpencil_sculpt, "use_select_mask", text="")
@ToolDef.from_fn
def smooth():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Smooth",
icon="ops.gpencil.sculpt_smooth",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='SMOOTH', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def thickness():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Thickness",
icon="ops.gpencil.sculpt_thickness",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='THICKNESS', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def strength():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Strength",
icon="ops.gpencil.sculpt_strength",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='STRENGTH', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def grab():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Grab",
icon="ops.gpencil.sculpt_grab",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='GRAB', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def push():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Push",
icon="ops.gpencil.sculpt_push",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='PUSH', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def twist():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Twist",
icon="ops.gpencil.sculpt_twist",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='TWIST', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def pinch():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Pinch",
icon="ops.gpencil.sculpt_pinch",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='PINCH', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def randomize():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Randomize",
icon="ops.gpencil.sculpt_randomize",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='RANDOMIZE', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
@ToolDef.from_fn
def clone():
def draw_settings(context, layout, tool):
_defs_gpencil_sculpt.draw_settings_common(context, layout, tool)
return dict(
text="Clone",
icon="ops.gpencil.sculpt_clone",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='CLONE', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
class _defs_gpencil_weight:
@classmethod
def draw_settings_common(cls, context, layout, tool):
ob = context.active_object
if ob and ob.mode == 'GPENCIL_WEIGHT':
settings = context.tool_settings.gpencil_sculpt
brush = settings.brush
layout.prop(brush, "size", slider=True)
row = layout.row(align=True)
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
@ToolDef.from_fn
def paint():
def draw_settings(context, layout, tool):
_defs_gpencil_weight.draw_settings_common(context, layout, tool)
return dict(
text="Draw",
icon="ops.gpencil.sculpt_weight",
widget=None,
keymap=(
("gpencil.brush_paint",
dict(mode='WEIGHT', wait_for_input=False),
dict(type='EVT_TWEAK_A', value='ANY')),
),
draw_settings=draw_settings,
)
class IMAGE_PT_tools_active(ToolSelectPanelHelper, Panel):
bl_space_type = 'IMAGE_EDITOR'
@ -951,8 +1440,6 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
_defs_transform.scale,
_defs_transform.scale_cage,
),
None,
_defs_view3d_generic.ruler,
)
_tools_select = (
@ -963,6 +1450,16 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
)
_tools_annotate = (
(
_defs_annotate.scribble,
_defs_annotate.line,
_defs_annotate.poly,
_defs_annotate.eraser,
),
_defs_view3d_generic.ruler,
)
_tools = {
None: [
_defs_view3d_generic.cursor,
@ -972,21 +1469,27 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
*_tools_select,
None,
*_tools_transform,
None,
*_tools_annotate,
],
'POSE': [
*_tools_select,
*_tools_transform,
None,
*_tools_annotate,
None,
(
_defs_pose.breakdown,
_defs_pose.push,
_defs_pose.relax,
)
),
],
'EDIT_ARMATURE': [
*_tools_select,
None,
*_tools_transform,
None,
*_tools_annotate,
_defs_edit_armature.roll,
(
_defs_edit_armature.bone_size,
@ -996,13 +1499,15 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
(
_defs_edit_armature.extrude,
_defs_edit_armature.extrude_cursor,
)
),
],
'EDIT_MESH': [
*_tools_select,
None,
*_tools_transform,
None,
*_tools_annotate,
None,
_defs_edit_mesh.cube_add,
None,
(
@ -1047,6 +1552,8 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_transform,
None,
*_tools_annotate,
None,
_defs_edit_curve.draw,
_defs_edit_curve.extrude_cursor,
],
@ -1075,6 +1582,33 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
_defs_weight_paint.gradient,
],
'GPENCIL_PAINT': [
_defs_gpencil_paint.generate_from_brushes,
],
'GPENCIL_EDIT': [
*_tools_select,
None,
*_tools_transform,
None,
_defs_gpencil_edit.bend,
_defs_gpencil_edit.mirror,
_defs_gpencil_edit.shear,
_defs_gpencil_edit.tosphere,
],
'GPENCIL_SCULPT': [
_defs_gpencil_sculpt.smooth,
_defs_gpencil_sculpt.thickness,
_defs_gpencil_sculpt.strength,
_defs_gpencil_sculpt.grab,
_defs_gpencil_sculpt.push,
_defs_gpencil_sculpt.twist,
_defs_gpencil_sculpt.pinch,
_defs_gpencil_sculpt.randomize,
_defs_gpencil_sculpt.clone,
],
'GPENCIL_WEIGHT': [
_defs_gpencil_weight.paint,
],
}

@ -128,6 +128,8 @@ class TOPBAR_HT_lower_bar(Header):
pass
elif mode == 'PARTICLE':
layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
elif mode == 'GPENCIL_PAINT':
layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_paint", category="")
def draw_center(self, context):
pass
@ -165,6 +167,15 @@ class TOPBAR_HT_lower_bar(Header):
layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".particlemode", category="")
elif mode == 'OBJECT':
layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".objectmode", category="")
elif mode == 'GPENCIL_PAINT':
layout.prop(context.tool_settings, "gpencil_stroke_placement_view3d", text='')
if context.tool_settings.gpencil_stroke_placement_view3d in ('ORIGIN', 'CURSOR'):
layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='')
layout.prop(context.tool_settings, "use_gpencil_draw_onback", text="", icon='ORTHO')
layout.prop(context.tool_settings, "use_gpencil_additive_drawing", text="", icon='FREEZE')
elif mode == 'GPENCIL_SCULPT':
layout.prop(context.tool_settings.gpencil_sculpt, "lockaxis", text='')
class _draw_left_context_mode:

@ -361,14 +361,16 @@ class USERPREF_PT_edit(Panel):
row.separator()
col = row.column()
col.label(text="Grease Pencil:")
col.label(text="Annotations:")
sub = col.row()
sub.prop(edit, "grease_pencil_default_color", text="Default Color")
col.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
col.separator()
col.label(text="Grease Pencil/Annotations:")
col.separator()
col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
col.separator()
col.prop(edit, "grease_pencil_default_color", text="Default Color")
col.separator()
col.prop(edit, "use_grease_pencil_simplify_stroke", text="Simplify Stroke")
col.separator()
col.separator()
@ -527,7 +529,10 @@ class USERPREF_PT_system(Panel):
col.prop(system, "gpu_viewport_quality")
col.separator()
col.label(text="Grease Pencil Options:")
col.prop(system, "gpencil_multi_sample", text="")
col.separator()
col.label(text="Text Draw Options:")
col.prop(system, "use_text_antialiasing")
if system.use_text_antialiasing:

@ -19,11 +19,8 @@
# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from .properties_grease_pencil_common import (
GreasePencilDataPanel,
GreasePencilPaletteColorPanel,
)
from .properties_paint_common import UnifiedPaintPanel
from .properties_grease_pencil_common import GreasePencilDataPanel
from bpy.app.translations import contexts as i18n_contexts
@ -80,18 +77,40 @@ class VIEW3D_HT_header(Header):
row.operator("pose.paste", text="", icon='PASTEDOWN').flipped = False
row.operator("pose.paste", text="", icon='PASTEFLIPDOWN').flipped = True
# GPencil
if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
row = layout.row(align=True)
row.operator("gpencil.copy", text="", icon='COPYDOWN')
row.operator("gpencil.paste", text="", icon='PASTEDOWN')
# Grease Pencil
if obj and obj.type == 'GPENCIL' and context.gpencil_data:
gpd = context.gpencil_data
# XXX: icon
layout.prop(context.gpencil_data, "use_onion_skinning", text="Onion Skins", icon='PARTICLE_PATH')
if gpd.is_stroke_paint_mode:
row = layout.row(align=True)
row.popover(
panel="VIEW3D_PT_tools_grease_pencil_shapes",
text="Shapes"
)
row = layout.row(align=True)
row.prop(tool_settings.gpencil_sculpt, "use_select_mask")
row.prop(tool_settings.gpencil_sculpt, "selection_alpha", slider=True)
if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode:
row = layout.row(align=True)
row.prop(gpd, "use_multiedit", text="", icon="FORCE_HARMONIC")
sub = row.row(align=True)
sub.active = gpd.use_multiedit
sub.popover(
panel="VIEW3D_PT_gpencil_multi_frame",
text="Multiframe"
)
if gpd.use_stroke_edit_mode:
row = layout.row(align=True)
row.operator("gpencil.copy", text="", icon='COPYDOWN')
row.operator("gpencil.paste", text="", icon='PASTEDOWN')
row = layout.row(align=True)
row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
row.popover(
panel="VIEW3D_PT_tools_grease_pencil_interpolate",
text="Interpolate"
)
VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
@ -101,7 +120,7 @@ class VIEW3D_HT_header(Header):
scene = context.scene
# Orientation
if object_mode in {'OBJECT', 'EDIT', 'POSE'}:
if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT'}:
orientation = scene.transform_orientation
current_orientation = scene.current_orientation
@ -126,7 +145,8 @@ class VIEW3D_HT_header(Header):
if obj is None:
show_snap = True
else:
if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}:
if object_mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT',
'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}:
show_snap = True
else:
@ -160,13 +180,15 @@ class VIEW3D_HT_header(Header):
# Proportional editing
if obj:
if context.gpencil_data and context.gpencil_data.use_stroke_edit_mode:
row = layout.row(align=True)
row.prop(tool_settings, "proportional_edit", icon_only=True)
gpd = context.gpencil_data
if gpd is not None:
if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode:
row = layout.row(align=True)
row.prop(tool_settings, "proportional_edit", icon_only=True)
sub = row.row(align=True)
sub.active = tool_settings.proportional_edit != 'DISABLED'
sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
sub = row.row(align=True)
sub.active = tool_settings.proportional_edit != 'DISABLED'
sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
elif object_mode in {'EDIT', 'PARTICLE_EDIT'}:
row = layout.row(align=True)
@ -190,7 +212,7 @@ class VIEW3D_HT_header(Header):
sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
# Pivot
if object_mode in {'OBJECT', 'EDIT', 'POSE'}:
if object_mode in {'OBJECT', 'EDIT', 'POSE', 'GPENCIL_EDIT', 'GPENCIL_SCULPT'}:
pivot_point = tool_settings.transform_pivot_point
act_pivot_point = bpy.types.ToolSettings.bl_rna.properties["transform_pivot_point"].enum_items[pivot_point]
row = layout.row(align=True)
@ -234,13 +256,14 @@ class VIEW3D_MT_editor_menus(Menu):
obj = context.active_object
mode_string = context.mode
edit_object = context.edit_object
gp_edit = context.gpencil_data and context.gpencil_data.use_stroke_edit_mode
gp_edit = obj and obj.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}
layout.menu("VIEW3D_MT_view")
# Select Menu
if gp_edit:
layout.menu("VIEW3D_MT_select_gpencil")
if mode_string not in {'GPENCIL_PAINT', 'GPENCIL_WEIGHT'}:
layout.menu("VIEW3D_MT_select_gpencil")
elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
mesh = obj.data
if mesh.use_paint_mask:
@ -266,7 +289,15 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("INFO_MT_edit_armature_add", text="Add")
if gp_edit:
layout.menu("VIEW3D_MT_edit_gpencil")
if obj and obj.mode == 'GPENCIL_PAINT':
layout.menu("VIEW3D_MT_paint_gpencil")
elif obj and obj.mode == 'GPENCIL_EDIT':
layout.menu("VIEW3D_MT_edit_gpencil")
elif obj and obj.mode == 'GPENCIL_SCULPT':
layout.menu("VIEW3D_MT_sculpt_gpencil")
elif obj and obj.mode == 'GPENCIL_WEIGHT':
layout.menu("VIEW3D_MT_weight_gpencil")
elif edit_object:
layout.menu("VIEW3D_MT_edit_%s" % edit_object.type.lower())
@ -1194,6 +1225,7 @@ class VIEW3D_MT_select_gpencil(Menu):
layout.separator()
layout.operator("gpencil.select_linked", text="Linked")
layout.operator("gpencil.select_alternate")
layout.operator_menu_enum("gpencil.select_grouped", "type", text="Grouped")
layout.separator()
@ -1454,6 +1486,7 @@ class INFO_MT_add(Menu):
layout.menu("INFO_MT_armature_add", icon='OUTLINER_OB_ARMATURE')
layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY')
layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL')
layout.separator()
layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER')
@ -3110,12 +3143,17 @@ class VIEW3D_MT_edit_gpencil_delete(Menu):
layout.separator()
layout.operator("gpencil.dissolve")
layout.operator_enum("gpencil.dissolve", "type")
layout.separator()
layout.operator("gpencil.active_frames_delete_all")
layout.separator()
layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes").mode = 'ACTIVE'
layout.operator("gpencil.frame_clean_fill", text="Clean Boundary Strokes all Frames").mode = 'ALL'
# Edit Curve
# draw_curve is used by VIEW3D_MT_edit_curve and VIEW3D_MT_edit_surface
@ -3476,11 +3514,34 @@ class VIEW3D_MT_edit_armature_delete(Menu):
layout.operator("armature.dissolve", text="Dissolve")
# ********** GPencil Stroke Edit menu **********
# ********** Grease Pencil Stroke menus **********
class VIEW3D_MT_gpencil_simplify(Menu):
bl_label = "Simplify"
def draw(self, context):
layout = self.layout
layout.operator("gpencil.stroke_simplify_fixed", text="Fixed")
layout.operator("gpencil.stroke_simplify", text="Adaptative")
class VIEW3D_MT_paint_gpencil(Menu):
bl_label = "Strokes"
def draw(self, context):
layout = self.layout
layout.menu("VIEW3D_MT_gpencil_animation")
layout.menu("VIEW3D_MT_edit_gpencil_interpolate")
layout.separator()
layout.operator("gpencil.delete", text="Delete Frame").type = 'FRAME'
layout.operator("gpencil.active_frames_delete_all")
class VIEW3D_MT_edit_gpencil(Menu):
bl_label = "GPencil"
bl_label = "Strokes"
def draw(self, context):
tool_settings = context.tool_settings
@ -3488,53 +3549,126 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout = self.layout
layout.menu("VIEW3D_MT_edit_gpencil_transform")
layout.operator("transform.mirror", text="Mirror")
layout.separator()
layout.menu("GPENCIL_MT_snap")
layout.separator()
layout.operator("gpencil.brush_paint", text="Sculpt Strokes").wait_for_input = True
layout.prop_menu_enum(tool_settings.gpencil_sculpt, "tool", text="Sculpt Brush")
layout.menu("VIEW3D_MT_gpencil_animation")
layout.separator()
layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access...
layout.menu("VIEW3D_MT_edit_gpencil_interpolate")
layout.separator()
layout.operator("gpencil.duplicate_move", text="Duplicate")
layout.operator("gpencil.stroke_subdivide", text="Subdivide")
layout.menu("VIEW3D_MT_gpencil_simplify")
layout.separator()
layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...")
layout.operator("gpencil.stroke_split", text="Split")
layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...")
layout.operator("gpencil.stroke_flip", text="Flip Direction")
layout.separator()
layout.operator("gpencil.copy", text="Copy")
layout.operator("gpencil.paste", text="Paste")
layout.operator("gpencil.paste", text="Paste").type = 'COPY'
layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
layout.separator()
layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
layout.operator("gpencil.stroke_change_color", text="Change Color")
layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...")
layout.separator()
layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
layout.separator()
layout.menu("VIEW3D_MT_edit_gpencil_delete")
layout.operator("gpencil.stroke_cyclical_set", text="Toggle Cyclic").type = 'TOGGLE'
layout.separator()
layout.operator_menu_enum("gpencil.frame_clean_fill", text="Clean Boundary Strokes...", property="mode")
class VIEW3D_MT_sculpt_gpencil(Menu):
bl_label = "Strokes"
def draw(self, context):
layout = self.layout
layout.menu("VIEW3D_MT_edit_gpencil_transform")
layout.separator()
layout.menu("GPENCIL_MT_snap")
layout.operator("gpencil.reveal")
layout.operator("gpencil.hide", text="Show Active Layer Only").unselected = True
layout.operator("gpencil.hide", text="Hide Active Layer").unselected = False
layout.separator()
layout.operator("gpencil.duplicate_move", text="Duplicate")
layout.operator("gpencil.stroke_subdivide", text="Subdivide")
layout.menu("VIEW3D_MT_gpencil_simplify")
layout.separator()
layout.operator_menu_enum("gpencil.stroke_separate", "mode", text="Separate...")
layout.operator("gpencil.stroke_split", text="Split")
layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...")
layout.operator("gpencil.stroke_flip", text="Flip Direction")
layout.separator()
layout.operator("gpencil.copy", text="Copy")
layout.operator("gpencil.paste", text="Paste").type = 'COPY'
layout.operator("gpencil.paste", text="Paste & Merge").type = 'MERGE'
layout.separator()
layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer")
layout.operator("gpencil.stroke_change_color", text="Move to Color")
layout.operator("gpencil.stroke_change_color", text="Change Color")
layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...")
layout.separator()
layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...")
layout.separator()
layout.menu("VIEW3D_MT_edit_gpencil_delete")
class VIEW3D_MT_weight_gpencil(Menu):
bl_label = "Weights"
def draw(self, context):
layout = self.layout
layout.operator("gpencil.vertex_group_invert", text="Invert")
layout.operator("gpencil.vertex_group_smooth", text="Smooth")
class VIEW3D_MT_gpencil_animation(Menu):
bl_label = "Animation"
@classmethod
def poll(cls, context):
ob = context.active_object
return ob and ob.type == 'GPENCIL' and ob.mode != 'OBJECT'
@staticmethod
def draw(self, context):
layout = self.layout
layout.operator("gpencil.blank_frame_add")
layout.operator("gpencil.active_frames_delete_all", text="Delete Frame(s)")
layout.separator()
layout.operator("gpencil.frame_duplicate", text="Duplicate Active Frame")
layout.operator("gpencil.frame_duplicate", text="Duplicate All Layers").mode = 'ALL'
class VIEW3D_MT_edit_gpencil_transform(Menu):
@ -3595,20 +3729,6 @@ class VIEW3D_MT_view_pie(Menu):
# ********** Panel **********
class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
# NOTE: this is just a wrapper around the generic GP Panel
class VIEW3D_PT_grease_pencil_palettecolor(GreasePencilPaletteColorPanel, Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
# NOTE: this is just a wrapper around the generic GP Panel
class VIEW3D_PT_view3d_properties(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@ -3720,6 +3840,7 @@ class VIEW3D_PT_object_type_visibility(Panel):
"armature",
"lattice",
"empty",
"grease_pencil",
"camera",
"light",
"light_probe",
@ -4040,6 +4161,8 @@ class VIEW3D_PT_overlay_guides(Panel):
if shading.type == 'MATERIAL':
col.prop(overlay, "show_look_dev")
col.prop(overlay, "show_annotation", text="Annotations")
class VIEW3D_PT_overlay_object(Panel):
bl_space_type = 'VIEW_3D'
@ -4578,6 +4701,60 @@ class VIEW3D_PT_transform_orientations(Panel):
row.operator("transform.delete_orientation", text="", icon='X', emboss=False)
class VIEW3D_PT_overlay_gpencil_options(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_parent_id = 'VIEW3D_PT_overlay'
bl_label = ""
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'GPENCIL'
def draw_header(self, context):
layout = self.layout
layout.label(text={
'GPENCIL_PAINT': "Draw Grease Pencil",
'GPENCIL_EDIT': "Edit Grease Pencil",
'GPENCIL_SCULPT': "Sculpt Grease Pencil",
'GPENCIL_WEIGHT': "Weight Grease Pencil",
'OBJECT': "Grease Pencil",
}[context.mode])
def draw(self, context):
layout = self.layout
view = context.space_data
overlay = view.overlay
layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin")
col = layout.column()
row = col.row()
row.prop(overlay, "use_gpencil_paper", text="")
sub = row.row()
sub.active = overlay.use_gpencil_paper
sub.prop(overlay, "gpencil_paper_opacity", text="Fade 3D Objects", slider=True)
col = layout.column()
row = col.row()
row.prop(overlay, "use_gpencil_grid", text="")
sub = row.row()
sub.active = overlay.use_gpencil_grid
sub.prop(overlay, "gpencil_grid_opacity", text="Canvas Grid", slider=True)
if overlay.use_gpencil_grid:
row = layout.row(align=True)
row.prop(overlay, "gpencil_grid_scale")
col = row.column()
col.prop(overlay, "gpencil_grid_lines", text="Subdivisions")
col.prop(overlay, "gpencil_grid_axis")
if context.object.mode in {'GPENCIL_EDIT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}:
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)
class VIEW3D_PT_quad_view(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@ -4605,6 +4782,14 @@ class VIEW3D_PT_quad_view(Panel):
row.prop(region, "use_box_clip")
# Annotation properties
class VIEW3D_PT_grease_pencil(GreasePencilDataPanel, Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
# NOTE: this is just a wrapper around the generic GP Panel
class VIEW3D_PT_view3d_stereo(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
@ -4684,6 +4869,27 @@ class VIEW3D_PT_context_properties(Panel):
rna_prop_ui.draw(self.layout, context, member, object, False)
# Grease Pencil Object - Multiframe falloff tools
class VIEW3D_PT_gpencil_multi_frame(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Multi Frame"
@staticmethod
def draw(self, context):
gpd = context.gpencil_data
settings = context.tool_settings.gpencil_sculpt
layout = self.layout
col = layout.column(align=True)
col.prop(settings, "use_multiframe_falloff")
# Falloff curve
if gpd.use_multiedit and settings.use_multiframe_falloff:
layout.template_curve_mapping(settings, "multiframe_falloff_curve", brush=True)
classes = (
VIEW3D_HT_header,
VIEW3D_MT_editor_menus,
@ -4791,8 +4997,13 @@ classes = (
VIEW3D_MT_edit_mesh_clean,
VIEW3D_MT_edit_mesh_delete,
VIEW3D_MT_edit_mesh_showhide,
VIEW3D_MT_paint_gpencil,
VIEW3D_MT_edit_gpencil,
VIEW3D_MT_edit_gpencil_delete,
VIEW3D_MT_sculpt_gpencil,
VIEW3D_MT_weight_gpencil,
VIEW3D_MT_gpencil_animation,
VIEW3D_MT_gpencil_simplify,
VIEW3D_MT_edit_curve,
VIEW3D_MT_edit_curve_ctrlpoints,
VIEW3D_MT_edit_curve_segments,
@ -4815,12 +5026,12 @@ classes = (
VIEW3D_MT_edit_gpencil_interpolate,
VIEW3D_MT_object_mode_pie,
VIEW3D_MT_view_pie,
VIEW3D_PT_grease_pencil,
VIEW3D_PT_grease_pencil_palettecolor,
VIEW3D_PT_view3d_properties,
VIEW3D_PT_view3d_camera_lock,
VIEW3D_PT_view3d_cursor,
VIEW3D_PT_object_type_visibility,
VIEW3D_PT_grease_pencil,
VIEW3D_PT_gpencil_multi_frame,
VIEW3D_PT_quad_view,
VIEW3D_PT_view3d_stereo,
VIEW3D_PT_shading,
@ -4849,6 +5060,7 @@ classes = (
VIEW3D_PT_pivot_point,
VIEW3D_PT_snapping,
VIEW3D_PT_transform_orientations,
VIEW3D_PT_overlay_gpencil_options,
VIEW3D_PT_context_properties,
)

@ -20,19 +20,17 @@
import bpy
from bpy.types import Menu, Panel, UIList
from .properties_grease_pencil_common import (
GreasePencilDrawingToolsPanel,
GreasePencilStrokeEditPanel,
GreasePencilInterpolatePanel,
GreasePencilStrokeSculptPanel,
GreasePencilBrushPanel,
GreasePencilBrushCurvesPanel
)
GreasePencilStrokeEditPanel,
GreasePencilStrokeSculptPanel,
GreasePencilAppearancePanel,
)
from .properties_paint_common import (
UnifiedPaintPanel,
brush_texture_settings,
brush_texpaint_common,
brush_mask_texture_settings,
)
UnifiedPaintPanel,
brush_texture_settings,
brush_texpaint_common,
brush_mask_texture_settings,
)
from bl_operators.presets import PresetMenu
class View3DPanel:
@ -70,6 +68,12 @@ def draw_vpaint_symmetry(layout, vpaint):
col.use_property_split = True
col.prop(vpaint, "radial_symmetry", text="Radial")
# Most of these panels should not be visible in GP edit modes
def is_not_gpencil_edit_mode(context):
is_gpmode = context.active_object and \
context.active_object.mode in {'GPENCIL_EDIT', 'GPENCIL_PAINT', 'GPENCIL_SCULPT', 'GPENCIL_WEIGHT'}
return not is_gpmode
# ********** default tools for editmode_mesh ****************
@ -1341,9 +1345,272 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
sub.prop(pe, "fade_frames", slider=True)
# Grease Pencil drawing tools
class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
# ********** grease pencil object tool panels ****************
# Grease Pencil drawing brushes
class VIEW3D_PT_tools_grease_pencil_brush(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Brush"
@classmethod
def poll(cls, context):
is_3d_view = context.space_data.type == 'VIEW_3D'
if is_3d_view:
if context.gpencil_data is None:
return False
gpd = context.gpencil_data
return bool(gpd.is_stroke_paint_mode)
else:
return True
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
ts = context.scene.tool_settings
settings = ts.gpencil_paint
row = layout.row()
col = row.column()
col.template_ID_preview(settings, "brush", new="brush.add_gpencil", rows=3, cols=8)
col = row.column()
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
sub = col.column(align=True)
sub.operator("gpencil.brush_presets_create", icon='HELP', text="")
if brush is not None:
# XXX: Items in "sub" currently show up beside the brush selector in a separate column
if gp_settings.gpencil_brush_type == 'ERASE':
sub.prop(gp_settings, "default_eraser", text="")
# Brush details
if gp_settings.gpencil_brush_type == 'ERASE':
col = layout.column(align=True)
col.prop(brush, "size", text="Radius")
col.separator()
row = col.row()
row.prop(gp_settings, "eraser_mode", expand=True)
elif gp_settings.gpencil_brush_type == 'FILL':
col = layout.column(align=True)
col.prop(gp_settings, "gpencil_fill_leak", text="Leak Size")
col.prop(brush, "size", text="Thickness")
col.prop(gp_settings, "gpencil_fill_simplyfy_level", text="Simplify")
col = layout.row(align=True)
col.template_ID(gp_settings, "material")
row = layout.row(align=True)
row.prop(gp_settings, "gpencil_fill_draw_mode", text="Boundary Draw Mode")
row.prop(gp_settings, "gpencil_fill_show_boundary", text="", icon='GRID')
col = layout.column(align=True)
col.enabled = gp_settings.gpencil_fill_draw_mode != "STROKE"
col.prop(gp_settings, "gpencil_fill_hide", text="Hide Transparent Lines")
sub = col.row(align=True)
sub.enabled = gp_settings.gpencil_fill_hide
sub.prop(gp_settings, "gpencil_fill_threshold", text="Threshold")
else: # bgpsettings.gpencil_brush_type == 'DRAW':
row = layout.row(align=True)
row.prop(brush, "size", text="Radius")
row.prop(gp_settings, "use_pressure", text="", icon='STYLUS_PRESSURE')
row = layout.row(align=True)
row.prop(gp_settings, "pen_strength", slider=True)
row.prop(gp_settings, "use_strength_pressure", text="", icon='STYLUS_PRESSURE')
row = layout.row(align=True)
row.template_ID(gp_settings, "material")
# Grease Pencil drawing brushes options
class VIEW3D_PT_tools_grease_pencil_brush_option(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Options"
bl_options = {'DEFAULT_CLOSED'}
def draw_header_preset(self, context):
VIEW3D_PT_gpencil_brush_presets.draw_panel_header(self.layout)
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
if brush is not None:
col = layout.column(align=True)
col.prop(gp_settings, "input_samples")
col.separator()
col.prop(gp_settings, "active_smooth_factor")
col.separator()
col.prop(gp_settings, "angle", slider=True)
col.prop(gp_settings, "angle_factor", text="Factor", slider=True)
col.separator()
class VIEW3D_PT_tools_grease_pencil_brush_stabilizer(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
bl_label = "Stabilizer"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
return brush is not None and gp_settings.gpencil_brush_type == 'DRAW'
def draw_header(self, context):
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
self.layout.prop(gp_settings, "use_stabilizer", text="")
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
layout.active = gp_settings.use_stabilizer
layout.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
layout.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
class VIEW3D_PT_tools_grease_pencil_brush_settings(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
bl_label = "Post-processing Settings"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
brush = context.active_gpencil_brush
return brush is not None
def draw_header(self, context):
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
self.layout.prop(gp_settings, "enable_settings", text="")
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
layout.active = gp_settings.enable_settings
layout.prop(gp_settings, "pen_smooth_factor")
layout.prop(gp_settings, "pen_smooth_steps")
layout.prop(gp_settings, "pen_thick_smooth_factor")
layout.prop(gp_settings, "pen_thick_smooth_steps")
layout.prop(gp_settings, "pen_subdivision_steps")
layout.prop(gp_settings, "random_subdiv", text="Randomness", slider=True)
class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_brush_option'
bl_label = "Random Settings"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
brush = context.active_gpencil_brush
return brush is not None
def draw_header(self, context):
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
self.layout.prop(gp_settings, "enable_random", text="")
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
layout.active = gp_settings.enable_random
layout.prop(gp_settings, "random_pressure", text="Pressure", slider=True)
layout.prop(gp_settings, "random_strength", text="Strength", slider=True)
layout.prop(gp_settings, "uv_random", text="UV", slider=True)
row = layout.row(align=True)
row.prop(gp_settings, "pen_jitter", slider=True)
row.prop(gp_settings, "use_jitter_pressure", text="", icon='STYLUS_PRESSURE')
# Grease Pencil drawingcurves
class VIEW3D_PT_tools_grease_pencil_brushcurves(View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Curves"
bl_options = {'DEFAULT_CLOSED'}
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
brush = context.active_gpencil_brush
gp_settings = brush.gpencil_settings
# Brush
layout.label("Sensitivity")
layout.template_curve_mapping(gp_settings, "curve_sensitivity", brush=True)
layout.label("Strength")
layout.template_curve_mapping(gp_settings, "curve_strength", brush=True)
layout.label("Jitter")
layout.template_curve_mapping(gp_settings, "curve_jitter", brush=True)
# Grease Pencil create shapes
class VIEW3D_PT_tools_grease_pencil_shapes(View3DPanel, Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Shapes"
@classmethod
def poll(cls, context):
ob = context.active_object
return ob and ob.type == 'GPENCIL'
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
col = layout.column(align=True)
col.operator("gpencil.primitive", text="Line", icon='IPO_CONSTANT').type = 'LINE'
col.operator("gpencil.primitive", text="Rectangle", icon='UV_FACESEL').type = 'BOX'
col.operator("gpencil.primitive", text="Circle", icon='ANTIALIASED').type = 'CIRCLE'
layout.operator("object.gpencil_add", text="Monkey", icon='MONKEY').type = 'MONKEY'
# Grease Pencil stroke editing tools
@ -1352,24 +1619,109 @@ class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
# Grease Pencil stroke interpolation tools
class VIEW3D_PT_tools_grease_pencil_interpolate(GreasePencilInterpolatePanel, Panel):
class VIEW3D_PT_tools_grease_pencil_interpolate(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
bl_label = "Interpolate"
@classmethod
def poll(cls, context):
if context.gpencil_data is None:
return False
gpd = context.gpencil_data
return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
@staticmethod
def draw(self, context):
layout = self.layout
settings = context.tool_settings.gpencil_interpolate
col = layout.column(align=True)
col.label("Interpolate Strokes")
col.operator("gpencil.interpolate", text="Interpolate")
col.operator("gpencil.interpolate_sequence", text="Sequence")
col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns")
col = layout.column(align=True)
col.label(text="Options:")
col.prop(settings, "interpolate_all_layers")
col.prop(settings, "interpolate_selected_only")
col = layout.column(align=True)
col.label(text="Sequence Options:")
col.prop(settings, "type")
if settings.type == 'CUSTOM':
# TODO: Options for loading/saving curve presets?
col.template_curve_mapping(settings, "interpolation_curve", brush=True)
elif settings.type != 'LINEAR':
col.prop(settings, "easing")
if settings.type == 'BACK':
layout.prop(settings, "back")
elif setting.type == 'ELASTIC':
sub = layout.column(align=True)
sub.prop(settings, "amplitude")
sub.prop(settings, "period")
# Grease Pencil stroke sculpting tools
class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel):
bl_space_type = 'VIEW_3D'
class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, View3DPanel, Panel):
bl_context = ".greasepencil_sculpt"
bl_category = "Tools"
bl_label = "Sculpt Strokes"
# Grease Pencil drawing brushes
class VIEW3D_PT_tools_grease_pencil_brush(GreasePencilBrushPanel, Panel):
bl_space_type = 'VIEW_3D'
# Grease Pencil weight painting tools
class VIEW3D_PT_tools_grease_pencil_weight_paint(View3DPanel, Panel):
bl_context = ".greasepencil_weight"
bl_category = "Tools"
bl_label = "Weight Paint"
# Grease Pencil drawingcurves
@staticmethod
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
gpd = context.gpencil_data
settings = context.tool_settings.gpencil_sculpt
tool = settings.tool
brush = settings.brush
class VIEW3D_PT_tools_grease_pencil_brushcurves(GreasePencilBrushCurvesPanel, Panel):
bl_space_type = 'VIEW_3D'
layout.template_icon_view(settings, "weight_tool", show_labels=True)
col = layout.column()
col.prop(brush, "size", slider=True)
row = col.row(align=True)
row.prop(brush, "strength", slider=True)
row.prop(brush, "use_pressure_strength", text="")
col.prop(brush, "use_falloff")
# Grease Pencil Brush Appeareance (one for each mode)
class VIEW3D_PT_tools_grease_pencil_paint_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
bl_context = ".greasepencil_paint"
bl_label = "Appearance"
class VIEW3D_PT_tools_grease_pencil_sculpt_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
bl_context = ".greasepencil_sculpt"
bl_label = "Appearance"
class VIEW3D_PT_tools_grease_pencil_weight_appearance(GreasePencilAppearancePanel, View3DPanel, Panel):
bl_context = ".greasepencil_weight"
bl_label = "Appearance"
class VIEW3D_PT_gpencil_brush_presets(PresetMenu):
"""Brush settings"""
bl_label = "Brush Presets"
preset_subdir = "gpencil_brush"
preset_operator = "script.execute_preset"
preset_add_operator = "scene.gpencil_brush_preset_add"
classes = (
@ -1401,12 +1753,21 @@ classes = (
VIEW3D_PT_tools_projectpaint,
VIEW3D_MT_tools_projectpaint_stencil,
VIEW3D_PT_tools_particlemode,
VIEW3D_PT_tools_grease_pencil_draw,
VIEW3D_PT_tools_grease_pencil_edit,
VIEW3D_PT_tools_grease_pencil_interpolate,
VIEW3D_PT_tools_grease_pencil_sculpt,
VIEW3D_PT_gpencil_brush_presets,
VIEW3D_PT_tools_grease_pencil_brush,
VIEW3D_PT_tools_grease_pencil_brush_option,
VIEW3D_PT_tools_grease_pencil_brush_settings,
VIEW3D_PT_tools_grease_pencil_brush_stabilizer,
VIEW3D_PT_tools_grease_pencil_brush_random,
VIEW3D_PT_tools_grease_pencil_brushcurves,
VIEW3D_PT_tools_grease_pencil_shapes,
VIEW3D_PT_tools_grease_pencil_sculpt,
VIEW3D_PT_tools_grease_pencil_weight_paint,
VIEW3D_PT_tools_grease_pencil_paint_appearance,
VIEW3D_PT_tools_grease_pencil_sculpt_appearance,
VIEW3D_PT_tools_grease_pencil_weight_appearance,
VIEW3D_PT_tools_grease_pencil_interpolate,
)
if __name__ == "__main__": # only for live edit.

@ -44,7 +44,9 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fileglobal_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_freestyle_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_genfile.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_shader_fx_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_group_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h
@ -112,6 +114,8 @@ add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)
add_subdirectory(modifiers)
add_subdirectory(gpencil_modifiers)
add_subdirectory(shader_fx)
add_subdirectory(makesdna)
add_subdirectory(makesrna)

@ -28,11 +28,14 @@
*/
enum eCurveMappingPreset;
struct bContext;
struct Brush;
struct Paint;
struct ImBuf;
struct ImagePool;
struct Main;
struct Scene;
struct ToolSettings;
struct UnifiedPaintSettings;
// enum eCurveMappingPreset;
@ -45,14 +48,17 @@ void BKE_brush_system_exit(void);
/* datablock functions */
void BKE_brush_init(struct Brush *brush);
struct Brush *BKE_brush_add(struct Main *bmain, const char *name, const eObjectMode ob_mode);
struct Brush *BKE_brush_add_gpencil(struct Main *bmain, struct ToolSettings *ts, const char *name);
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode);
void BKE_brush_copy_data(struct Main *bmain, struct Brush *brush_dst, const struct Brush *brush_src, const int flag);
struct Brush *BKE_brush_copy(struct Main *bmain, const struct Brush *brush);
void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool lib_local);
void BKE_brush_unlink(struct Main *bmain, struct Brush *brush);
void BKE_brush_free(struct Brush *brush);
void BKE_brush_sculpt_reset(struct Brush *brush);
void BKE_brush_gpencil_presets(struct bContext *C);
struct Brush *BKE_brush_getactive_gpencil(struct ToolSettings *ts);
struct Paint *BKE_brush_get_gpencil_paint(struct ToolSettings *ts);
/* image icon function */
struct ImBuf *get_brush_icon(struct Brush *brush);

@ -65,9 +65,7 @@ struct bPoseChannel;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDpalette;
struct bGPDpalettecolor;
struct bGPDbrush;
struct Brush;
struct wmWindow;
struct wmWindowManager;
struct RenderEngineType;
@ -120,6 +118,10 @@ enum {
CTX_MODE_PAINT_TEXTURE,
CTX_MODE_PARTICLE,
CTX_MODE_OBJECT,
CTX_MODE_GPENCIL_PAINT,
CTX_MODE_GPENCIL_EDIT,
CTX_MODE_GPENCIL_SCULPT,
CTX_MODE_GPENCIL_WEIGHT,
CTX_MODE_NUM /* must be last */
};
@ -313,9 +315,7 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list);
struct bGPdata *CTX_data_gpencil_data(const bContext *C);
struct bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C);
struct bGPDframe *CTX_data_active_gpencil_frame(const bContext *C);
struct bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C);
struct bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C);
struct bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C);
struct Brush *CTX_data_active_gpencil_brush(const bContext *C);
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list);
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list);

@ -31,25 +31,45 @@
* \author Joshua Leung
*/
struct CurveMapping;
struct Depsgraph;
struct GpencilModifierData;
struct ToolSettings;
struct ListBase;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
struct bGPDspoint;
struct bGPDstroke;
struct Material;
struct bGPDpalette;
struct bGPDpalettecolor;
struct Main;
struct BoundBox;
struct Brush;
struct Object;
struct bDeformGroup;
struct SimplifyGpencilModifierData;
struct InstanceGpencilModifierData;
struct LatticeGpencilModifierData;
struct MDeformVert;
struct MDeformWeight;
/* ------------ Grease-Pencil API ------------------ */
void BKE_gpencil_free_point_weights(struct MDeformVert *dvert);
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps);
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
void BKE_gpencil_free_frames(struct bGPDlayer *gpl);
void BKE_gpencil_free_layers(struct ListBase *list);
void BKE_gpencil_free_brushes(struct ListBase *list);
void BKE_gpencil_free_palettes(struct ListBase *list);
void BKE_gpencil_free(struct bGPdata *gpd, bool free_palettes);
bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf);
void BKE_gpencil_free_derived_frames(struct bGPdata *gpd);
void BKE_gpencil_free(struct bGPdata *gpd, bool free_all);
void BKE_gpencil_batch_cache_dirty(struct bGPdata *gpd);
void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
void BKE_gpencil_stroke_sync_selection(struct bGPDstroke *gps);
@ -60,21 +80,36 @@ struct bGPdata *BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
struct bGPDframe *BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src);
struct bGPDlayer *BKE_gpencil_layer_duplicate(const struct bGPDlayer *gpl_src);
void BKE_gpencil_frame_copy_strokes(struct bGPDframe *gpf_src, struct bGPDframe *gpf_dst);
struct bGPDstroke *BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src);
void BKE_gpencil_copy_data(struct Main *bmain, struct bGPdata *gpd_dst, const struct bGPdata *gpd_src, const int flag);
struct bGPdata *BKE_gpencil_copy(struct Main *bmain, const struct bGPdata *gpd);
struct bGPdata *BKE_gpencil_data_duplicate(struct Main *bmain, const struct bGPdata *gpd, bool internal_copy);
void BKE_gpencil_make_local(struct Main *bmain, struct bGPdata *gpd, const bool lib_local);
void BKE_gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf);
struct bGPDpalette *BKE_gpencil_palette_addnew(struct bGPdata *gpd, const char *name, bool setactive);
struct bGPDpalette *BKE_gpencil_palette_duplicate(const struct bGPDpalette *palette_src);
struct bGPDpalettecolor *BKE_gpencil_palettecolor_addnew(struct bGPDpalette *palette, const char *name, bool setactive);
/* materials */
void BKE_gpencil_material_index_remove(struct bGPdata *gpd, int index);
void BKE_gpencil_material_remap(struct bGPdata *gpd, const unsigned int *remap, unsigned int remap_len);
struct bGPDbrush *BKE_gpencil_brush_addnew(struct ToolSettings *ts, const char *name, bool setactive);
struct bGPDbrush *BKE_gpencil_brush_duplicate(const struct bGPDbrush *brush_src);
void BKE_gpencil_brush_init_presets(struct ToolSettings *ts);
/* statistics functions */
void BKE_gpencil_stats_update(struct bGPdata *gpd);
/* Utilities for creating and populating GP strokes */
/* - Number of values defining each point in the built-in data
* buffers for primitives (e.g. 2D Monkey)
*/
#define GP_PRIM_DATABUF_SIZE 5
void BKE_gpencil_stroke_add_points(
struct bGPDstroke *gps,
const float *array, const int totpoints,
const float mat[4][4]);
struct bGPDstroke *BKE_gpencil_add_stroke(struct bGPDframe *gpf, int mat_idx, int totpoints, short thickness);
/* Stroke and Fill - Alpha Visibility Threshold */
#define GPENCIL_ALPHA_OPACITY_THRESH 0.001f
@ -103,20 +138,40 @@ struct bGPDlayer *BKE_gpencil_layer_getactive(struct bGPdata *gpd);
void BKE_gpencil_layer_setactive(struct bGPdata *gpd, struct bGPDlayer *active);
void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl);
struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts);
void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active);
void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush);
struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd);
void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active);
void BKE_gpencil_palette_delete(struct bGPdata *gpd, struct bGPDpalette *palette);
void BKE_gpencil_palette_change_strokes(struct bGPdata *gpd);
struct bGPDpalettecolor *BKE_gpencil_palettecolor_getactive(struct bGPDpalette *palette);
void BKE_gpencil_palettecolor_setactive(struct bGPDpalette *palette, struct bGPDpalettecolor *active);
void BKE_gpencil_palettecolor_delete(struct bGPDpalette *palette, struct bGPDpalettecolor *palcolor);
struct bGPDpalettecolor *BKE_gpencil_palettecolor_getbyname(struct bGPDpalette *palette, char *name);
void BKE_gpencil_palettecolor_changename(struct bGPdata *gpd, char *oldname, const char *newname);
void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name);
struct Material *BKE_gpencil_get_material_from_brush(struct Brush *brush);
struct Material *BKE_gpencil_material_ensure(struct Main *bmain, struct Object *ob);
/* object boundbox */
bool BKE_gpencil_stroke_minmax(
const struct bGPDstroke *gps, const bool use_select,
float r_min[3], float r_max[3]);
struct BoundBox *BKE_gpencil_boundbox_get(struct Object *ob);
void BKE_gpencil_centroid_3D(struct bGPdata *gpd, float r_centroid[3]);
/* vertex groups */
float BKE_gpencil_vgroup_use_index(struct MDeformVert *dvert, int index);
void BKE_gpencil_vgroup_remove(struct Object *ob, struct bDeformGroup *defgroup);
struct MDeformWeight *BKE_gpencil_vgroup_add_point_weight(struct MDeformVert *dvert, int index, float weight);
bool BKE_gpencil_vgroup_remove_point_weight(struct MDeformVert *dvert, int index);
void BKE_gpencil_stroke_weights_duplicate(struct bGPDstroke *gps_src, struct bGPDstroke *gps_dst);
/* GPencil geometry evaluation */
void BKE_gpencil_eval_geometry(struct Depsgraph *depsgraph, struct bGPdata *gpd);
/* stroke geometry utilities */
void BKE_gpencil_stroke_normal(const struct bGPDstroke *gps, float r_normal[3]);
void BKE_gpencil_simplify_stroke(struct bGPDstroke *gps, float factor);
void BKE_gpencil_simplify_fixed(struct bGPDstroke *gps);
void BKE_gpencil_transform(struct bGPdata *gpd, float mat[4][4]);
bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf);
bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence);
bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence);
bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence);
void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
float BKE_gpencil_multiframe_falloff_calc(struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff);
#endif /* __BKE_GPENCIL_H__ */

@ -0,0 +1,256 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is: all of this file.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BKE_GPENCIL_MODIFIER_H__
#define __BKE_GPENCIL_MODIFIER_H__
/** \file BKE_greasepencil_modifier.h
* \ingroup bke
*/
#include "DNA_gpencil_modifier_types.h" /* needed for all enum typdefs */
#include "BLI_compiler_attrs.h"
#include "BKE_customdata.h"
struct ID;
struct Depsgraph;
struct DerivedMesh;
struct bContext; /* NOTE: bakeModifier() - called from UI - needs to create new datablocks, hence the need for this */
struct Mesh;
struct Object;
struct Scene;
struct ViewLayer;
struct ListBase;
struct bArmature;
struct Main;
struct GpencilModifierData;
struct BMEditMesh;
struct DepsNodeHandle;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct ModifierUpdateDepsgraphContext;
#define GPENCIL_MODIFIER_ACTIVE(_md, _is_render) (((_md->mode & eGpencilModifierMode_Realtime) && (_is_render == false)) || \
((_md->mode & eGpencilModifierMode_Render) && (_is_render == true)))
#define GPENCIL_MODIFIER_EDIT(_md, _is_edit) (((_md->mode & eGpencilModifierMode_Editmode) == 0) && (_is_edit))
typedef enum {
/* Should not be used, only for None modifier type */
eGpencilModifierTypeType_None,
/* grease pencil modifiers */
eGpencilModifierTypeType_Gpencil,
} GpencilModifierTypeType;
typedef enum {
eGpencilModifierTypeFlag_SupportsMapping = (1 << 0),
eGpencilModifierTypeFlag_SupportsEditmode = (1 << 1),
/* For modifiers that support editmode this determines if the
* modifier should be enabled by default in editmode. This should
* only be used by modifiers that are relatively speedy and
* also generally used in editmode, otherwise let the user enable
* it by hand.
*/
eGpencilModifierTypeFlag_EnableInEditmode = (1 << 2),
/* For modifiers that require original data and so cannot
* be placed after any non-deformative modifier.
*/
eGpencilModifierTypeFlag_RequiresOriginalData = (1 << 3),
/* max one per type */
eGpencilModifierTypeFlag_Single = (1 << 4),
/* can't be added manually by user */
eGpencilModifierTypeFlag_NoUserAdd = (1 << 5),
} GpencilModifierTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
typedef void(*GreasePencilObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
typedef void(*GreasePencilIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
typedef void(*GreasePencilTexWalkFunc)(void *userData, struct Object *ob, struct GpencilModifierData *md, const char *propname);
typedef struct GpencilModifierTypeInfo {
/* The user visible name for this modifier */
char name[32];
/* The DNA struct name for the modifier data type, used to
* write the DNA data out.
*/
char struct_name[32];
/* The size of the modifier data type, used by allocation. */
int struct_size;
GpencilModifierType type;
GpencilModifierTypeFlag flags;
/********************* Non-optional functions *********************/
/* Copy instance data for this modifier type. Should copy all user
* level settings to the target modifier.
*/
void (*copyData)(const struct GpencilModifierData *md, struct GpencilModifierData *target);
/* Callback for GP "stroke" modifiers that operate on the
* shape and parameters of the provided strokes (e.g. Thickness, Noise, etc.)
*
* The gpl parameter contains the GP layer that the strokes come from.
* While access is provided to this data, you should not directly access
* the gpl->frames data from the modifier. Instead, use the gpf parameter
* instead.
*
* The gps parameter contains the GP stroke to operate on. This is usually a copy
* of the original (unmodified and saved to files) stroke data.
*/
void (*deformStroke)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
struct Object *ob, struct bGPDlayer *gpl, struct bGPDstroke *gps);
/* Callback for GP "geometry" modifiers that create extra geometry
* in the frame (e.g. Array)
*
* The gpf parameter contains the GP frame/strokes to operate on. This is
* usually a copy of the original (unmodified and saved to files) stroke data.
* Modifiers should only add any generated strokes to this frame (and not one accessed
* via the gpl parameter).
*
* The modifier_index parameter indicates where the modifier is
* in the modifier stack in relation to other modifiers.
*/
void (*generateStrokes)(struct GpencilModifierData *md, struct Depsgraph *depsgraph,
struct Object *ob, struct bGPDlayer *gpl, struct bGPDframe *gpf);
/* Bake-down GP modifier's effects into the GP datablock.
*
* This gets called when the user clicks the "Apply" button in the UI.
* As such, this callback needs to go through all layers/frames in the
* datablock, mutating the geometry and/or creating new datablocks/objects
*/
void (*bakeModifier)(struct Main *bmain, struct Depsgraph *depsgraph,
struct GpencilModifierData *md, struct Object *ob);
/********************* Optional functions *********************/
/* Initialize new instance data for this modifier type, this function
* should set modifier variables to their default values.
*
* This function is optional.
*/
void (*initData)(struct GpencilModifierData *md);
/* Free internal modifier data variables, this function should
* not free the md variable itself.
*
* This function is optional.
*/
void (*freeData)(struct GpencilModifierData *md);
/* Return a boolean value indicating if this modifier is able to be
* calculated based on the modifier data. This is *not* regarding the
* md->flag, that is tested by the system, this is just if the data
* validates (for example, a lattice will return false if the lattice
* object is not defined).
*
* This function is optional (assumes never disabled if not present).
*/
bool (*isDisabled)(struct GpencilModifierData *md, int userRenderParams);
/* Add the appropriate relations to the dependency graph.
*
* This function is optional.
*/
void (*updateDepsgraph)(struct GpencilModifierData *md,
const struct ModifierUpdateDepsgraphContext *ctx);
/* Should return true if the modifier needs to be recalculated on time
* changes.
*
* This function is optional (assumes false if not present).
*/
bool (*dependsOnTime)(struct GpencilModifierData *md);
/* Should call the given walk function on with a pointer to each Object
* pointer that the modifier data stores. This is used for linking on file
* load and for unlinking objects or forwarding object references.
*
* This function is optional.
*/
void (*foreachObjectLink)(struct GpencilModifierData *md, struct Object *ob,
GreasePencilObjectWalkFunc walk, void *userData);
/* Should call the given walk function with a pointer to each ID
* pointer (i.e. each datablock pointer) that the modifier data
* stores. This is used for linking on file load and for
* unlinking datablocks or forwarding datablock references.
*
* This function is optional. If it is not present, foreachObjectLink
* will be used.
*/
void (*foreachIDLink)(struct GpencilModifierData *md, struct Object *ob,
GreasePencilIDWalkFunc walk, void *userData);
/* Should call the given walk function for each texture that the
* modifier data stores. This is used for finding all textures in
* the context for the UI.
*
* This function is optional. If it is not present, it will be
* assumed the modifier has no textures.
*/
void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob,
GreasePencilTexWalkFunc walk, void *userData);
} GpencilModifierTypeInfo;
void BKE_gpencil_instance_modifier_instance_tfm(struct InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4]);
/* Initialize modifier's global data (type info and some common global storages). */
void BKE_gpencil_modifier_init(void);
const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type);
struct GpencilModifierData *BKE_gpencil_modifier_new(int type);
void BKE_gpencil_modifier_free_ex(struct GpencilModifierData *md, const int flag);
void BKE_gpencil_modifier_free(struct GpencilModifierData *md);
bool BKE_gpencil_modifier_unique_name(struct ListBase *modifiers, struct GpencilModifierData *gmd);
bool BKE_gpencil_modifier_dependsOnTime(struct GpencilModifierData *md);
struct GpencilModifierData *BKE_gpencil_modifiers_findByType(struct Object *ob, GpencilModifierType type);
struct GpencilModifierData *BKE_gpencil_modifiers_findByName(struct Object *ob, const char *name);
void BKE_gpencil_modifier_copyData_generic(const struct GpencilModifierData *md_src, struct GpencilModifierData *md_dst);
void BKE_gpencil_modifier_copyData(struct GpencilModifierData *md, struct GpencilModifierData *target);
void BKE_gpencil_modifier_copyData_ex(struct GpencilModifierData *md, struct GpencilModifierData *target, const int flag);
void BKE_gpencil_modifiers_foreachIDLink(struct Object *ob, GreasePencilIDWalkFunc walk, void *userData);
void BKE_gpencil_modifiers_foreachTexLink(struct Object *ob, GreasePencilTexWalkFunc walk, void *userData);
bool BKE_gpencil_has_geometry_modifiers(struct Object *ob);
void BKE_gpencil_stroke_modifiers(
struct Depsgraph *depsgraph, struct Object *ob,
struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps, bool is_render);
void BKE_gpencil_geometry_modifiers(
struct Depsgraph *depsgraph, struct Object *ob,
struct bGPDlayer *gpl, struct bGPDframe *gpf, bool is_render);
void BKE_gpencil_lattice_init(struct Object *ob);
void BKE_gpencil_lattice_clear(struct Object *ob);
#endif /* __BKE_GPENCIL_MODIFIER_H__ */

@ -43,7 +43,10 @@ enum {
ICON_DATA_PREVIEW,
/** 2D triangles: obj is #Icon_Geom */
ICON_DATA_GEOM,
/** Studiolight */
ICON_DATA_STUDIOLIGHT,
/** GPencil Layer color preview (annotations): obj is #bGPDlayer */
ICON_DATA_GPLAYER,
};
struct Icon {
@ -79,6 +82,7 @@ struct ImBuf;
struct PreviewImage;
struct ID;
struct StudioLight;
struct bGPDlayer;
enum eIconSizes;
@ -87,6 +91,9 @@ void BKE_icons_init(int first_dyn_id);
/* return icon id for library object or create new icon if not found */
int BKE_icon_id_ensure(struct ID *id);
/* return icon id for Grease Pencil layer (color preview) or create new icon if not found */
int BKE_icon_gplayer_color_ensure(struct bGPDlayer *gpl);
int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview);
/* retrieve icon for id */

@ -54,7 +54,6 @@ void BKE_lattice_free(struct Lattice *lt);
void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool lib_local);
void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du);
struct LatticeDeformData;
struct LatticeDeformData *init_latt_deform(struct Object *oblatt, struct Object *ob) ATTR_WARN_UNUSED_RESULT;
void calc_latt_deform(struct LatticeDeformData *lattice_deform_data, float co[3], float weight);
void end_latt_deform(struct LatticeDeformData *lattice_deform_data);

@ -54,11 +54,13 @@ void BKE_material_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst);
struct Material *BKE_material_add(struct Main *bmain, const char *name);
struct Material *BKE_material_add_gpencil(struct Main *bmain, const char *name);
void BKE_material_copy_data(struct Main *bmain, struct Material *ma_dst, const struct Material *ma_src, const int flag);
struct Material *BKE_material_copy(struct Main *bmain, const struct Material *ma);
struct Material *BKE_material_localize(struct Material *ma);
struct Material *give_node_material(struct Material *ma); /* returns node material or self */
void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool lib_local);
void BKE_material_init_gpencil_settings(struct Material *ma);
/* UNUSED */
// void automatname(struct Material *);
@ -87,6 +89,8 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma
bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);

@ -37,8 +37,11 @@ extern "C" {
struct Base;
struct Depsgraph;
struct GpencilModifierData;
struct Scene;
struct ShaderFxData;
struct ViewLayer;
struct ID;
struct Object;
struct BoundBox;
struct View3D;
@ -49,6 +52,7 @@ struct Mesh;
struct RigidBodyWorld;
struct HookModifierData;
struct ModifierData;
struct HookGpencilModifierData;
#include "DNA_object_enums.h"
@ -69,11 +73,16 @@ void BKE_object_free_derived_mesh_caches(struct Object *ob);
void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob, struct HookGpencilModifierData *hmd);
bool BKE_object_modifier_gpencil_use_time(struct Object *ob, struct GpencilModifierData *md);
bool BKE_object_shaderfx_use_time(struct Object *ob, struct ShaderFxData *md);
bool BKE_object_support_modifier_type_check(const struct Object *ob, int modifier_type);
void BKE_object_link_modifiers(struct Scene *scene, struct Object *ob_dst, const struct Object *ob_src);
void BKE_object_free_modifiers(struct Object *ob, const int flag);
void BKE_object_free_shaderfx(struct Object *ob, const int flag);
void BKE_object_make_proxy(struct Main *bmain, struct Object *ob, struct Object *target, struct Object *gob);
void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target);
@ -108,6 +117,9 @@ struct Object *BKE_object_add_from(
struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer,
int type, const char *name, struct Object *ob_src)
ATTR_NONNULL(1, 2, 3, 6) ATTR_RETURNS_NONNULL;
struct Object *BKE_object_add_for_data(
struct Main *bmain, struct ViewLayer *view_layer,
int type, const char *name, struct ID *data, bool do_id_user) ATTR_RETURNS_NONNULL;
void *BKE_object_obdata_add_from_type(
struct Main *bmain,
int type, const char *name)

@ -77,7 +77,8 @@ typedef enum ePaintMode {
ePaintTextureProjective = 3,
ePaintTexture2D = 4,
ePaintSculptUV = 5,
ePaintInvalid = 6
ePaintInvalid = 6,
ePaintGpencil = 7
} ePaintMode;
/* overlay invalidation */

@ -0,0 +1,180 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is: all of this file.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __BKE_SHADER_FX_H__
#define __BKE_SHADER_FX_H__
/** \file BKE_shader_fx.h
* \ingroup bke
*/
#include "DNA_shader_fx_types.h" /* needed for all enum typdefs */
#include "BLI_compiler_attrs.h"
#include "BKE_customdata.h"
struct ID;
struct Depsgraph;
struct DerivedMesh;
struct Mesh;
struct Object;
struct Scene;
struct ViewLayer;
struct ListBase;
struct bArmature;
struct Main;
struct ShaderFxData;
struct DepsNodeHandle;
struct bGPDlayer;
struct bGPDframe;
struct bGPDstroke;
struct ModifierUpdateDepsgraphContext;
#define SHADER_FX_ACTIVE(_fx, _is_render) (((_fx->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \
((_fx->mode & eShaderFxMode_Render) && (_is_render == true)))
#define SHADER_FX_EDIT(_fx, _is_edit) (((_fx->mode & eShaderFxMode_Editmode) == 0) && (_is_edit))
typedef enum {
/* Should not be used, only for None type */
eShaderFxType_NoneType,
/* grease pencil effects */
eShaderFxType_GpencilType,
} ShaderFxTypeType;
typedef enum {
eShaderFxTypeFlag_SupportsEditmode = (1 << 0),
/* For effects that support editmode this determines if the
* effect should be enabled by default in editmode.
*/
eShaderFxTypeFlag_EnableInEditmode = (1 << 2),
/* max one per type */
eShaderFxTypeFlag_Single = (1 << 4),
/* can't be added manually by user */
eShaderFxTypeFlag_NoUserAdd = (1 << 5),
} ShaderFxTypeFlag;
/* IMPORTANT! Keep ObjectWalkFunc and IDWalkFunc signatures compatible. */
typedef void(*ShaderFxObjectWalkFunc)(void *userData, struct Object *ob, struct Object **obpoin, int cb_flag);
typedef void(*ShaderFxIDWalkFunc)(void *userData, struct Object *ob, struct ID **idpoin, int cb_flag);
typedef void(*ShaderFxTexWalkFunc)(void *userData, struct Object *ob, struct ShaderFxData *fx, const char *propname);
typedef struct ShaderFxTypeInfo {
/* The user visible name for this effect */
char name[32];
/* The DNA struct name for the effect data type, used to
* write the DNA data out.
*/
char struct_name[32];
/* The size of the effect data type, used by allocation. */
int struct_size;
ShaderFxTypeType type;
ShaderFxTypeFlag flags;
/* Copy instance data for this effect type. Should copy all user
* level settings to the target effect.
*/
void(*copyData)(const struct ShaderFxData *fx, struct ShaderFxData *target);
/* Initialize new instance data for this effect type, this function
* should set effect variables to their default values.
*
* This function is optional.
*/
void (*initData)(struct ShaderFxData *fx);
/* Free internal effect data variables, this function should
* not free the fx variable itself.
*
* This function is optional.
*/
void (*freeData)(struct ShaderFxData *fx);
/* Return a boolean value indicating if this effect is able to be
* calculated based on the effect data. This is *not* regarding the
* fx->flag, that is tested by the system, this is just if the data
* validates (for example, a lattice will return false if the lattice
* object is not defined).
*
* This function is optional (assumes never disabled if not present).
*/
bool (*isDisabled)(struct ShaderFxData *fx, int userRenderParams);
/* Add the appropriate relations to the dependency graph.
*
* This function is optional.
*/
void (*updateDepsgraph)(struct ShaderFxData *fx,
const struct ModifierUpdateDepsgraphContext *ctx);
/* Should return true if the effect needs to be recalculated on time
* changes.
*
* This function is optional (assumes false if not present).
*/
bool (*dependsOnTime)(struct ShaderFxData *fx);
/* Should call the given walk function on with a pointer to each Object
* pointer that the effect data stores. This is used for linking on file
* load and for unlinking objects or forwarding object references.
*
* This function is optional.
*/
void (*foreachObjectLink)(struct ShaderFxData *fx, struct Object *ob,
ShaderFxObjectWalkFunc walk, void *userData);
/* Should call the given walk function with a pointer to each ID
* pointer (i.e. each datablock pointer) that the effect data
* stores. This is used for linking on file load and for
* unlinking datablocks or forwarding datablock references.
*
* This function is optional. If it is not present, foreachObjectLink
* will be used.
*/
void (*foreachIDLink)(struct ShaderFxData *fx, struct Object *ob,
ShaderFxIDWalkFunc walk, void *userData);
} ShaderFxTypeInfo;
/* Initialize global data (type info and some common global storages). */
void BKE_shaderfx_init(void);
const ShaderFxTypeInfo *BKE_shaderfxType_getInfo(ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_new(int type);
void BKE_shaderfx_free_ex(struct ShaderFxData *fx, const int flag);
void BKE_shaderfx_free(struct ShaderFxData *fx);
bool BKE_shaderfx_unique_name(struct ListBase *shaderfx, struct ShaderFxData *fx);
bool BKE_shaderfx_dependsOnTime(struct ShaderFxData *fx);
struct ShaderFxData *BKE_shaderfx_findByType(struct Object *ob, ShaderFxType type);
struct ShaderFxData *BKE_shaderfx_findByName(struct Object *ob, const char *name);
void BKE_shaderfx_copyData_generic(const struct ShaderFxData *fx_src, struct ShaderFxData *fx_dst);
void BKE_shaderfx_copyData(struct ShaderFxData *fx, struct ShaderFxData *target);
void BKE_shaderfx_copyData_ex(struct ShaderFxData *fx, struct ShaderFxData *target, const int flag);
void BKE_shaderfx_foreachIDLink(struct Object *ob, ShaderFxIDWalkFunc walk, void *userData);
bool BKE_shaderfx_has_gpencil(struct Object *ob);
#endif /* __BKE_SHADER_FX_H__ */

@ -38,6 +38,8 @@ set(INC
../makesrna
../bmesh
../modifiers
../gpencil_modifiers
../shader_fx
../nodes
../physics
../render/extern/include
@ -115,6 +117,7 @@ set(SRC
intern/font.c
intern/freestyle.c
intern/gpencil.c
intern/gpencil_modifier.c
intern/icons.c
intern/icons_rasterize.c
intern/idcode.c
@ -180,6 +183,7 @@ set(SRC
intern/seqeffects.c
intern/seqmodifier.c
intern/sequencer.c
intern/shader_fx.c
intern/shrinkwrap.c
intern/smoke.c
intern/softbody.c
@ -259,6 +263,7 @@ set(SRC
BKE_freestyle.h
BKE_global.h
BKE_gpencil.h
BKE_gpencil_modifier.h
BKE_icons.h
BKE_idcode.h
BKE_idprop.h
@ -306,6 +311,7 @@ set(SRC
BKE_scene.h
BKE_screen.h
BKE_sequencer.h
BKE_shader_fx.h
BKE_shrinkwrap.h
BKE_smoke.h
BKE_softbody.h

@ -104,6 +104,7 @@ bool id_type_can_have_animdata(const short id_type)
case ID_MSK:
case ID_GD:
case ID_CF:
case ID_PAL:
return true;
/* no AnimData */
@ -1150,6 +1151,9 @@ void BKE_animdata_main_cb(Main *bmain, ID_AnimData_Edit_Callback func, void *use
/* grease pencil */
ANIMDATA_IDS_CB(bmain->gpencil.first);
/* palettes */
ANIMDATA_IDS_CB(bmain->palettes.first);
/* cache files */
ANIMDATA_IDS_CB(bmain->cachefiles.first);
}
@ -2925,6 +2929,9 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, Scene
/* grease pencil */
EVAL_ANIM_IDS(main->gpencil.first, ADT_RECALC_ANIM);
/* palettes */
EVAL_ANIM_IDS(main->palettes.first, ADT_RECALC_ANIM);
/* cache files */
EVAL_ANIM_IDS(main->cachefiles.first, ADT_RECALC_ANIM);

@ -29,6 +29,7 @@
#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@ -36,6 +37,7 @@
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
@ -129,6 +131,7 @@ static void brush_defaults(Brush *brush)
brush->stencil_dimension[0] = 256;
brush->stencil_dimension[1] = 256;
}
/* Datablock add/copy/free/make_local */
@ -164,6 +167,368 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
return brush;
}
/* add a new gp-brush */
Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name)
{
Brush *brush;
Paint *paint = BKE_brush_get_gpencil_paint(ts);
brush = BKE_brush_add(bmain, name, OB_MODE_GPENCIL_PAINT);
BKE_paint_brush_set(paint, brush);
id_us_min(&brush->id);
/* grease pencil basic settings */
brush->size = 3;
brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->flag = 0;
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
/* curves */
brush->gpencil_settings->curve_sensitivity = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
brush->gpencil_settings->curve_strength = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
brush->gpencil_settings->curve_jitter = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
/* return brush */
return brush;
}
Paint *BKE_brush_get_gpencil_paint(ToolSettings *ts)
{
/* alloc paint session */
if (ts->gp_paint == NULL) {
ts->gp_paint = MEM_callocN(sizeof(GpPaint), "GpPaint");
}
return &ts->gp_paint->paint;
}
/* grease pencil cumapping->preset */
typedef enum eGPCurveMappingPreset {
GPCURVE_PRESET_PENCIL = 0,
GPCURVE_PRESET_INK = 1,
GPCURVE_PRESET_INKNOISE = 2,
} eGPCurveMappingPreset;
static void brush_gpencil_curvemap_reset(CurveMap *cuma, int preset)
{
if (cuma->curve)
MEM_freeN(cuma->curve);
cuma->totpoint = 3;
cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
switch (preset) {
case GPCURVE_PRESET_PENCIL:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
cuma->curve[1].x = 0.75115f;
cuma->curve[1].y = 0.25f;
cuma->curve[2].x = 1.0f;
cuma->curve[2].y = 1.0f;
break;
case GPCURVE_PRESET_INK:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
cuma->curve[1].x = 0.63448f;
cuma->curve[1].y = 0.375f;
cuma->curve[2].x = 1.0f;
cuma->curve[2].y = 1.0f;
break;
case GPCURVE_PRESET_INKNOISE:
cuma->curve[0].x = 0.0f;
cuma->curve[0].y = 0.0f;
cuma->curve[1].x = 0.63134f;
cuma->curve[1].y = 0.3625f;
cuma->curve[2].x = 1.0f;
cuma->curve[2].y = 1.0f;
break;
}
if (cuma->table) {
MEM_freeN(cuma->table);
cuma->table = NULL;
}
}
/* create a set of grease pencil presets */
void BKE_brush_gpencil_presets(bContext *C)
{
#define SMOOTH_STROKE_RADIUS 40
#define SMOOTH_STROKE_FACTOR 0.9f
ToolSettings *ts = CTX_data_tool_settings(C);
Paint *paint = BKE_brush_get_gpencil_paint(ts);
Main *bmain = CTX_data_main(C);
Brush *brush, *deft;
CurveMapping *custom_curve;
/* Pencil brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pencil");
brush->size = 25.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 0.6f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
brush->gpencil_settings->draw_random_press = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.5f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PENCIL;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
/* Pen brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Draw Pen");
deft = brush; /* save default brush */
brush->size = 30.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
brush->gpencil_settings->draw_random_press = 0.0f;
brush->gpencil_settings->draw_random_strength = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.5f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
/* Ink brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Draw Ink");
brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
brush->gpencil_settings->draw_sensitivity = 1.6f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->draw_random_press = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.5f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INK;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
/* Curve */
custom_curve = brush->gpencil_settings->curve_sensitivity;
curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
curvemapping_initialize(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INK);
/* Ink Noise brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Draw Noise");
brush->size = 60.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
brush->gpencil_settings->draw_random_press = 0.7f;
brush->gpencil_settings->draw_random_strength = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 1.0f;
brush->gpencil_settings->draw_smoothlvl = 2;
brush->gpencil_settings->thick_smoothfac = 0.5f;
brush->gpencil_settings->thick_smoothlvl = 2;
brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_INKNOISE;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
/* Curve */
custom_curve = brush->gpencil_settings->curve_sensitivity;
curvemapping_set_defaults(custom_curve, 0, 0.0f, 0.0f, 1.0f, 1.0f);
curvemapping_initialize(custom_curve);
brush_gpencil_curvemap_reset(custom_curve->cm, GPCURVE_PRESET_INKNOISE);
/* Block Basic brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Draw Block");
brush->size = 150.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 0.7f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_STENGTH_PRESSURE;
brush->gpencil_settings->draw_random_press = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_angle = 0.0f;
brush->gpencil_settings->draw_angle_factor = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.0f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 0;
brush->gpencil_settings->draw_random_sub = 0;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_BLOCK;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
/* Marker brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Draw Marker");
brush->size = 80.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_USE_PRESSURE | GP_BRUSH_ENABLE_CURSOR);
brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->draw_strength = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_RANDOM;
brush->gpencil_settings->draw_random_press = 0.374f;
brush->gpencil_settings->draw_random_strength = 0.0f;
brush->gpencil_settings->draw_jitter = 0.0f;
brush->gpencil_settings->flag |= GP_BRUSH_USE_JITTER_PRESSURE;
brush->gpencil_settings->draw_angle = M_PI_4; /* 45 degrees */
brush->gpencil_settings->draw_angle_factor = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_GROUP_SETTINGS;
brush->gpencil_settings->draw_smoothfac = 0.5f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 1;
brush->gpencil_settings->draw_random_sub = 0.0f;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_MARKER;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_DRAW;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
/* Fill brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Fill Area");
brush->size = 1.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
brush->gpencil_settings->draw_sensitivity = 1.0f;
brush->gpencil_settings->fill_leak = 3;
brush->gpencil_settings->fill_threshold = 0.1f;
brush->gpencil_settings->fill_simplylvl = 1;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_FILL;
brush->gpencil_settings->draw_smoothfac = 0.5f;
brush->gpencil_settings->draw_smoothlvl = 1;
brush->gpencil_settings->thick_smoothfac = 1.0f;
brush->gpencil_settings->thick_smoothlvl = 3;
brush->gpencil_settings->draw_subdivide = 1;
brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS;
brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR;
brush->gpencil_settings->draw_strength = 1.0f;
/* Soft Eraser brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Soft");
brush->size = 30.0f;
brush->gpencil_settings->flag |= (GP_BRUSH_ENABLE_CURSOR | GP_BRUSH_DEFAULT_ERASER);
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_SOFT;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_SOFT;
/* Hard Eraser brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Hard");
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_HARD;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_HARD;
/* Stroke Eraser brush */
brush = BKE_brush_add_gpencil(bmain, ts, "Eraser Stroke");
brush->size = 30.0f;
brush->gpencil_settings->flag |= GP_BRUSH_ENABLE_CURSOR;
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_ERASE_STROKE;
brush->gpencil_settings->brush_type = GP_BRUSH_TYPE_ERASE;
brush->gpencil_settings->eraser_mode = GP_BRUSH_ERASER_STROKE;
/* set defaut brush */
BKE_paint_brush_set(paint, deft);
}
/* get the active gp-brush for editing */
Brush *BKE_brush_getactive_gpencil(ToolSettings *ts)
{
/* error checking */
if (ELEM(NULL, ts, ts->gp_paint)) {
return NULL;
}
Paint *paint = &ts->gp_paint->paint;
return paint->brush;
}
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
Brush *brush;
@ -197,6 +562,12 @@ void BKE_brush_copy_data(Main *UNUSED(bmain), Brush *brush_dst, const Brush *bru
}
brush_dst->curve = curvemapping_copy(brush_src->curve);
if (brush_src->gpencil_settings != NULL) {
brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
brush_dst->gpencil_settings->curve_sensitivity = curvemapping_copy(brush_src->gpencil_settings->curve_sensitivity);
brush_dst->gpencil_settings->curve_strength = curvemapping_copy(brush_src->gpencil_settings->curve_strength);
brush_dst->gpencil_settings->curve_jitter = curvemapping_copy(brush_src->gpencil_settings->curve_jitter);
}
/* enable fake user by default */
id_fake_user_set(&brush_dst->id);
@ -215,11 +586,18 @@ void BKE_brush_free(Brush *brush)
if (brush->icon_imbuf) {
IMB_freeImBuf(brush->icon_imbuf);
}
curvemapping_free(brush->curve);
if (brush->gpencil_settings != NULL) {
curvemapping_free(brush->gpencil_settings->curve_sensitivity);
curvemapping_free(brush->gpencil_settings->curve_strength);
curvemapping_free(brush->gpencil_settings->curve_jitter);
MEM_SAFE_FREE(brush->gpencil_settings);
}
MEM_SAFE_FREE(brush->gradient);
BKE_previewimg_free(&(brush->preview));
}

@ -282,6 +282,7 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
case CURVE_PRESET_MID9: cuma->totpoint = 9; break;
case CURVE_PRESET_ROUND: cuma->totpoint = 4; break;
case CURVE_PRESET_ROOT: cuma->totpoint = 4; break;
case CURVE_PRESET_GAUSS: cuma->totpoint = 7; break;
}
cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), "curve points");
@ -352,6 +353,24 @@ void curvemap_reset(CurveMap *cuma, const rctf *clipr, int preset, int slope)
cuma->curve[3].x = 1;
cuma->curve[3].y = 0;
break;
case CURVE_PRESET_GAUSS:
cuma->curve[0].x = 0;
cuma->curve[0].y = 0.025f;
cuma->curve[1].x = 0.16f;
cuma->curve[1].y = 0.135f;
cuma->curve[2].x = 0.298f;
cuma->curve[2].y = 0.36f;
cuma->curve[3].x = 0.50f;
cuma->curve[3].y = 1.0f;
cuma->curve[4].x = 0.70f;
cuma->curve[4].y = 0.36f;
cuma->curve[5].x = 0.84f;
cuma->curve[5].y = 0.135f;
cuma->curve[6].x = 1.0f;
cuma->curve[6].y = 0.025f;
break;
}
/* mirror curve in x direction to have positive slope

@ -1014,6 +1014,10 @@ int CTX_data_mode_enum_ex(const Object *obedit, const Object *ob, const eObjectM
else if (object_mode & OB_MODE_VERTEX_PAINT) return CTX_MODE_PAINT_VERTEX;
else if (object_mode & OB_MODE_TEXTURE_PAINT) return CTX_MODE_PAINT_TEXTURE;
else if (object_mode & OB_MODE_PARTICLE_EDIT) return CTX_MODE_PARTICLE;
else if (object_mode & OB_MODE_GPENCIL_PAINT) return CTX_MODE_GPENCIL_PAINT;
else if (object_mode & OB_MODE_GPENCIL_EDIT) return CTX_MODE_GPENCIL_EDIT;
else if (object_mode & OB_MODE_GPENCIL_SCULPT) return CTX_MODE_GPENCIL_SCULPT;
else if (object_mode & OB_MODE_GPENCIL_WEIGHT) return CTX_MODE_GPENCIL_WEIGHT;
}
}
@ -1044,6 +1048,10 @@ static const char *data_mode_strings[] = {
"imagepaint",
"particlemode",
"objectmode",
"greasepencil_paint",
"greasepencil_edit",
"greasepencil_sculpt",
"greasepencil_weight",
NULL
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1, "Must have a string for each context mode")
@ -1212,17 +1220,7 @@ bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
return ctx_data_pointer_get(C, "active_gpencil_layer");
}
bGPDpalette *CTX_data_active_gpencil_palette(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_palette");
}
bGPDpalettecolor *CTX_data_active_gpencil_palettecolor(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_palettecolor");
}
bGPDbrush *CTX_data_active_gpencil_brush(const bContext *C)
Brush *CTX_data_active_gpencil_brush(const bContext *C)
{
return ctx_data_pointer_get(C, "active_gpencil_brush");
}

@ -74,7 +74,9 @@ bDeformGroup *BKE_defgroup_new(Object *ob, const char *name)
BLI_addtail(&ob->defbase, defgroup);
defgroup_unique_name(defgroup, ob);
BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
if (ob->type != OB_GPENCIL) {
BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
}
return defgroup;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,679 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2017, Blender Foundation
* This is a new part of Blender
*
* Contributor(s): Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/blenkernel/intern/gpencil_modifier.c
* \ingroup bke
*/
#include <stdio.h>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
#include "BLI_string_utils.h"
#include "BLT_translation.h"
#include "DNA_meshdata_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_library_query.h"
#include "BKE_gpencil.h"
#include "BKE_lattice.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "MOD_gpencil_modifiertypes.h"
static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL };
/* *************************************************** */
/* Geometry Utilities */
/* calculate stroke normal using some points */
void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
{
if (gps->totpoints < 3) {
zero_v3(r_normal);
return;
}
bGPDspoint *points = gps->points;
int totpoints = gps->totpoints;
const bGPDspoint *pt0 = &points[0];
const bGPDspoint *pt1 = &points[1];
const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
float vec1[3];
float vec2[3];
/* initial vector (p0 -> p1) */
sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
/* point vector at 3/4 */
sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
/* vector orthogonal to polygon plane */
cross_v3_v3v3(r_normal, vec1, vec2);
/* Normalize vector */
normalize_v3(r_normal);
}
/* Get points of stroke always flat to view not affected by camera view or view position */
static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d)
{
const bGPDspoint *pt0 = &points[0];
const bGPDspoint *pt1 = &points[1];
const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
float locx[3];
float locy[3];
float loc3[3];
float normal[3];
/* local X axis (p0 -> p1) */
sub_v3_v3v3(locx, &pt1->x, &pt0->x);
/* point vector at 3/4 */
sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
/* vector orthogonal to polygon plane */
cross_v3_v3v3(normal, locx, loc3);
/* local Y axis (cross to normal/x axis) */
cross_v3_v3v3(locy, normal, locx);
/* Normalize vectors */
normalize_v3(locx);
normalize_v3(locy);
/* Get all points in local space */
for (int i = 0; i < totpoints; i++) {
const bGPDspoint *pt = &points[i];
float loc[3];
/* Get local space using first point as origin */
sub_v3_v3v3(loc, &pt->x, &pt0->x);
vec2f *point = &points2d[i];
point->x = dot_v3v3(loc, locx);
point->y = dot_v3v3(loc, locy);
}
}
/* Stroke Simplify ------------------------------------- */
/* Reduce a series of points to a simplified version, but
* maintains the general shape of the series
*
* Ramer - Douglas - Peucker algorithm
* by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
*/
static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon)
{
vec2f *old_points2d = points2d;
int totpoints = gps->totpoints;
char *marked = NULL;
char work;
int start = 1;
int end = gps->totpoints - 2;
marked = MEM_callocN(totpoints, "GP marked array");
marked[start] = 1;
marked[end] = 1;
work = 1;
int totmarked = 0;
/* while still reducing */
while (work) {
int ls, le;
work = 0;
ls = start;
le = start + 1;
/* while not over interval */
while (ls < end) {
int max_i = 0;
float v1[2];
/* divided to get more control */
float max_dist = epsilon / 10.0f;
/* find the next marked point */
while (marked[le] == 0) {
le++;
}
/* perpendicular vector to ls-le */
v1[1] = old_points2d[le].x - old_points2d[ls].x;
v1[0] = old_points2d[ls].y - old_points2d[le].y;
for (int i = ls + 1; i < le; i++) {
float mul;
float dist;
float v2[2];
v2[0] = old_points2d[i].x - old_points2d[ls].x;
v2[1] = old_points2d[i].y - old_points2d[ls].y;
if (v2[0] == 0 && v2[1] == 0) {
continue;
}
mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
if (dist > max_dist) {
max_dist = dist;
max_i = i;
}
}
if (max_i != 0) {
work = 1;
marked[max_i] = 1;
totmarked++;
}
ls = le;
le = ls + 1;
}
}
/* adding points marked */
bGPDspoint *old_points = MEM_dupallocN(gps->points);
MDeformVert *old_dvert = MEM_dupallocN(gps->dvert);
/* resize gps */
gps->flag |= GP_STROKE_RECALC_CACHES;
gps->tot_triangles = 0;
int j = 0;
for (int i = 0; i < totpoints; i++) {
bGPDspoint *pt_src = &old_points[i];
bGPDspoint *pt = &gps->points[j];
MDeformVert *dvert_src = &old_dvert[i];
MDeformVert *dvert = &gps->dvert[j];
if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
memcpy(pt, pt_src, sizeof(bGPDspoint));
memcpy(dvert, dvert_src, sizeof(MDeformVert));
j++;
}
else {
BKE_gpencil_free_point_weights(dvert_src);
}
}
gps->totpoints = j;
MEM_SAFE_FREE(old_points);
MEM_SAFE_FREE(old_dvert);
MEM_SAFE_FREE(marked);
}
/* Simplify stroke using Ramer-Douglas-Peucker algorithm */
void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor)
{
/* first create temp data and convert points to 2D */
vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
gpencil_rdp_stroke(gps, points2d, factor);
MEM_SAFE_FREE(points2d);
}
/* Simplify alternate vertex of stroke except extrems */
void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
{
if (gps->totpoints < 5) {
return;
}
/* save points */
bGPDspoint *old_points = MEM_dupallocN(gps->points);
MDeformVert *old_dvert = MEM_dupallocN(gps->dvert);
/* resize gps */
int newtot = (gps->totpoints - 2) / 2;
if (((gps->totpoints - 2) % 2) > 0) {
newtot++;
}
newtot += 2;
gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
gps->flag |= GP_STROKE_RECALC_CACHES;
gps->tot_triangles = 0;
int j = 0;
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt_src = &old_points[i];
bGPDspoint *pt = &gps->points[j];
MDeformVert *dvert_src = &old_dvert[i];
MDeformVert *dvert = &gps->dvert[j];
if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
memcpy(pt, pt_src, sizeof(bGPDspoint));
memcpy(dvert, dvert_src, sizeof(MDeformVert));
j++;
}
else {
BKE_gpencil_free_point_weights(dvert_src);
}
}
gps->totpoints = j;
MEM_SAFE_FREE(old_points);
MEM_SAFE_FREE(old_dvert);
}
/* *************************************************** */
/* Modifier Utilities */
/* Lattice Modifier ---------------------------------- */
/* Usually, evaluation of the lattice modifier is self-contained.
* However, since GP's modifiers operate on a per-stroke basis,
* we need to these two extra functions that called before/after
* each loop over all the geometry being evaluated.
*/
/* init lattice deform data */
void BKE_gpencil_lattice_init(Object *ob)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
if (md->type == eGpencilModifierType_Lattice) {
LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
Object *latob = NULL;
latob = mmd->object;
if ((!latob) || (latob->type != OB_LATTICE)) {
return;
}
if (mmd->cache_data) {
end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
}
/* init deform data */
mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
}
}
}
/* clear lattice deform data */
void BKE_gpencil_lattice_clear(Object *ob)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
if (md->type == eGpencilModifierType_Lattice) {
LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
if ((mmd) && (mmd->cache_data)) {
end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
mmd->cache_data = NULL;
}
}
}
}
/* *************************************************** */
/* Modifier Methods - Evaluation Loops, etc. */
/* check if exist geometry modifiers */
bool BKE_gpencil_has_geometry_modifiers(Object *ob)
{
GpencilModifierData *md;
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
if (mti && mti->generateStrokes) {
return true;
}
}
return false;
}
/* apply stroke modifiers */
void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render)
{
GpencilModifierData *md;
bGPdata *gpd = ob->data;
const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
if (GPENCIL_MODIFIER_ACTIVE(md, is_render))
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
continue;
}
if (mti && mti->deformStroke) {
mti->deformStroke(md, depsgraph, ob, gpl, gps);
}
}
}
}
/* apply stroke geometry modifiers */
void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render)
{
GpencilModifierData *md;
bGPdata *gpd = ob->data;
const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
if (GPENCIL_MODIFIER_ACTIVE(md, is_render))
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
continue;
}
if (mti->generateStrokes) {
mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
}
}
}
}
/* *************************************************** */
void BKE_gpencil_eval_geometry(Depsgraph *depsgraph,
bGPdata *gpd)
{
DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
int ctime = (int)DEG_get_ctime(depsgraph);
/* update active frame */
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
}
/* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
* This would be better than inventing our own logic for this stuff...
*/
/* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
* later when there's more happening here. For now, let's just keep this in here to avoid
* needing to have one more node slowing down evaluation...
*/
if (DEG_is_active(depsgraph)) {
bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
/* sync "actframe" changes back to main-db too,
* so that editing tools work with copy-on-write
* when the current frame changes
*/
for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) {
gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
}
}
}
void BKE_gpencil_modifier_init(void)
{
/* Initialize modifier types */
gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
}
GpencilModifierData *BKE_gpencil_modifier_new(int type)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
/* note, this name must be made unique later */
BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
md->type = type;
md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded;
md->flag = eGpencilModifierFlag_StaticOverride_Local;
if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
md->mode |= eGpencilModifierMode_Editmode;
if (mti->initData) mti->initData(md);
return md;
}
static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
{
ID *id = *idpoin;
if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
id_us_min(id);
}
}
void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (mti->foreachIDLink) {
mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
}
else if (mti->foreachObjectLink) {
mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
}
}
if (mti->freeData) mti->freeData(md);
if (md->error) MEM_freeN(md->error);
MEM_freeN(md);
}
void BKE_gpencil_modifier_free(GpencilModifierData *md)
{
BKE_gpencil_modifier_free_ex(md, 0);
}
/* check unique name */
bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
{
if (modifiers && gmd) {
const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name));
}
return false;
}
bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
return mti->dependsOnTime && mti->dependsOnTime(md);
}
const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
{
/* type unsigned, no need to check < 0 */
if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
return modifier_gpencil_types[type];
}
else {
return NULL;
}
}
void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
/* md_dst may have alredy be fully initialized with some extra allocated data,
* we need to free it now to avoid memleak. */
if (mti->freeData) {
mti->freeData(md_dst);
}
const size_t data_size = sizeof(GpencilModifierData);
const char *md_src_data = ((const char *)md_src) + data_size;
char *md_dst_data = ((char *)md_dst) + data_size;
BLI_assert(data_size <= (size_t)mti->struct_size);
memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
}
static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
{
ID *id = *idpoin;
if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
id_us_plus(id);
}
}
void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag)
{
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
target->mode = md->mode;
target->flag = md->flag;
if (mti->copyData) {
mti->copyData(md, target);
}
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
if (mti->foreachIDLink) {
mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
}
else if (mti->foreachObjectLink) {
mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
}
}
}
void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
{
BKE_gpencil_modifier_copyData_ex(md, target, 0);
}
GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
for (; md; md = md->next)
if (md->type == type)
break;
return md;
}
void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
for (; md; md = md->next) {
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
if (mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
else if (mti->foreachObjectLink) {
/* each Object can masquerade as an ID, so this should be OK */
GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
mti->foreachObjectLink(md, ob, fp, userData);
}
}
}
void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
{
GpencilModifierData *md = ob->greasepencil_modifiers.first;
for (; md; md = md->next) {
const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
if (mti->foreachTexLink)
mti->foreachTexLink(md, ob, walk, userData);
}
}
GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
{
return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
}
/* helper function for per-instance positioning */
void BKE_gpencil_instance_modifier_instance_tfm(InstanceGpencilModifierData *mmd, const int elem_idx[3], float r_mat[4][4])
{
float offset[3], rot[3], scale[3];
int ri = mmd->rnd[0];
float factor;
offset[0] = mmd->offset[0] * elem_idx[0];
offset[1] = mmd->offset[1] * elem_idx[1];
offset[2] = mmd->offset[2] * elem_idx[2];
/* rotation */
if (mmd->flag & GP_INSTANCE_RANDOM_ROT) {
factor = mmd->rnd_rot * mmd->rnd[ri];
mul_v3_v3fl(rot, mmd->rot, factor);
add_v3_v3(rot, mmd->rot);
}
else {
copy_v3_v3(rot, mmd->rot);
}
/* scale */
if (mmd->flag & GP_INSTANCE_RANDOM_SIZE) {
factor = mmd->rnd_size * mmd->rnd[ri];
mul_v3_v3fl(scale, mmd->scale, factor);
add_v3_v3(scale, mmd->scale);
}
else {
copy_v3_v3(scale, mmd->scale);
}
/* advance random index */
mmd->rnd[0]++;
if (mmd->rnd[0] > 19) {
mmd->rnd[0] = 1;
}
/* calculate matrix */
loc_eul_size_to_mat4(r_mat, offset, rot, scale);
}

@ -37,6 +37,8 @@
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@ -45,7 +47,6 @@
#include "DNA_screen_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "DNA_brush_types.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@ -127,6 +128,9 @@ static void icon_free_data(int icon_id, Icon *icon)
else if (icon->obj_type == ICON_DATA_PREVIEW) {
((PreviewImage *)(icon->obj))->icon_id = 0;
}
else if (icon->obj_type == ICON_DATA_GPLAYER) {
((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
}
else if (icon->obj_type == ICON_DATA_GEOM) {
((struct Icon_Geom *)(icon->obj))->icon_id = 0;
}
@ -598,6 +602,44 @@ int BKE_icon_id_ensure(struct ID *id)
return icon_id_ensure_create_icon(id);
}
static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl)
{
BLI_assert(BLI_thread_is_main());
/* NOTE: The color previews for GP Layers don't really need
* to be "rendered" to image per se (as it will just be a plain
* colored rectangle), we need to define icon data here so that
* we can store a pointer to the layer data in icon->obj.
*/
Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
icon->flag = ICON_FLAG_MANAGED;
return gpl->runtime.icon_id;
}
int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
{
/* Never handle icons in non-main thread! */
BLI_assert(BLI_thread_is_main());
if (!gpl || G.background) {
return 0;
}
if (gpl->runtime.icon_id)
return gpl->runtime.icon_id;
gpl->runtime.icon_id = get_next_free_id();
if (!gpl->runtime.icon_id) {
printf("%s: Internal error - not enough IDs\n", __func__);
return 0;
}
return icon_gplayer_color_ensure_create_icon(gpl);
}
/**
* Return icon id of given preview, or create new icon if not found.
*/

@ -1073,6 +1073,7 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[INDEX_ID_IP] = &(main->ipo);
lb[INDEX_ID_AC] = &(main->action); /* moved here to avoid problems when freeing with animato (aligorith) */
lb[INDEX_ID_KE] = &(main->key);
lb[INDEX_ID_PAL] = &(main->palettes); /* referenced by gpencil, so needs to be before that to avoid crashes */
lb[INDEX_ID_GD] = &(main->gpencil); /* referenced by nodes, objects, view, scene etc, before to free after. */
lb[INDEX_ID_NT] = &(main->nodetree);
lb[INDEX_ID_IM] = &(main->image);

@ -417,7 +417,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
SEQ_END
}
CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER);
for (CollectionObject *cob = scene->master_collection->gobject.first; cob; cob = cob->next) {
CALLBACK_INVOKE(cob->ob, IDWALK_CB_USER);
@ -478,6 +477,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (toolsett->uvsculpt) {
library_foreach_paint(&data, &toolsett->uvsculpt->paint);
}
if (toolsett->gp_paint) {
library_foreach_paint(&data, &toolsett->gp_paint->paint);
}
}
if (scene->rigidbody_world) {
@ -641,6 +643,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
if (material->texpaintslot != NULL) {
CALLBACK_INVOKE(material->texpaintslot->ima, IDWALK_CB_NOP);
}
if (material->gp_style != NULL) {
CALLBACK_INVOKE(material->gp_style->sima, IDWALK_CB_USER);
CALLBACK_INVOKE(material->gp_style->ima, IDWALK_CB_USER);
}
break;
}
@ -758,6 +764,9 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP);
CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER);
if (brush->gpencil_settings) {
CALLBACK_INVOKE(brush->gpencil_settings->material, IDWALK_CB_USER);
}
library_foreach_mtex(&data, &brush->mtex);
library_foreach_mtex(&data, &brush->mask_mtex);
break;
@ -941,10 +950,15 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
case ID_GD:
{
bGPdata *gpencil = (bGPdata *) id;
/* materials */
for (i = 0; i < gpencil->totcol; i++) {
CALLBACK_INVOKE(gpencil->mat[i], IDWALK_CB_USER);
}
for (bGPDlayer *gp_layer = gpencil->layers.first; gp_layer; gp_layer = gp_layer->next) {
CALLBACK_INVOKE(gp_layer->parent, IDWALK_CB_NOP);
for (bGPDlayer *gplayer = gpencil->layers.first; gplayer != NULL; gplayer = gplayer->next) {
CALLBACK_INVOKE(gplayer->parent, IDWALK_CB_NOP);
}
break;
}
@ -1072,7 +1086,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return true;
#endif
case ID_BR:
return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE);
return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE, ID_MA);
case ID_PA:
return ELEM(id_type_used, ID_OB, ID_GR, ID_TE);
case ID_MC:
@ -1083,6 +1097,8 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
return (ELEM(id_type_used, ID_TE, ID_OB));
case ID_LP:
return ELEM(id_type_used, ID_IM);
case ID_GD:
return ELEM(id_type_used, ID_MA);
case ID_WS:
return ELEM(id_type_used, ID_SCR, ID_SCE);
case ID_IM:
@ -1091,7 +1107,6 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_SO:
case ID_AR:
case ID_AC:
case ID_GD:
case ID_WM:
case ID_PAL:
case ID_PC:

@ -43,6 +43,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_customdata_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_ID.h"
#include "DNA_meta_types.h"
#include "DNA_node_types.h"
@ -58,6 +59,7 @@
#include "BKE_animsys.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_library.h"
@ -103,10 +105,30 @@ void BKE_material_free(Material *ma)
MEM_SAFE_FREE(ma->texpaintslot);
MEM_SAFE_FREE(ma->gp_style);
BKE_icon_id_delete((ID *)ma);
BKE_previewimg_free(&ma->preview);
}
void BKE_material_init_gpencil_settings(Material *ma)
{
if ((ma) && (ma->gp_style == NULL)) {
ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings");
MaterialGPencilStyle *gp_style = ma->gp_style;
/* set basic settings */
gp_style->stroke_rgba[3] = 1.0f;
gp_style->pattern_gridsize = 0.1f;
gp_style->gradient_radius = 0.5f;
ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
gp_style->texture_opacity = 1.0f;
gp_style->texture_pixsize = 100.0f;
}
}
void BKE_material_init(Material *ma)
{
BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id));
@ -124,6 +146,7 @@ void BKE_material_init(Material *ma)
ma->preview = NULL;
ma->alpha_threshold = 0.5f;
}
Material *BKE_material_add(Main *bmain, const char *name)
@ -137,6 +160,19 @@ Material *BKE_material_add(Main *bmain, const char *name)
return ma;
}
Material *BKE_material_add_gpencil(Main *bmain, const char *name)
{
Material *ma;
ma = BKE_material_add(bmain, name);
/* grease pencil settings */
BKE_material_init_gpencil_settings(ma);
return ma;
}
/**
* Only copy internal data of Material ID from source to already allocated/initialized destination.
* You probably nerver want to use that directly, use id_copy or BKE_id_copy_ex for typical needs.
@ -164,6 +200,10 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr
ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot);
}
if (ma_src->gp_style != NULL) {
ma_dst->gp_style = MEM_dupallocN(ma_src->gp_style);
}
BLI_listbase_clear(&ma_dst->gpumaterial);
/* TODO Duplicate Engine Settings and set runtime to NULL */
@ -199,6 +239,7 @@ Material *BKE_material_localize(Material *ma)
man->texpaintslot = NULL;
man->preview = NULL;
/* man->gp_style = NULL; */ /* XXX: We probably don't want to clear here, or else we may get problems with COW later? */
BLI_listbase_clear(&man->gpumaterial);
/* TODO Duplicate Engine Settings and set runtime to NULL */
@ -218,6 +259,7 @@ Material ***give_matarar(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@ -231,6 +273,10 @@ Material ***give_matarar(Object *ob)
mb = ob->data;
return &(mb->mat);
}
else if (ob->type == OB_GPENCIL) {
gpd = ob->data;
return &(gpd->mat);
}
return NULL;
}
@ -239,6 +285,7 @@ short *give_totcolp(Object *ob)
Mesh *me;
Curve *cu;
MetaBall *mb;
bGPdata *gpd;
if (ob->type == OB_MESH) {
me = ob->data;
@ -252,6 +299,10 @@ short *give_totcolp(Object *ob)
mb = ob->data;
return &(mb->totcol);
}
else if (ob->type == OB_GPENCIL) {
gpd = ob->data;
return &(gpd->totcol);
}
return NULL;
}
@ -286,6 +337,8 @@ short *give_totcolp_id(ID *id)
return &(((Curve *)id)->totcol);
case ID_MB:
return &(((MetaBall *)id)->totcol);
case ID_GD:
return &(((bGPdata *)id)->totcol);
default:
break;
}
@ -307,6 +360,9 @@ static void material_data_index_remove_id(ID *id, short index)
case ID_MB:
/* meta-elems don't have materials atm */
break;
case ID_GD:
BKE_gpencil_material_index_remove((bGPdata *)id, index);
break;
default:
break;
}
@ -487,6 +543,21 @@ Material *give_current_material(Object *ob, short act)
return ma;
}
MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
{
Material *ma = give_current_material(ob, act);
if (ma != NULL) {
if (ma->gp_style == NULL) {
BKE_material_init_gpencil_settings(ma);
}
return ma->gp_style;
}
else {
return NULL;
}
}
Material *give_node_material(Material *ma)
{
if (ma && ma->use_nodes && ma->nodetree) {
@ -727,6 +798,9 @@ void BKE_material_remap_object(Object *ob, const unsigned int *remap)
else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_curve_material_remap(ob->data, remap, ob->totcol);
}
if (ob->type == OB_GPENCIL) {
BKE_gpencil_material_remap(ob->data, remap, ob->totcol);
}
else {
/* add support for this object data! */
BLI_assert(matar == NULL);
@ -924,7 +998,7 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from mesh */
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_GPENCIL)) {
material_data_index_remove_id((ID *)ob->data, actcol - 1);
if (ob->runtime.curve_cache) {
BKE_displist_free(&ob->runtime.curve_cache->disp);

@ -41,6 +41,7 @@
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@ -53,6 +54,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_shader_fx_types.h"
#include "DNA_smoke_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
@ -86,6 +88,7 @@
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_icons.h"
#include "BKE_key.h"
#include "BKE_lamp.h"
@ -110,12 +113,14 @@
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
#include "BKE_speaker.h"
#include "BKE_softbody.h"
#include "BKE_subsurf.h"
#include "BKE_material.h"
#include "BKE_camera.h"
#include "BKE_image.h"
#include "BKE_gpencil.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@ -185,11 +190,15 @@ void BKE_object_free_curve_cache(Object *ob)
void BKE_object_free_modifiers(Object *ob, const int flag)
{
ModifierData *md;
GpencilModifierData *gp_md;
while ((md = BLI_pophead(&ob->modifiers))) {
modifier_free_ex(md, flag);
}
while ((gp_md = BLI_pophead(&ob->greasepencil_modifiers))) {
BKE_gpencil_modifier_free_ex(gp_md, flag);
}
/* particle modifiers were freed, so free the particlesystems as well */
BKE_object_free_particlesystems(ob);
@ -200,6 +209,15 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
BKE_object_free_derived_caches(ob);
}
void BKE_object_free_shaderfx(Object *ob, const int flag)
{
ShaderFxData *fx;
while ((fx = BLI_pophead(&ob->shader_fx))) {
BKE_shaderfx_free_ex(fx, flag);
}
}
void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
{
/* reset functionality */
@ -222,6 +240,29 @@ void BKE_object_modifier_hook_reset(Object *ob, HookModifierData *hmd)
}
}
void BKE_object_modifier_gpencil_hook_reset(Object *ob, HookGpencilModifierData *hmd)
{
if (hmd->object == NULL) {
return;
}
/* reset functionality */
bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
if (hmd->subtarget[0] && pchan) {
float imat[4][4], mat[4][4];
/* calculate the world-space matrix for the pose-channel target first, then carry on as usual */
mul_m4_m4m4(mat, hmd->object->obmat, pchan->pose_mat);
invert_m4_m4(imat, mat);
mul_m4_m4m4(hmd->parentinv, imat, ob->obmat);
}
else {
invert_m4_m4(hmd->object->imat, hmd->object->obmat);
mul_m4_m4m4(hmd->parentinv, hmd->object->imat, ob->obmat);
}
}
bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
{
const ModifierTypeInfo *mti;
@ -428,6 +469,7 @@ void BKE_object_free(Object *ob)
/* BKE_<id>_free shall never touch to ID->us. Never ever. */
BKE_object_free_modifiers(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
BKE_object_free_shaderfx(ob, LIB_ID_CREATE_NO_USER_REFCOUNT);
MEM_SAFE_FREE(ob->mat);
MEM_SAFE_FREE(ob->matbits);
@ -653,6 +695,7 @@ static const char *get_obdata_defname(int type)
case OB_ARMATURE: return DATA_("Armature");
case OB_SPEAKER: return DATA_("Speaker");
case OB_EMPTY: return DATA_("Empty");
case OB_GPENCIL: return DATA_("GPencil");
default:
printf("get_obdata_defname: Internal error, bad type: %d\n", type);
return DATA_("Empty");
@ -677,6 +720,7 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name)
case OB_ARMATURE: return BKE_armature_add(bmain, name);
case OB_SPEAKER: return BKE_speaker_add(bmain, name);
case OB_LIGHTPROBE:return BKE_lightprobe_add(bmain, name);
case OB_GPENCIL: return BKE_gpencil_data_addnew(bmain, name);
case OB_EMPTY: return NULL;
default:
printf("%s: Internal error, bad type: %d\n", __func__, type);
@ -810,7 +854,7 @@ Object *BKE_object_add(
/**
* Add a new object, using another one as a reference
*
* /param ob_src object to use to determine the collections of the new object.
* \param ob_src object to use to determine the collections of the new object.
*/
Object *BKE_object_add_from(
Main *bmain, Scene *scene, ViewLayer *view_layer,
@ -828,6 +872,41 @@ Object *BKE_object_add_from(
return ob;
}
/**
* Add a new object, but assign the given datablock as the ob->data
* for the newly created object.
*
* \param data The datablock to assign as ob->data for the new object.
* This is assumed to be of the correct type.
* \param do_id_user If true, id_us_plus() will be called on data when
* assigning it to the object.
*/
Object *BKE_object_add_for_data(
Main *bmain, ViewLayer *view_layer,
int type, const char *name, ID *data, bool do_id_user)
{
Object *ob;
Base *base;
LayerCollection *layer_collection;
/* same as object_add_common, except we don't create new ob->data */
ob = BKE_object_add_only_object(bmain, type, name);
ob->data = data;
if (do_id_user) id_us_plus(data);
BKE_view_layer_base_deselect_all(view_layer);
DEG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
layer_collection = BKE_layer_collection_get_active(view_layer);
BKE_collection_object_add(bmain, layer_collection->collection, ob);
base = BKE_view_layer_base_find(view_layer, ob);
BKE_view_layer_base_select(view_layer, base);
return ob;
}
void BKE_object_copy_softbody(struct Object *ob_dst, const struct Object *ob_src, const int flag)
{
SoftBody *sb = ob_src->soft;
@ -1153,6 +1232,8 @@ void BKE_object_transform_copy(Object *ob_tar, const Object *ob_src)
void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag)
{
ModifierData *md;
GpencilModifierData *gmd;
ShaderFxData *fx;
/* Do not copy runtime data. */
BKE_object_runtime_reset(ob_dst);
@ -1179,6 +1260,24 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
BLI_addtail(&ob_dst->modifiers, nmd);
}
BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
for (gmd = ob_src->greasepencil_modifiers.first; gmd; gmd = gmd->next) {
GpencilModifierData *nmd = BKE_gpencil_modifier_new(gmd->type);
BLI_strncpy(nmd->name, gmd->name, sizeof(nmd->name));
BKE_gpencil_modifier_copyData_ex(gmd, nmd, flag_subdata);
BLI_addtail(&ob_dst->greasepencil_modifiers, nmd);
}
BLI_listbase_clear(&ob_dst->shader_fx);
for (fx = ob_src->shader_fx.first; fx; fx = fx->next) {
ShaderFxData *nfx = BKE_shaderfx_new(fx->type);
BLI_strncpy(nfx->name, fx->name, sizeof(nfx->name));
BKE_shaderfx_copyData_ex(fx, nfx, flag_subdata);
BLI_addtail(&ob_dst->shader_fx, nfx);
}
if (ob_src->pose) {
copy_object_pose(ob_dst, ob_src, flag_subdata);
/* backwards compat... non-armatures can get poses in older files? */
@ -1210,6 +1309,10 @@ void BKE_object_copy_data(Main *bmain, Object *ob_dst, const Object *ob_src, con
BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
BLI_listbase_clear(&ob_dst->pc_ids);
/* grease pencil: clean derived data */
if (ob_dst->type == OB_GPENCIL)
BKE_gpencil_free_derived_frames(ob_dst->data);
ob_dst->avs = ob_src->avs;
ob_dst->mpath = animviz_copy_motionpath(ob_src->mpath);
@ -1469,6 +1572,11 @@ void BKE_object_obdata_size_init(struct Object *ob, const float size)
ob->empty_drawsize *= size;
break;
}
case OB_GPENCIL:
{
ob->empty_drawsize *= size;
break;
}
case OB_FONT:
{
Curve *cu = ob->data;
@ -2452,7 +2560,7 @@ void BKE_object_minmax(Object *ob, float min_r[3], float max_r[3], const bool us
float size[3];
copy_v3_v3(size, ob->size);
if (ob->type == OB_EMPTY) {
if ((ob->type == OB_EMPTY) || (ob->type == OB_GPENCIL)) {
mul_v3_fl(size, ob->empty_drawsize);
}
@ -3694,6 +3802,88 @@ bool BKE_object_modifier_use_time(Object *ob, ModifierData *md)
return false;
}
bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
{
if (BKE_gpencil_modifier_dependsOnTime(md)) {
return true;
}
/* Check whether modifier is animated. */
/* TODO (Aligorith): this should be handled as part of build_animdata() */
if (ob->adt) {
AnimData *adt = ob->adt;
FCurve *fcu;
char pattern[MAX_NAME + 32];
BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md->name);
/* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
if (adt->action) {
for (fcu = (FCurve *)adt->action->curves.first;
fcu != NULL;
fcu = (FCurve *)fcu->next)
{
if (fcu->rna_path && strstr(fcu->rna_path, pattern))
return true;
}
}
/* This here allows modifier properties to get driven and still update properly
*
*/
for (fcu = (FCurve *)adt->drivers.first;
fcu != NULL;
fcu = (FCurve *)fcu->next)
{
if (fcu->rna_path && strstr(fcu->rna_path, pattern))
return true;
}
}
return false;
}
bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
{
if (BKE_shaderfx_dependsOnTime(fx)) {
return true;
}
/* Check whether effect is animated. */
/* TODO (Aligorith): this should be handled as part of build_animdata() */
if (ob->adt) {
AnimData *adt = ob->adt;
FCurve *fcu;
char pattern[MAX_NAME + 32];
BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx->name);
/* action - check for F-Curves with paths containing string[' */
if (adt->action) {
for (fcu = (FCurve *)adt->action->curves.first;
fcu != NULL;
fcu = (FCurve *)fcu->next)
{
if (fcu->rna_path && strstr(fcu->rna_path, pattern))
return true;
}
}
/* This here allows properties to get driven and still update properly
*
*/
for (fcu = (FCurve *)adt->drivers.first;
fcu != NULL;
fcu = (FCurve *)fcu->next)
{
if (fcu->rna_path && strstr(fcu->rna_path, pattern))
return true;
}
}
return false;
}
/* set "ignore cache" flag for all caches on this object */
static void object_cacheIgnoreClear(Object *ob, int state)
{

@ -53,6 +53,7 @@
#include "BKE_object.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_gpencil.h"
/** \name Misc helpers
* \{ */
@ -402,12 +403,17 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
*/
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
if (BKE_object_is_in_editmode_vgroup(ob))
object_defgroup_remove_edit_mode(ob, defgroup);
else
object_defgroup_remove_object_mode(ob, defgroup);
if ((ob) && (ob->type == OB_GPENCIL)) {
BKE_gpencil_vgroup_remove(ob, defgroup);
}
else {
if (BKE_object_is_in_editmode_vgroup(ob))
object_defgroup_remove_edit_mode(ob, defgroup);
else
object_defgroup_remove_object_mode(ob, defgroup);
BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
BKE_mesh_batch_cache_dirty(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
}
}
/**

@ -62,6 +62,7 @@
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_gpencil.h"
#include "MEM_guardedalloc.h"
@ -324,6 +325,9 @@ void BKE_object_eval_uber_data(Depsgraph *depsgraph,
case OB_MBALL:
BKE_mball_batch_cache_dirty(ob->data, BKE_MBALL_BATCH_DIRTY_ALL);
break;
case OB_GPENCIL:
BKE_gpencil_batch_cache_dirty(ob->data);
break;
}
}

@ -41,13 +41,19 @@
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "DNA_space_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_workspace_types.h"
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_string_utils.h"
#include "BLI_math_vector.h"
#include "BLI_listbase.h"
#include "BLT_translation.h"
#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_deform.h"
@ -55,6 +61,7 @@
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
#include "BKE_image.h"
#include "BKE_key.h"
#include "BKE_library.h"
@ -151,6 +158,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode)
return &ts->imapaint.paint;
case ePaintSculptUV:
return &ts->uvsculpt->paint;
case ePaintGpencil:
return &ts->gp_paint->paint;
case ePaintInvalid:
return NULL;
default:
@ -176,6 +185,8 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer)
return &ts->wpaint->paint;
case OB_MODE_TEXTURE_PAINT:
return &ts->imapaint.paint;
case OB_MODE_GPENCIL_PAINT:
return &ts->gp_paint->paint;
case OB_MODE_EDIT:
if (ts->use_uv_sculpt)
return &ts->uvsculpt->paint;
@ -430,13 +441,11 @@ PaletteColor *BKE_palette_color_add(Palette *palette)
return color;
}
bool BKE_palette_is_empty(const struct Palette *palette)
{
return BLI_listbase_is_empty(&palette->colors);
}
/* are we in vertex paint or weight pain face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{

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

Loading…
Cancel
Save