Compare commits
106 Commits
temp-node-
...
GPencil_Fi
Author | SHA1 | Date | |
---|---|---|---|
027824714e | |||
dfc7423a26 | |||
e33691dc59 | |||
f193652814 | |||
d404a45df0 | |||
7a80a76b0d | |||
24380454da | |||
365b38799a | |||
f11a5ce8c1 | |||
37c08c1e9f | |||
32db28d08a | |||
cf3ce9fbfc | |||
0a0c2d48d5 | |||
ee89e770e3 | |||
3eca27cdd1 | |||
527d1593e8 | |||
79236d5b81 | |||
fa9a41cd02 | |||
86749a5f7c | |||
23bbab6bdc | |||
f01a10d07d | |||
c80972286c | |||
1219070c55 | |||
aadb8305b4 | |||
516f551052 | |||
5035eef260 | |||
3d5317febd | |||
b800500814 | |||
4793302674 | |||
bb45d48c1b | |||
ead565678b | |||
2c1bcad26b | |||
ef71a77e56 | |||
3540bebf23 | |||
e14b8711b3 | |||
41e5c6198f | |||
1201c20558 | |||
f0170d035b | |||
da5a4a2f26 | |||
388baf3b70 | |||
b09ac229ca | |||
efb32c7169 | |||
bd7b692f29 | |||
c8a0e91ac2 | |||
b62677210e | |||
e9ae8a382f | |||
5de47a3d6e | |||
c7eee31838 | |||
c6110bf156 | |||
34fe61ebcb | |||
76007990d3 | |||
c3c22afd9e | |||
6ed6dd1301 | |||
c704c69b7e | |||
cd540f3937 | |||
ec8ad8d0c4 | |||
e3fd2fe14b | |||
8b445fba5c | |||
0e3ac25de0 | |||
d5d2a289db | |||
c39e9e3534 | |||
3dd6dbdc6f | |||
8b5a6e9323 | |||
f94c969193 | |||
7e61d1fc4f | |||
8abecb7a50 | |||
3437544b88 | |||
d88288b209 | |||
4f6c99a53c | |||
f4a1ed4351 | |||
38308baf1b | |||
7d047917b5 | |||
ec5f0d27b5 | |||
e2b872ccc8 | |||
ab62df4837 | |||
779826d295 | |||
9921e72b72 | |||
c10359cb81 | |||
ae65857471 | |||
97f9b3c05f | |||
3e0a73e45a | |||
b42c5a05d5 | |||
9ef589cbcc | |||
72c19c2148 | |||
245c5d3d3a | |||
e744bc03e1 | |||
5be7c40552 | |||
50d88a316d | |||
fb883b3262 | |||
80c4e23531 | |||
625aeb5900 | |||
9dd0881abb | |||
3cfeeeb2ad | |||
5222194967 | |||
0b62328bb5 | |||
159caf73da | |||
e456c54fa4 | |||
72e18c873e | |||
b616bea15c | |||
e1a65d804d | |||
f08fdc0b33 | |||
75b708f702 | |||
914efb853d | |||
e4d1fe7c65 | |||
06e188adb7 | |||
0c346fab2c |
@@ -32,7 +32,10 @@ KM_HIERARCHY = [
|
||||
('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region)
|
||||
('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation
|
||||
('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region)
|
||||
('Grease Pencil', 'EMPTY', 'WINDOW', []), # grease pencil stuff (per region)
|
||||
|
||||
('Grease Pencil', 'EMPTY', 'WINDOW', [ # grease pencil stuff (per region)
|
||||
('Grease Pencil Stroke Edit Mode', 'EMPTY', 'WINDOW', []),
|
||||
]),
|
||||
|
||||
('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
|
||||
('Object Mode', 'EMPTY', 'WINDOW', []),
|
||||
|
@@ -19,11 +19,35 @@
|
||||
# <pep8 compliant>
|
||||
|
||||
|
||||
class GreasePencilPanel():
|
||||
import bpy
|
||||
from bpy.types import Menu, UIList
|
||||
|
||||
|
||||
def gpencil_stroke_placement_settings(context, layout, gpd):
|
||||
col = layout.column(align=True)
|
||||
|
||||
col.label(text="Stroke Placement:")
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop_enum(gpd, "draw_mode", 'VIEW')
|
||||
row.prop_enum(gpd, "draw_mode", 'CURSOR')
|
||||
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
row = col.row(align=True)
|
||||
row.prop_enum(gpd, "draw_mode", 'SURFACE')
|
||||
row.prop_enum(gpd, "draw_mode", 'STROKE')
|
||||
|
||||
row = col.row(align=False)
|
||||
row.active = gpd.draw_mode in ('SURFACE', 'STROKE')
|
||||
row.prop(gpd, "use_stroke_endpoints")
|
||||
|
||||
|
||||
class GreasePencilDrawingToolsPanel():
|
||||
# subclass must set
|
||||
# bl_space_type = 'IMAGE_EDITOR'
|
||||
# bl_region_type = 'TOOLS'
|
||||
bl_label = "Grease Pencil"
|
||||
bl_category = "Grease Pencil"
|
||||
bl_region_type = 'TOOLS'
|
||||
|
||||
@staticmethod
|
||||
def draw(self, context):
|
||||
@@ -31,19 +55,293 @@ class GreasePencilPanel():
|
||||
|
||||
col = layout.column(align=True)
|
||||
|
||||
col.label(text="Draw:")
|
||||
row = col.row(align=True)
|
||||
row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
|
||||
row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
|
||||
|
||||
row = col.row(align=True)
|
||||
row.operator("gpencil.draw", text="Poly").mode = 'DRAW_POLY'
|
||||
row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(context.tool_settings, "use_grease_pencil_sessions")
|
||||
row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
|
||||
row.operator("gpencil.draw", text="Poly").mode = 'DRAW_POLY'
|
||||
|
||||
|
||||
row = col.row(align=True)
|
||||
row.prop(context.tool_settings, "use_grease_pencil_sessions", text="Continuous Drawing")
|
||||
|
||||
gpd = context.gpencil_data
|
||||
if gpd:
|
||||
col.separator()
|
||||
gpencil_stroke_placement_settings(context, col, gpd)
|
||||
|
||||
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
col.separator()
|
||||
col.separator()
|
||||
|
||||
col.label(text="Measure:")
|
||||
col.label(text="Tools:")
|
||||
col.operator("gpencil.convert", text="Convert...")
|
||||
col.operator("view3d.ruler")
|
||||
|
||||
|
||||
class GreasePencilStrokeEditPanel():
|
||||
# subclass must set
|
||||
# bl_space_type = 'IMAGE_EDITOR'
|
||||
bl_label = "Edit Strokes"
|
||||
bl_category = "Grease Pencil"
|
||||
bl_region_type = 'TOOLS'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (context.gpencil_data is not None)
|
||||
|
||||
@staticmethod
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
gpd = context.gpencil_data
|
||||
edit_ok = bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode)
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True)
|
||||
|
||||
col.separator()
|
||||
|
||||
col.label(text="Select:")
|
||||
subcol = col.column(align=True)
|
||||
subcol.active = edit_ok
|
||||
subcol.operator("gpencil.select_all", text="Select All")
|
||||
subcol.operator("gpencil.select_border")
|
||||
subcol.operator("gpencil.select_circle")
|
||||
|
||||
col.separator()
|
||||
|
||||
col.label(text="Edit:")
|
||||
subcol = col.column(align=True)
|
||||
subcol.active = edit_ok
|
||||
subcol.operator("gpencil.strokes_duplicate", text="Duplicate")
|
||||
subcol.operator("transform.mirror", text="Mirror").gpencil_strokes = True
|
||||
|
||||
col.separator()
|
||||
|
||||
subcol = col.column(align=True)
|
||||
subcol.active = edit_ok
|
||||
subcol.operator("transform.translate").gpencil_strokes = True # icon='MAN_TRANS'
|
||||
subcol.operator("transform.rotate").gpencil_strokes = True # icon='MAN_ROT'
|
||||
subcol.operator("transform.resize", text="Scale").gpencil_strokes = True # icon='MAN_SCALE'
|
||||
|
||||
|
||||
###############################
|
||||
|
||||
class GPENCIL_PIE_tool_palette(Menu):
|
||||
"""A pie menu for quick access to Grease Pencil tools"""
|
||||
bl_label = "Grease Pencil Tools"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
pie = layout.menu_pie()
|
||||
gpd = context.gpencil_data
|
||||
|
||||
# W - Drawing Settings
|
||||
col = pie.column()
|
||||
col.operator("gpencil.draw", text="Draw", icon='GREASEPENCIL').mode = 'DRAW'
|
||||
col.operator("gpencil.draw", text="Straight Lines", icon='LINE_DATA').mode = 'DRAW_STRAIGHT'
|
||||
col.operator("gpencil.draw", text="Poly", icon='MESH_DATA').mode = 'DRAW_POLY'
|
||||
|
||||
# E - Eraser
|
||||
# XXX: needs a dedicated icon...
|
||||
pie.operator("gpencil.draw", text="Eraser", icon='FORCE_CURVE').mode = 'ERASER'
|
||||
|
||||
# Editing tools
|
||||
if gpd:
|
||||
if gpd.use_stroke_edit_mode and context.editable_gpencil_strokes:
|
||||
# S - Select
|
||||
col = pie.column()
|
||||
col.operator("gpencil.select_all", text="Select All", icon='PARTICLE_POINT')
|
||||
col.operator("gpencil.select_border", text="Border Select", icon='BORDER_RECT')
|
||||
col.operator("gpencil.select_circle", text="Circle Select", icon='META_EMPTY')
|
||||
#col.operator("gpencil.select", text="Stroke Under Mouse").entire_strokes = True
|
||||
|
||||
# N - Move
|
||||
pie.operator("transform.translate", icon='MAN_TRANS').gpencil_strokes = True
|
||||
|
||||
# NW - Rotate
|
||||
pie.operator("transform.rotate", icon='MAN_ROT').gpencil_strokes = True
|
||||
|
||||
# NE - Scale
|
||||
pie.operator("transform.resize", text="Scale", icon='MAN_SCALE').gpencil_strokes = True
|
||||
|
||||
# SW - Copy
|
||||
pie.operator("gpencil.strokes_duplicate", icon='PARTICLE_PATH')
|
||||
|
||||
# SE - Exit Edit Mode
|
||||
pie.prop(gpd, "use_stroke_edit_mode", text="Exit Edit Mode", icon='EDIT')
|
||||
else:
|
||||
# Toggle Edit Mode
|
||||
pie.prop(gpd, "use_stroke_edit_mode", text="Enable Stroke Editing", icon='EDIT')
|
||||
|
||||
|
||||
###############################
|
||||
|
||||
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
|
||||
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
if gpl.lock:
|
||||
layout.active = False
|
||||
|
||||
split = layout.split(percentage=0.2)
|
||||
split.prop(gpl, "color", text="")
|
||||
split.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)
|
||||
elif self.layout_type in {'GRID'}:
|
||||
layout.alignment = 'CENTER'
|
||||
layout.label(text="", icon_value=icon)
|
||||
|
||||
|
||||
class GreasePencilDataPanel():
|
||||
# subclass must set
|
||||
# bl_space_type = 'IMAGE_EDITOR'
|
||||
bl_label = "Grease Pencil"
|
||||
bl_region_type = 'UI'
|
||||
|
||||
@staticmethod
|
||||
def draw_header(self, context):
|
||||
self.layout.prop(context.space_data, "show_grease_pencil", text="")
|
||||
|
||||
@staticmethod
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
# owner of Grease Pencil data
|
||||
gpd_owner = context.gpencil_data_owner
|
||||
gpd = context.gpencil_data
|
||||
|
||||
# Owner Selector
|
||||
# XXX: add this for 3D view too
|
||||
if context.space_data.type == 'CLIP_EDITOR':
|
||||
layout.prop(context.space_data, "grease_pencil_source", expand=True)
|
||||
|
||||
# Grease Pencil data selector
|
||||
layout.template_ID(gpd_owner, "grease_pencil", new="gpencil.data_add", unlink="gpencil.data_unlink")
|
||||
|
||||
# Grease Pencil data...
|
||||
if gpd is None:
|
||||
# even with no data, this operator will still work, as it makes gpd too
|
||||
layout.operator("gpencil.layer_add", text="New Layer", icon='ZOOMIN')
|
||||
else:
|
||||
self.draw_layers(context, layout, gpd)
|
||||
|
||||
# only sequencer doesn't have a toolbar to show these settings in,
|
||||
# so only show this for the sequencer...
|
||||
if context.space_data.type == 'SEQUENCE_EDITOR':
|
||||
layout.separator()
|
||||
layout.separator()
|
||||
|
||||
layout.prop(gpd, "use_stroke_edit_mode", text="Enable Stroke Editing", icon='EDIT', toggle=True)
|
||||
|
||||
layout.separator()
|
||||
layout.separator()
|
||||
|
||||
gpencil_stroke_placement_settings(context, layout, gpd)
|
||||
|
||||
def draw_layers(self, context, layout, gpd):
|
||||
row = layout.row()
|
||||
|
||||
col = row.column()
|
||||
col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index", rows=5)
|
||||
|
||||
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:
|
||||
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'
|
||||
|
||||
if gpl:
|
||||
self.draw_layer(layout, gpl)
|
||||
|
||||
def draw_layer(self, layout, gpl):
|
||||
# layer settings
|
||||
split = layout.split(percentage=0.5)
|
||||
split.active = not gpl.lock
|
||||
|
||||
# Column 1 - Stroke
|
||||
col = split.column(align=True)
|
||||
col.label(text="Stroke:")
|
||||
col.prop(gpl, "color", text="")
|
||||
col.prop(gpl, "alpha", slider=True)
|
||||
|
||||
# Column 2 - Fill
|
||||
col = split.column(align=True)
|
||||
col.label(text="Fill:")
|
||||
col.prop(gpl, "fill_color", text="")
|
||||
col.prop(gpl, "fill_alpha", text="Opacity", slider=True)
|
||||
|
||||
# Options
|
||||
split = layout.split(percentage=0.5)
|
||||
split.active = not gpl.lock
|
||||
|
||||
col = split.column(align=True)
|
||||
col.prop(gpl, "line_width", slider=True)
|
||||
col.prop(gpl, "use_volumetric_strokes")
|
||||
|
||||
col = split.column(align=True)
|
||||
col.prop(gpl, "show_x_ray")
|
||||
|
||||
#if debug:
|
||||
# layout.prop(gpl, "show_points")
|
||||
|
||||
layout.separator()
|
||||
|
||||
# Full-Row - Frame Locking (and Delete Frame)
|
||||
row = layout.row(align=True)
|
||||
row.active = not gpl.lock
|
||||
|
||||
if gpl.active_frame:
|
||||
lock_status = "Locked" if gpl.lock_frame else "Unlocked"
|
||||
lock_label = "Frame: %d (%s)" % (gpl.active_frame.frame_number, lock_status)
|
||||
else:
|
||||
lock_label = "Lock Frame"
|
||||
row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
|
||||
row.operator("gpencil.active_frame_delete", text="", icon='X')
|
||||
|
||||
layout.separator()
|
||||
|
||||
# Onion skinning
|
||||
col = layout.column(align=True)
|
||||
col.active = not gpl.lock
|
||||
|
||||
row = col.row()
|
||||
row.prop(gpl, "use_onion_skinning")
|
||||
row.prop(gpl, "use_ghost_custom_colors", text="", icon='COLOR')
|
||||
|
||||
split = col.split(percentage = 0.5)
|
||||
split.active = gpl.use_onion_skinning
|
||||
|
||||
# - Before Frames
|
||||
sub = split.column(align=True)
|
||||
row = sub.row(align=True)
|
||||
row.active = gpl.use_ghost_custom_colors
|
||||
row.prop(gpl, "before_color", text="")
|
||||
sub.prop(gpl, "ghost_before_range", text="Before")
|
||||
|
||||
|
||||
# - After Frames
|
||||
sub = split.column(align=True)
|
||||
row = sub.row(align=True)
|
||||
row.active = gpl.use_ghost_custom_colors
|
||||
row.prop(gpl, "after_color", text="")
|
||||
sub.prop(gpl, "ghost_after_range", text="After")
|
||||
|
@@ -21,7 +21,11 @@
|
||||
import bpy
|
||||
from bpy.types import Panel, Header, Menu, UIList
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
from bl_ui.properties_grease_pencil_common import GreasePencilPanel
|
||||
from bl_ui.properties_grease_pencil_common import (
|
||||
GreasePencilDrawingToolsPanel,
|
||||
GreasePencilStrokeEditPanel,
|
||||
GreasePencilDataPanel
|
||||
)
|
||||
|
||||
|
||||
class CLIP_UL_tracking_objects(UIList):
|
||||
@@ -1050,12 +1054,6 @@ class CLIP_PT_tools_mask(MASK_PT_tools, Panel):
|
||||
# --- end mask ---
|
||||
|
||||
|
||||
class CLIP_PT_tools_grease_pencil(GreasePencilPanel, Panel):
|
||||
bl_space_type = 'CLIP_EDITOR'
|
||||
bl_region_type = 'TOOLS'
|
||||
bl_category = "Grease Pencil"
|
||||
|
||||
|
||||
class CLIP_PT_footage(CLIP_PT_clip_view_panel, Panel):
|
||||
bl_space_type = 'CLIP_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
@@ -1110,6 +1108,26 @@ class CLIP_PT_tools_scenesetup(Panel):
|
||||
layout.operator("clip.setup_tracking_scene")
|
||||
|
||||
|
||||
# Grease Pencil properties
|
||||
class CLIP_PT_grease_pencil(GreasePencilDataPanel, 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'
|
||||
|
||||
|
||||
# Grease Pencil stroke editing tools
|
||||
class CLIP_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
|
||||
bl_space_type = 'CLIP_EDITOR'
|
||||
|
||||
|
||||
class CLIP_MT_view(Menu):
|
||||
bl_label = "View"
|
||||
|
||||
|
@@ -365,14 +365,16 @@ class DOPESHEET_MT_gpencil_frame(Menu):
|
||||
layout = self.layout
|
||||
|
||||
layout.menu("DOPESHEET_MT_key_transform", text="Transform")
|
||||
|
||||
#layout.operator_menu_enum("action.snap", "type", text="Snap")
|
||||
#layout.operator_menu_enum("action.mirror", "type", text="Mirror")
|
||||
layout.operator_menu_enum("action.snap", "type", text="Snap")
|
||||
layout.operator_menu_enum("action.mirror", "type", text="Mirror")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("action.duplicate")
|
||||
layout.operator("action.delete")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("action.keyframe_type")
|
||||
|
||||
#layout.separator()
|
||||
#layout.operator("action.copy")
|
||||
#layout.operator("action.paste")
|
||||
|
@@ -25,7 +25,11 @@ from bl_ui.properties_paint_common import (
|
||||
brush_texpaint_common,
|
||||
brush_mask_texture_settings,
|
||||
)
|
||||
from bl_ui.properties_grease_pencil_common import GreasePencilPanel
|
||||
from bl_ui.properties_grease_pencil_common import (
|
||||
GreasePencilDrawingToolsPanel,
|
||||
GreasePencilStrokeEditPanel,
|
||||
GreasePencilDataPanel
|
||||
)
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
|
||||
|
||||
@@ -1148,10 +1152,21 @@ class IMAGE_PT_scope_sample(Panel):
|
||||
sub.prop(sima.scopes, "accuracy")
|
||||
|
||||
|
||||
class IMAGE_PT_tools_grease_pencil(GreasePencilPanel, Panel):
|
||||
# Grease Pencil properties
|
||||
class IMAGE_PT_grease_pencil(GreasePencilDataPanel, 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'
|
||||
|
||||
|
||||
# Grease Pencil stroke editing tools
|
||||
class IMAGE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
|
||||
bl_space_type = 'IMAGE_EDITOR'
|
||||
bl_region_type = 'TOOLS'
|
||||
bl_category = "Grease Pencil"
|
||||
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
|
@@ -19,6 +19,11 @@
|
||||
# <pep8 compliant>
|
||||
import bpy
|
||||
from bpy.types import Header, Menu, Panel
|
||||
from bl_ui.properties_grease_pencil_common import (
|
||||
GreasePencilDrawingToolsPanel,
|
||||
GreasePencilStrokeEditPanel,
|
||||
GreasePencilDataPanel,
|
||||
)
|
||||
|
||||
|
||||
class NODE_HT_header(Header):
|
||||
@@ -439,6 +444,32 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
|
||||
layout.template_node_socket(color)
|
||||
|
||||
|
||||
# Grease Pencil properties
|
||||
class NODE_PT_grease_pencil(GreasePencilDataPanel, 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
|
||||
|
||||
# Tool Shelf ------------------
|
||||
|
||||
|
||||
# Grease Pencil drawing tools
|
||||
class NODE_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
|
||||
|
||||
# Grease Pencil stroke editing tools
|
||||
class NODE_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
|
||||
# -----------------------------
|
||||
|
||||
def node_draw_tree_view(layout, context):
|
||||
pass
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
# <pep8 compliant>
|
||||
import bpy
|
||||
from bpy.types import Header, Menu, Panel
|
||||
from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel
|
||||
from bpy.app.translations import pgettext_iface as iface_
|
||||
|
||||
|
||||
@@ -1012,5 +1013,13 @@ class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel):
|
||||
col.prop(mod, "contrast")
|
||||
|
||||
|
||||
class SEQUENCER_PT_grease_pencil(GreasePencilDataPanel, 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
|
||||
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
bpy.utils.register_module(__name__)
|
||||
|
@@ -19,6 +19,7 @@
|
||||
# <pep8 compliant>
|
||||
import bpy
|
||||
from bpy.types import Header, Menu, Panel
|
||||
from bl_ui.properties_grease_pencil_common import GreasePencilDataPanel
|
||||
from bl_ui.properties_paint_common import UnifiedPaintPanel
|
||||
from bpy.app.translations import contexts as i18n_contexts
|
||||
|
||||
@@ -2703,6 +2704,12 @@ class VIEW3D_MT_edit_armature_roll(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_view3d_properties(Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
|
@@ -19,7 +19,10 @@
|
||||
# <pep8 compliant>
|
||||
import bpy
|
||||
from bpy.types import Menu, Panel, UIList
|
||||
from bl_ui.properties_grease_pencil_common import GreasePencilPanel
|
||||
from bl_ui.properties_grease_pencil_common import (
|
||||
GreasePencilDrawingToolsPanel,
|
||||
GreasePencilStrokeEditPanel
|
||||
)
|
||||
from bl_ui.properties_paint_common import (
|
||||
UnifiedPaintPanel,
|
||||
brush_texture_settings,
|
||||
@@ -1804,11 +1807,14 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
|
||||
sub.prop(pe, "fade_frames", slider=True)
|
||||
|
||||
|
||||
# Grease Pencil tools
|
||||
class VIEW3D_PT_tools_grease_pencil(GreasePencilPanel, Panel):
|
||||
# Grease Pencil drawing tools
|
||||
class VIEW3D_PT_tools_grease_pencil_draw(GreasePencilDrawingToolsPanel, Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
|
||||
|
||||
# Grease Pencil stroke editing tools
|
||||
class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel):
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'TOOLS'
|
||||
bl_category = "Grease Pencil"
|
||||
|
||||
|
||||
# Note: moved here so that it's always in last position in 'Tools' panels!
|
||||
|
@@ -56,6 +56,9 @@ struct Text;
|
||||
struct ImBuf;
|
||||
struct EditBone;
|
||||
struct bPoseChannel;
|
||||
struct bGPdata;
|
||||
struct bGPDlayer;
|
||||
struct bGPDframe;
|
||||
struct wmWindow;
|
||||
struct wmWindowManager;
|
||||
struct SpaceText;
|
||||
@@ -275,6 +278,14 @@ struct bPoseChannel *CTX_data_active_pose_bone(const bContext *C);
|
||||
int CTX_data_selected_pose_bones(const bContext *C, ListBase *list);
|
||||
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);
|
||||
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);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -35,6 +35,7 @@ struct ListBase;
|
||||
struct bGPdata;
|
||||
struct bGPDlayer;
|
||||
struct bGPDframe;
|
||||
struct bGPDstroke;
|
||||
|
||||
/* ------------ Grease-Pencil API ------------------ */
|
||||
|
||||
@@ -43,6 +44,8 @@ void free_gpencil_frames(struct bGPDlayer *gpl);
|
||||
void free_gpencil_layers(struct ListBase *list);
|
||||
void BKE_gpencil_free(struct bGPdata *gpd);
|
||||
|
||||
void gpencil_stroke_sync_selection(struct bGPDstroke *gps);
|
||||
|
||||
struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
|
||||
struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd, const char *name, int setactive);
|
||||
struct bGPdata *gpencil_data_addnew(const char name[]);
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "DNA_windowmanager_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_linestyle_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
@@ -1090,3 +1091,34 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list)
|
||||
{
|
||||
return ctx_data_collection_get(C, "visible_pose_bones", list);
|
||||
}
|
||||
|
||||
bGPdata *CTX_data_gpencil_data(const bContext *C)
|
||||
{
|
||||
return ctx_data_pointer_get(C, "gpencil_data");
|
||||
}
|
||||
|
||||
bGPDlayer *CTX_data_active_gpencil_layer(const bContext *C)
|
||||
{
|
||||
return ctx_data_pointer_get(C, "active_gpencil_layer");
|
||||
}
|
||||
|
||||
bGPDframe *CTX_data_active_gpencil_frame(const bContext *C)
|
||||
{
|
||||
return ctx_data_pointer_get(C, "active_gpencil_frame");
|
||||
}
|
||||
|
||||
int CTX_data_visible_gpencil_layers(const bContext *C, ListBase *list)
|
||||
{
|
||||
return ctx_data_collection_get(C, "visible_gpencil_layers", list);
|
||||
}
|
||||
|
||||
int CTX_data_editable_gpencil_layers(const bContext *C, ListBase *list)
|
||||
{
|
||||
return ctx_data_collection_get(C, "editable_gpencil_layers", list);
|
||||
}
|
||||
|
||||
int CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list)
|
||||
{
|
||||
return ctx_data_collection_get(C, "editable_gpencil_strokes", list);
|
||||
}
|
||||
|
||||
|
@@ -300,6 +300,31 @@ bGPdata *gpencil_data_duplicate(bGPdata *src)
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* -------- GP-Stroke API --------- */
|
||||
|
||||
/* ensure selection status of stroke is in sync with its points */
|
||||
void gpencil_stroke_sync_selection(bGPDstroke *gps)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
/* error checking */
|
||||
if (gps == NULL)
|
||||
return;
|
||||
|
||||
/* we'll stop when we find the first selected point,
|
||||
* so initially, we must deselect
|
||||
*/
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
if (pt->flag & GP_SPOINT_SELECT) {
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- GP-Frame API ---------- */
|
||||
|
||||
/* delete the last stroke of the given frame */
|
||||
@@ -468,16 +493,23 @@ bGPDframe *gpencil_layer_getframe(bGPDlayer *gpl, int cframe, short addnew)
|
||||
bool gpencil_layer_delframe(bGPDlayer *gpl, bGPDframe *gpf)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
|
||||
/* error checking */
|
||||
if (ELEM(NULL, gpl, gpf))
|
||||
return false;
|
||||
|
||||
|
||||
/* if this frame was active, make the previous frame active instead
|
||||
* since it's tricky to set active frame otherwise
|
||||
*/
|
||||
if (gpl->actframe == gpf)
|
||||
gpl->actframe = gpf->prev;
|
||||
else
|
||||
gpl->actframe = NULL;
|
||||
|
||||
/* free the frame and its data */
|
||||
changed = free_gpencil_strokes(gpf);
|
||||
BLI_freelinkN(&gpl->frames, gpf);
|
||||
gpl->actframe = NULL;
|
||||
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
@@ -3407,6 +3407,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
|
||||
/* step 4) draw special toggles .................................
|
||||
* - in Graph Editor, checkboxes for visibility in curves area
|
||||
* - in NLA Editor, glowing dots for solo/not solo...
|
||||
* - in Grease Pencil mode, color swatches for layer color
|
||||
*/
|
||||
if (ac->sl) {
|
||||
if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
|
||||
@@ -3431,6 +3432,10 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
|
||||
/* just skip - drawn as widget now */
|
||||
offset += ICON_WIDTH;
|
||||
}
|
||||
else if ((ac->datatype == ANIMCONT_GPENCIL) && (ale->type == ANIMTYPE_GPLAYER)) {
|
||||
/* just skip - drawn as a widget */
|
||||
offset += ICON_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* step 5) draw name ............................................... */
|
||||
@@ -3878,6 +3883,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
|
||||
/* step 3) draw special toggles .................................
|
||||
* - in Graph Editor, checkboxes for visibility in curves area
|
||||
* - in NLA Editor, glowing dots for solo/not solo...
|
||||
* - in Grease Pencil mode, color swatches for layer color
|
||||
*/
|
||||
if (ac->sl) {
|
||||
if ((ac->spacetype == SPACE_IPO) && acf->has_setting(ac, ale, ACHANNEL_SETTING_VISIBLE)) {
|
||||
@@ -3890,6 +3896,23 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
|
||||
draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_SOLO);
|
||||
offset += ICON_WIDTH;
|
||||
}
|
||||
else if ((ac->datatype == ANIMCONT_GPENCIL) && (ale->type == ANIMTYPE_GPLAYER)) {
|
||||
/* color swatch for layer color */
|
||||
bGPDlayer *gpl = (bGPDlayer *)ale->data;
|
||||
PointerRNA ptr;
|
||||
|
||||
RNA_pointer_create(ale->id, &RNA_GPencilLayer, ale->data, &ptr);
|
||||
|
||||
uiBlockSetEmboss(block, UI_EMBOSS);
|
||||
|
||||
uiDefButR(block, COLOR, 1, "", offset, yminc, ICON_WIDTH, ICON_WIDTH,
|
||||
&ptr, "color", -1,
|
||||
0, 0, 0, 0, gpl->info);
|
||||
|
||||
uiBlockSetEmboss(block, UI_EMBOSSN);
|
||||
|
||||
offset += ICON_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
/* step 4) draw text - check if renaming widget is in use... */
|
||||
|
@@ -136,6 +136,13 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_GPLAYER:
|
||||
{
|
||||
bGPDlayer *gpl = (bGPDlayer *)ale->data;
|
||||
|
||||
ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,8 +191,14 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datat
|
||||
break;
|
||||
}
|
||||
|
||||
/* unhandled currently, but may be interesting */
|
||||
case ANIMTYPE_GPLAYER:
|
||||
{
|
||||
bGPDlayer *gpl = (bGPDlayer *)channel_data;
|
||||
gpl->flag |= GP_LAYER_ACTIVE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* unhandled currently, but may be interesting */
|
||||
case ANIMTYPE_MASKLAYER:
|
||||
case ANIMTYPE_SHAPEKEY:
|
||||
case ANIMTYPE_NLAACTION:
|
||||
@@ -843,6 +856,13 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
|
||||
is_sel = SEL_NLT(nlt);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_GPLAYER:
|
||||
{
|
||||
bGPDlayer *gpl = (bGPDlayer *)channel;
|
||||
|
||||
is_sel = SEL_GPL(gpl);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type);
|
||||
return;
|
||||
@@ -1167,6 +1187,47 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrange
|
||||
|
||||
/* ------------------- */
|
||||
|
||||
static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
bAnimListElem *ale;
|
||||
int filter;
|
||||
|
||||
/* get rearranging function */
|
||||
AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
|
||||
|
||||
if (rearrange_func == NULL)
|
||||
return;
|
||||
|
||||
/* get Grease Pencil datablocks */
|
||||
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
|
||||
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
||||
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
ListBase anim_data_visible = {NULL, NULL};
|
||||
bGPdata *gpd = ale->data;
|
||||
|
||||
/* only consider layers if this datablock is open */
|
||||
BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK);
|
||||
if ((gpd->flag & GP_DATA_EXPAND) == 0)
|
||||
continue;
|
||||
|
||||
/* Filter visible data. */
|
||||
rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER);
|
||||
|
||||
/* rearrange datablock's layers */
|
||||
rearrange_animchannel_islands(&gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible);
|
||||
|
||||
/* free visible layers data */
|
||||
BLI_freelistN(&anim_data_visible);
|
||||
}
|
||||
|
||||
/* free GPD channel data */
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
/* ------------------- */
|
||||
|
||||
static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
@@ -1182,7 +1243,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
|
||||
/* method to move channels depends on the editor */
|
||||
if (ac.datatype == ANIMCONT_GPENCIL) {
|
||||
/* Grease Pencil channels */
|
||||
printf("Grease Pencil not supported for moving yet\n");
|
||||
rearrange_gpencil_channels(&ac, mode);
|
||||
}
|
||||
else if (ac.datatype == ANIMCONT_MASK) {
|
||||
/* Grease Pencil channels */
|
||||
@@ -2897,7 +2958,13 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
|
||||
gpl->flag |= GP_LAYER_SELECT;
|
||||
}
|
||||
|
||||
notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
|
||||
/* change active layer, if this is selected (since we must always have an active layer) */
|
||||
if (gpl->flag & GP_LAYER_SELECT) {
|
||||
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, gpl, ANIMTYPE_GPLAYER);
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); /* Grease Pencil updates */
|
||||
notifierFlags |= (ND_ANIMCHAN | NA_EDITED); /* Animation Ediotrs updates */
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_MASKDATABLOCK:
|
||||
|
@@ -1413,26 +1413,36 @@ static size_t animdata_filter_gpencil(ListBase *anim_data, void *UNUSED(data), i
|
||||
/* only show if gpd is used by something... */
|
||||
if (ID_REAL_USERS(gpd) < 1)
|
||||
continue;
|
||||
|
||||
/* add gpencil animation channels */
|
||||
BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
|
||||
{
|
||||
tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode);
|
||||
}
|
||||
END_ANIMFILTER_SUBCHANNELS;
|
||||
|
||||
/* did we find anything? */
|
||||
if (tmp_items) {
|
||||
/* include data-expand widget first */
|
||||
if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
|
||||
/* add gpd as channel too (if for drawing, and it has layers) */
|
||||
ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
|
||||
/* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation),
|
||||
* for convenience, this will return GP Datablocks instead. This may cause issues down
|
||||
* the track, but for now, this will do...
|
||||
*/
|
||||
if (filter_mode & ANIMFILTER_ANIMDATA) {
|
||||
/* just add GPD as a channel - this will add everything needed */
|
||||
ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
|
||||
}
|
||||
else {
|
||||
/* add gpencil animation channels */
|
||||
BEGIN_ANIMFILTER_SUBCHANNELS(EXPANDED_GPD(gpd))
|
||||
{
|
||||
tmp_items += animdata_filter_gpencil_data(&tmp_data, gpd, filter_mode);
|
||||
}
|
||||
END_ANIMFILTER_SUBCHANNELS;
|
||||
|
||||
/* now add the list of collected channels */
|
||||
BLI_movelisttolist(anim_data, &tmp_data);
|
||||
BLI_assert(BLI_listbase_is_empty(&tmp_data));
|
||||
items += tmp_items;
|
||||
/* did we find anything? */
|
||||
if (tmp_items) {
|
||||
/* include data-expand widget first */
|
||||
if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
|
||||
/* add gpd as channel too (if for drawing, and it has layers) */
|
||||
ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL);
|
||||
}
|
||||
|
||||
/* now add the list of collected channels */
|
||||
BLI_movelisttolist(anim_data, &tmp_data);
|
||||
BLI_assert(BLI_listbase_is_empty(&tmp_data));
|
||||
items += tmp_items;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -155,6 +155,7 @@ static DLRBT_Node *nalloc_ak_gpframe(void *data)
|
||||
/* store settings based on state of BezTriple */
|
||||
ak->cfra = gpf->framenum;
|
||||
ak->sel = (gpf->flag & GP_FRAME_SELECT) ? SELECT : 0;
|
||||
ak->key_type = gpf->key_type;
|
||||
|
||||
/* set 'modified', since this is used to identify long keyframes */
|
||||
ak->modified = 1;
|
||||
@@ -171,6 +172,10 @@ static void nupdate_ak_gpframe(void *node, void *data)
|
||||
/* set selection status and 'touched' status */
|
||||
if (gpf->flag & GP_FRAME_SELECT) ak->sel = SELECT;
|
||||
ak->modified += 1;
|
||||
|
||||
/* for keyframe type, 'proper' keyframes have priority over breakdowns (and other types for now) */
|
||||
if (gpf->key_type == BEZT_KEYTYPE_KEYFRAME)
|
||||
ak->key_type = BEZT_KEYTYPE_KEYFRAME;
|
||||
}
|
||||
|
||||
/* ......... */
|
||||
@@ -732,6 +737,21 @@ void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos)
|
||||
BLI_dlrbTree_free(&blocks);
|
||||
}
|
||||
|
||||
void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos)
|
||||
{
|
||||
DLRBT_Tree keys;
|
||||
|
||||
BLI_dlrbTree_init(&keys);
|
||||
|
||||
gpencil_to_keylist(ads, gpd, &keys);
|
||||
|
||||
BLI_dlrbTree_linkedlist_sync(&keys);
|
||||
|
||||
draw_keylist(v2d, &keys, NULL, ypos, 0);
|
||||
|
||||
BLI_dlrbTree_free(&keys);
|
||||
}
|
||||
|
||||
void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos)
|
||||
{
|
||||
DLRBT_Tree keys;
|
||||
@@ -924,6 +944,20 @@ void action_to_keylist(AnimData *adt, bAction *act, DLRBT_Tree *keys, DLRBT_Tree
|
||||
}
|
||||
|
||||
|
||||
void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, DLRBT_Tree *keys)
|
||||
{
|
||||
bGPDlayer *gpl;
|
||||
|
||||
if (gpd && keys) {
|
||||
/* for now, just aggregate out all the frames, but only for visible layers */
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
if ((gpl->flag & GP_LAYER_HIDE) == 0) {
|
||||
gpl_to_keylist(ads, gpl, keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, DLRBT_Tree *keys)
|
||||
{
|
||||
bGPDframe *gpf;
|
||||
|
@@ -43,7 +43,9 @@ set(SRC
|
||||
gpencil_edit.c
|
||||
gpencil_ops.c
|
||||
gpencil_paint.c
|
||||
gpencil_select.c
|
||||
gpencil_undo.c
|
||||
gpencil_utils.c
|
||||
|
||||
gpencil_intern.h
|
||||
)
|
||||
|
@@ -58,6 +58,8 @@
|
||||
#include "ED_gpencil.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "gpencil_intern.h"
|
||||
|
||||
/* ************************************************** */
|
||||
@@ -73,6 +75,9 @@ typedef enum eDrawStrokeFlags {
|
||||
GP_DRAWDATA_ONLYI2D = (1 << 3), /* only draw 'image' strokes */
|
||||
GP_DRAWDATA_IEDITHACK = (1 << 4), /* special hack for drawing strokes in Image Editor (weird coordinates) */
|
||||
GP_DRAWDATA_NO_XRAY = (1 << 5), /* don't draw xray in 3D view (which is default) */
|
||||
GP_DRAWDATA_NO_ONIONS = (1 << 6), /* no onionskins should be drawn (for animation playback) */
|
||||
GP_DRAWDATA_VOLUMETRIC = (1 << 7), /* draw strokes as "volumetric" circular billboards */
|
||||
GP_DRAWDATA_FILL = (1 << 8), /* fill insides/bounded-regions of strokes */
|
||||
} eDrawStrokeFlags;
|
||||
|
||||
|
||||
@@ -144,6 +149,200 @@ static void gp_draw_stroke_buffer(tGPspoint *points, int totpoints, short thickn
|
||||
}
|
||||
}
|
||||
|
||||
/* --------- 2D Stroke Drawing Helpers --------- */
|
||||
|
||||
/* helper function to calculate x-y drawing coordinates for 2D points */
|
||||
static void gp_calc_2d_stroke_xy(bGPDspoint *pt, short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
|
||||
{
|
||||
if (sflag & GP_STROKE_2DSPACE) {
|
||||
r_co[0] = pt->x;
|
||||
r_co[1] = pt->y;
|
||||
}
|
||||
else if (sflag & GP_STROKE_2DIMAGE) {
|
||||
const float x = (float)((pt->x * winx) + offsx);
|
||||
const float y = (float)((pt->y * winy) + offsy);
|
||||
|
||||
r_co[0] = x;
|
||||
r_co[1] = y;
|
||||
}
|
||||
else {
|
||||
const float x = (float)(pt->x / 100 * winx) + offsx;
|
||||
const float y = (float)(pt->y / 100 * winy) + offsy;
|
||||
|
||||
r_co[0] = x;
|
||||
r_co[1] = y;
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------- Volumetric Strokes --------------- */
|
||||
|
||||
/* draw a 2D buffer stroke in "volumetric" style
|
||||
* NOTE: the stroke buffer doesn't have any coordinate offsets/transforms
|
||||
*/
|
||||
static void gp_draw_stroke_volumetric_buffer(tGPspoint *points, int totpoints, short thickness, short dflag, short sflag)
|
||||
{
|
||||
GLUquadricObj *qobj = gluNewQuadric();
|
||||
float modelview[4][4];
|
||||
|
||||
tGPspoint *pt;
|
||||
int i;
|
||||
|
||||
/* error checking */
|
||||
if ((points == NULL) || (totpoints <= 0))
|
||||
return;
|
||||
|
||||
/* check if buffer can be drawn */
|
||||
if (dflag & (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_ONLYV2D))
|
||||
return;
|
||||
|
||||
/* get basic matrix - should be camera space (i.e "identity") */
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
|
||||
|
||||
/* draw points */
|
||||
glPushMatrix();
|
||||
|
||||
for (i = 0, pt = points; i < totpoints; i++, pt++) {
|
||||
/* set the transformed position */
|
||||
// TODO: scale should change based on zoom level, which requires proper translation mult too!
|
||||
modelview[3][0] = pt->x;
|
||||
modelview[3][1] = pt->y;
|
||||
|
||||
glLoadMatrixf((float *)modelview);
|
||||
|
||||
/* draw the disk using the current state... */
|
||||
gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
|
||||
|
||||
|
||||
modelview[3][0] = modelview[3][1] = 0.0f;
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
gluDeleteQuadric(qobj);
|
||||
}
|
||||
|
||||
/* draw a 2D strokes in "volumetric" style */
|
||||
static void gp_draw_stroke_volumetric_2d(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag,
|
||||
int offsx, int offsy, int winx, int winy)
|
||||
{
|
||||
GLUquadricObj *qobj = gluNewQuadric();
|
||||
float modelview[4][4];
|
||||
float baseloc[3];
|
||||
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
|
||||
/* get basic matrix */
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)modelview);
|
||||
copy_v3_v3(baseloc, modelview[3]);
|
||||
|
||||
/* draw points */
|
||||
glPushMatrix();
|
||||
|
||||
for (i = 0, pt = points; i < totpoints; i++, pt++) {
|
||||
/* set the transformed position */
|
||||
float co[2];
|
||||
|
||||
gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
|
||||
translate_m4(modelview, co[0], co[1], 0.0f);
|
||||
|
||||
glLoadMatrixf((float *)modelview);
|
||||
|
||||
/* draw the disk using the current state... */
|
||||
gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
|
||||
|
||||
/* restore matrix */
|
||||
copy_v3_v3(modelview[3], baseloc);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
gluDeleteQuadric(qobj);
|
||||
}
|
||||
|
||||
/* draw a 3D stroke in "volumetric" style */
|
||||
static void gp_draw_stroke_volumetric_3d(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag)
|
||||
{
|
||||
GLUquadricObj *qobj = gluNewQuadric();
|
||||
|
||||
float base_modelview[4][4], modelview[4][4];
|
||||
float base_loc[3];
|
||||
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
|
||||
/* Get the basic modelview matrix we use for performing calculations */
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, (float *)base_modelview);
|
||||
copy_v3_v3(base_loc, base_modelview[3]);
|
||||
|
||||
/* Create the basic view-aligned billboard matrix we're going to actually draw qobj with:
|
||||
* - We need to knock out the rotation so that we are
|
||||
* simply left with a camera-facing billboard
|
||||
* - The scale factors here are chosen so that the thickness
|
||||
* is relatively reasonable. Otherwise, it gets far too
|
||||
* large!
|
||||
*/
|
||||
scale_m4_fl(modelview, 0.1f);
|
||||
|
||||
/* draw each point as a disk... */
|
||||
glPushMatrix();
|
||||
|
||||
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
|
||||
/* apply translation to base_modelview, so that the translated point is put in the right place */
|
||||
translate_m4(base_modelview, pt->x, pt->y, pt->z);
|
||||
|
||||
/* copy the translation component to the billboard matrix we're going to use,
|
||||
* then reset the base matrix to the original values so that we can do the same
|
||||
* for the next point without accumulation/pollution effects
|
||||
*/
|
||||
copy_v3_v3(modelview[3], base_modelview[3]); /* copy offset value */
|
||||
copy_v3_v3(base_modelview[3], base_loc); /* restore */
|
||||
|
||||
/* apply our billboard matrix for drawing... */
|
||||
glLoadMatrixf((float *)modelview);
|
||||
|
||||
/* draw the disk using the current state... */
|
||||
gluDisk(qobj, 0.0, pt->pressure * thickness, 32, 1);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
gluDeleteQuadric(qobj);
|
||||
}
|
||||
|
||||
|
||||
/* --------------- Stroke Fills ----------------- */
|
||||
|
||||
/* draw fills for shapes */
|
||||
static void gp_draw_stroke_fill(bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag,
|
||||
int offsx, int offsy, int winx, int winy)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
BLI_assert(totpoints >= 3);
|
||||
|
||||
/* As an initial implementation, we use the OpenGL filled polygon drawing
|
||||
* here since it's the easiest option to implement for this case. It does
|
||||
* come with limitations (notably for concave shapes), though it shouldn't
|
||||
* be much of an issue in most cases.
|
||||
*/
|
||||
glBegin(GL_POLYGON);
|
||||
|
||||
for (i = 0, pt = points; i < totpoints; i++, pt++) {
|
||||
if (sflag & GP_STROKE_3DSPACE) {
|
||||
glVertex3fv(&pt->x);
|
||||
}
|
||||
else {
|
||||
float co[2];
|
||||
|
||||
gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
|
||||
glVertex2fv(co);
|
||||
}
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
/* ----- Existing Strokes Drawing (3D and Point) ------ */
|
||||
|
||||
/* draw a given stroke - just a single dot (only one point) */
|
||||
@@ -160,18 +359,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
|
||||
float co[2];
|
||||
|
||||
/* get coordinates of point */
|
||||
if (sflag & GP_STROKE_2DSPACE) {
|
||||
co[0] = points->x;
|
||||
co[1] = points->y;
|
||||
}
|
||||
else if (sflag & GP_STROKE_2DIMAGE) {
|
||||
co[0] = (points->x * winx) + offsx;
|
||||
co[1] = (points->y * winy) + offsy;
|
||||
}
|
||||
else {
|
||||
co[0] = (points->x / 100 * winx) + offsx;
|
||||
co[1] = (points->y / 100 * winy) + offsy;
|
||||
}
|
||||
gp_calc_2d_stroke_xy(points, sflag, offsx, offsy, winx, winy, co);
|
||||
|
||||
/* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple dot looks ok
|
||||
* - also mandatory in if Image Editor 'image-based' dot
|
||||
@@ -200,7 +388,7 @@ static void gp_draw_stroke_point(bGPDspoint *points, short thickness, short dfla
|
||||
}
|
||||
|
||||
/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
|
||||
static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, short debug)
|
||||
static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness, bool debug, short sflag)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
float curpressure = points[0].pressure;
|
||||
@@ -233,6 +421,7 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
|
||||
glEnd();
|
||||
|
||||
/* draw debug points of curve on top? */
|
||||
/* XXX: for now, we represent "selected" strokes in the same way as debug, which isn't used anymore */
|
||||
if (debug) {
|
||||
glBegin(GL_POINTS);
|
||||
for (i = 0, pt = points; i < totpoints && pt; i++, pt++)
|
||||
@@ -244,8 +433,8 @@ static void gp_draw_stroke_3d(bGPDspoint *points, int totpoints, short thickness
|
||||
/* ----- Fancy 2D-Stroke Drawing ------ */
|
||||
|
||||
/* draw a given stroke in 2d */
|
||||
static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
|
||||
short debug, int offsx, int offsy, int winx, int winy)
|
||||
static void gp_draw_stroke_2d(bGPDspoint *points, int totpoints, short thickness_s, short dflag, short sflag,
|
||||
bool debug, int offsx, int offsy, int winx, int winy)
|
||||
{
|
||||
/* otherwise thickness is twice that of the 3D view */
|
||||
float thickness = (float)thickness_s * 0.5f;
|
||||
@@ -261,21 +450,10 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
|
||||
if (sflag & GP_STROKE_2DSPACE) {
|
||||
glVertex2f(pt->x, pt->y);
|
||||
}
|
||||
else if (sflag & GP_STROKE_2DIMAGE) {
|
||||
const float x = (pt->x * winx) + offsx;
|
||||
const float y = (pt->y * winy) + offsy;
|
||||
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
else {
|
||||
const float x = (pt->x / 100 * winx) + offsx;
|
||||
const float y = (pt->y / 100 * winy) + offsy;
|
||||
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
float co[2];
|
||||
|
||||
gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
|
||||
glVertex2fv(co);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
@@ -299,22 +477,8 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
|
||||
float pthick; /* thickness at segment point */
|
||||
|
||||
/* get x and y coordinates from points */
|
||||
if (sflag & GP_STROKE_2DSPACE) {
|
||||
s0[0] = pt1->x; s0[1] = pt1->y;
|
||||
s1[0] = pt2->x; s1[1] = pt2->y;
|
||||
}
|
||||
else if (sflag & GP_STROKE_2DIMAGE) {
|
||||
s0[0] = (pt1->x * winx) + offsx;
|
||||
s0[1] = (pt1->y * winy) + offsy;
|
||||
s1[0] = (pt2->x * winx) + offsx;
|
||||
s1[1] = (pt2->y * winy) + offsy;
|
||||
}
|
||||
else {
|
||||
s0[0] = (pt1->x / 100 * winx) + offsx;
|
||||
s0[1] = (pt1->y / 100 * winy) + offsy;
|
||||
s1[0] = (pt2->x / 100 * winx) + offsx;
|
||||
s1[1] = (pt2->y / 100 * winy) + offsy;
|
||||
}
|
||||
gp_calc_2d_stroke_xy(pt1, sflag, offsx, offsy, winx, winy, s0);
|
||||
gp_calc_2d_stroke_xy(pt2, sflag, offsx, offsy, winx, winy, s1);
|
||||
|
||||
/* calculate gradient and normal - 'angle'=(ny/nx) */
|
||||
m1[1] = s1[1] - s0[1];
|
||||
@@ -448,52 +612,57 @@ static void gp_draw_stroke(bGPDspoint *points, int totpoints, short thickness_s,
|
||||
|
||||
glBegin(GL_POINTS);
|
||||
for (i = 0, pt = points; i < totpoints && pt; i++, pt++) {
|
||||
if (sflag & GP_STROKE_2DSPACE) {
|
||||
glVertex2fv(&pt->x);
|
||||
}
|
||||
else if (sflag & GP_STROKE_2DIMAGE) {
|
||||
const float x = (float)((pt->x * winx) + offsx);
|
||||
const float y = (float)((pt->y * winy) + offsy);
|
||||
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
else {
|
||||
const float x = (float)(pt->x / 100 * winx) + offsx;
|
||||
const float y = (float)(pt->y / 100 * winy) + offsy;
|
||||
|
||||
glVertex2f(x, y);
|
||||
}
|
||||
float co[2];
|
||||
|
||||
gp_calc_2d_stroke_xy(pt, sflag, offsx, offsy, winx, winy, co);
|
||||
glVertex2fv(co);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- General Drawing ------ */
|
||||
/* ----- Strokes Drawing ------ */
|
||||
|
||||
/* Helper for doing all the checks on whether a stroke can be drawn */
|
||||
static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
|
||||
{
|
||||
/* skip stroke if it isn't in the right display space for this drawing context */
|
||||
/* 1) 3D Strokes */
|
||||
if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
|
||||
return false;
|
||||
if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
|
||||
return false;
|
||||
|
||||
/* 2) Screen Space 2D Strokes */
|
||||
if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
|
||||
return false;
|
||||
if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
|
||||
return false;
|
||||
|
||||
/* 3) Image Space (2D) */
|
||||
if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
|
||||
return false;
|
||||
if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
|
||||
return false;
|
||||
|
||||
|
||||
/* skip stroke if it doesn't have any valid data */
|
||||
if ((gps->points == NULL) || (gps->totpoints < 1))
|
||||
return false;
|
||||
|
||||
/* stroke can be drawn */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* draw a set of strokes */
|
||||
static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag,
|
||||
short debug, short lthick, const float color[4])
|
||||
bool debug, short lthick, const float color[4], const float fill_color[4])
|
||||
{
|
||||
bGPDstroke *gps;
|
||||
|
||||
/* set color first (may need to reset it again later too) */
|
||||
glColor4fv(color);
|
||||
|
||||
for (gps = gpf->strokes.first; gps; gps = gps->next) {
|
||||
/* check if stroke can be drawn - checks here generally fall into pairs */
|
||||
if ((dflag & GP_DRAWDATA_ONLY3D) && !(gps->flag & GP_STROKE_3DSPACE))
|
||||
continue;
|
||||
if (!(dflag & GP_DRAWDATA_ONLY3D) && (gps->flag & GP_STROKE_3DSPACE))
|
||||
continue;
|
||||
if ((dflag & GP_DRAWDATA_ONLYV2D) && !(gps->flag & GP_STROKE_2DSPACE))
|
||||
continue;
|
||||
if (!(dflag & GP_DRAWDATA_ONLYV2D) && (gps->flag & GP_STROKE_2DSPACE))
|
||||
continue;
|
||||
if ((dflag & GP_DRAWDATA_ONLYI2D) && !(gps->flag & GP_STROKE_2DIMAGE))
|
||||
continue;
|
||||
if (!(dflag & GP_DRAWDATA_ONLYI2D) && (gps->flag & GP_STROKE_2DIMAGE))
|
||||
continue;
|
||||
if ((gps->points == NULL) || (gps->totpoints < 1))
|
||||
/* check if stroke can be drawn */
|
||||
if (gp_can_draw_stroke(gps, dflag) == false)
|
||||
continue;
|
||||
|
||||
/* check which stroke-drawer to use */
|
||||
@@ -515,11 +684,27 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
|
||||
#endif
|
||||
}
|
||||
|
||||
if (gps->totpoints == 1) {
|
||||
gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
|
||||
/* 3D Fill */
|
||||
if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
|
||||
glColor4fv(fill_color);
|
||||
gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
|
||||
}
|
||||
|
||||
/* 3D Stroke */
|
||||
glColor4fv(color);
|
||||
|
||||
if (dflag & GP_DRAWDATA_VOLUMETRIC) {
|
||||
/* volumetric stroke drawing */
|
||||
gp_draw_stroke_volumetric_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag);
|
||||
}
|
||||
else {
|
||||
gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug);
|
||||
/* 3D Lines - OpenGL primitives-based */
|
||||
if (gps->totpoints == 1) {
|
||||
gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
|
||||
}
|
||||
else {
|
||||
gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, debug, gps->flag);
|
||||
}
|
||||
}
|
||||
|
||||
if (no_xray) {
|
||||
@@ -534,16 +719,231 @@ static void gp_draw_strokes(bGPDframe *gpf, int offsx, int offsy, int winx, int
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (gps->totpoints == 1) {
|
||||
gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
|
||||
/* 2D - Fill */
|
||||
if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
|
||||
gp_draw_stroke_fill(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
|
||||
}
|
||||
|
||||
/* 2D Strokes... */
|
||||
glColor4fv(color);
|
||||
|
||||
if (dflag & GP_DRAWDATA_VOLUMETRIC) {
|
||||
/* blob/disk-based "volumetric" drawing */
|
||||
gp_draw_stroke_volumetric_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
|
||||
}
|
||||
else {
|
||||
gp_draw_stroke(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
|
||||
/* normal 2D strokes */
|
||||
if (gps->totpoints == 1) {
|
||||
gp_draw_stroke_point(gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy);
|
||||
}
|
||||
else {
|
||||
gp_draw_stroke_2d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, offsx, offsy, winx, winy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw selected verts for strokes being edited */
|
||||
static void gp_draw_strokes_edit(bGPDframe *gpf, int offsx, int offsy, int winx, int winy, short dflag, const float tcolor[3])
|
||||
{
|
||||
bGPDstroke *gps;
|
||||
|
||||
const int no_xray = (dflag & GP_DRAWDATA_NO_XRAY);
|
||||
int mask_orig = 0;
|
||||
|
||||
/* set up depth masks... */
|
||||
if (dflag & GP_DRAWDATA_ONLY3D) {
|
||||
if (no_xray) {
|
||||
glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
|
||||
glDepthMask(0);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
/* first arg is normally rv3d->dist, but this isn't
|
||||
* available here and seems to work quite well without */
|
||||
bglPolygonOffset(1.0f, 1.0f);
|
||||
#if 0
|
||||
glEnable(GL_POLYGON_OFFSET_LINE);
|
||||
glPolygonOffset(-1.0f, -1.0f);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* draw stroke verts */
|
||||
for (gps = gpf->strokes.first; gps; gps = gps->next) {
|
||||
bGPDspoint *pt;
|
||||
float vsize, bsize;
|
||||
int i;
|
||||
|
||||
/* check if stroke can be drawn */
|
||||
if (gp_can_draw_stroke(gps, dflag) == false)
|
||||
continue;
|
||||
|
||||
/* Optimisation: only draw points for selected strokes
|
||||
* We assume that selected points can only occur in
|
||||
* strokes that are selected too.
|
||||
*/
|
||||
if ((gps->flag & GP_STROKE_SELECT) == 0)
|
||||
continue;
|
||||
|
||||
/* Get size of verts:
|
||||
* - The selected state needs to be larger than the unselected state so that
|
||||
* they stand out more.
|
||||
* - We use the theme setting for size of the unselected verts
|
||||
*/
|
||||
bsize = UI_GetThemeValuef(TH_VERTEX_SIZE);
|
||||
if ((int)bsize > 8) {
|
||||
vsize = 10.0f;
|
||||
bsize = 8.0f;
|
||||
}
|
||||
else {
|
||||
vsize = bsize + 2;
|
||||
}
|
||||
|
||||
/* First Pass: Draw all the verts (i.e. these become the unselected state) */
|
||||
if (tcolor != NULL) {
|
||||
/* for now, we assume that the base color of the points is not too close to the real color */
|
||||
glColor3fv(tcolor);
|
||||
}
|
||||
else {
|
||||
/* this doesn't work well with the default theme and black strokes... */
|
||||
UI_ThemeColor(TH_VERTEX);
|
||||
}
|
||||
glPointSize(bsize);
|
||||
|
||||
glBegin(GL_POINTS);
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
|
||||
if (gps->flag & GP_STROKE_3DSPACE) {
|
||||
glVertex3fv(&pt->x);
|
||||
}
|
||||
else {
|
||||
float co[2];
|
||||
|
||||
gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
|
||||
glVertex2fv(co);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
|
||||
|
||||
/* Second Pass: Draw only verts which are selected */
|
||||
UI_ThemeColor(TH_VERTEX_SELECT);
|
||||
glPointSize(vsize);
|
||||
|
||||
glBegin(GL_POINTS);
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints && pt; i++, pt++) {
|
||||
if (pt->flag & GP_SPOINT_SELECT) {
|
||||
if (gps->flag & GP_STROKE_3DSPACE) {
|
||||
glVertex3fv(&pt->x);
|
||||
}
|
||||
else {
|
||||
float co[2];
|
||||
|
||||
gp_calc_2d_stroke_xy(pt, gps->flag, offsx, offsy, winx, winy, co);
|
||||
glVertex2fv(co);
|
||||
}
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
/* clear depth mask */
|
||||
if (dflag & GP_DRAWDATA_ONLY3D) {
|
||||
if (no_xray) {
|
||||
glDepthMask(mask_orig);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
bglPolygonOffset(0.0, 0.0);
|
||||
#if 0
|
||||
glDisable(GL_POLYGON_OFFSET_LINE);
|
||||
glPolygonOffset(0, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- General Drawing ------ */
|
||||
|
||||
/* draw onion-skinning for a layer */
|
||||
static void gp_draw_onionskins(bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy,
|
||||
int cfra, int dflag, short debug, short lthick)
|
||||
{
|
||||
const float alpha = gpl->color[3];
|
||||
float color[4];
|
||||
|
||||
/* 1) Draw Previous Frames First */
|
||||
if (gpl->flag & GP_LAYER_GHOST_PREVCOL) {
|
||||
copy_v3_v3(color, gpl->gcolor_prev);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(color, gpl->color);
|
||||
}
|
||||
|
||||
if (gpl->gstep) {
|
||||
bGPDframe *gf;
|
||||
float fac;
|
||||
|
||||
/* draw previous frames first */
|
||||
for (gf = gpf->prev; gf; gf = gf->prev) {
|
||||
/* check if frame is drawable */
|
||||
if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
|
||||
/* alpha decreases with distance from curframe index */
|
||||
fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
|
||||
color[3] = alpha * fac * 0.66f;
|
||||
gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
|
||||
if (gpf->prev) {
|
||||
color[3] = (alpha / 7);
|
||||
gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 2) Now draw next frames */
|
||||
if (gpl->flag & GP_LAYER_GHOST_NEXTCOL) {
|
||||
copy_v3_v3(color, gpl->gcolor_next);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(color, gpl->color);
|
||||
}
|
||||
|
||||
if (gpl->gstep_next) {
|
||||
bGPDframe *gf;
|
||||
float fac;
|
||||
|
||||
/* now draw next frames */
|
||||
for (gf = gpf->next; gf; gf = gf->next) {
|
||||
/* check if frame is drawable */
|
||||
if ((gf->framenum - gpf->framenum) <= gpl->gstep_next) {
|
||||
/* alpha decreases with distance from curframe index */
|
||||
fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
|
||||
color[3] = alpha * fac * 0.66f;
|
||||
gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
|
||||
if (gpf->next) {
|
||||
color[3] = (alpha / 4);
|
||||
gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, color, color);
|
||||
}
|
||||
}
|
||||
|
||||
/* 3) restore alpha */
|
||||
glColor4fv(gpl->color);
|
||||
}
|
||||
|
||||
/* draw grease-pencil datablock */
|
||||
static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
|
||||
{
|
||||
@@ -563,9 +963,8 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
bGPDframe *gpf;
|
||||
|
||||
short debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? 1 : 0;
|
||||
bool debug = (gpl->flag & GP_LAYER_DRAWDEBUG) ? true : false;
|
||||
short lthick = gpl->thickness;
|
||||
float color[4], tcolor[4];
|
||||
|
||||
/* don't draw layer if hidden */
|
||||
if (gpl->flag & GP_LAYER_HIDE)
|
||||
@@ -578,72 +977,40 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
|
||||
|
||||
/* set color, stroke thickness, and point size */
|
||||
glLineWidth(lthick);
|
||||
copy_v4_v4(color, gpl->color); // just for copying 4 array elements
|
||||
copy_v4_v4(tcolor, gpl->color); // additional copy of color (for ghosting)
|
||||
glColor4fv(color);
|
||||
glPointSize((float)(gpl->thickness + 2));
|
||||
|
||||
/* apply xray layer setting */
|
||||
if (gpl->flag & GP_LAYER_NO_XRAY) dflag |= GP_DRAWDATA_NO_XRAY;
|
||||
else dflag &= ~GP_DRAWDATA_NO_XRAY;
|
||||
|
||||
/* apply volumetric setting */
|
||||
if (gpl->flag & GP_LAYER_VOLUMETRIC) dflag |= GP_DRAWDATA_VOLUMETRIC;
|
||||
else dflag &= ~GP_DRAWDATA_VOLUMETRIC;
|
||||
|
||||
/* apply fill setting */
|
||||
// XXX: this is not a very good limit
|
||||
if (gpl->fill[3] > 0.001f) dflag |= GP_DRAWDATA_FILL;
|
||||
|
||||
/* draw 'onionskins' (frame left + right) */
|
||||
if (gpl->flag & GP_LAYER_ONIONSKIN) {
|
||||
/* drawing method - only immediately surrounding (gstep = 0),
|
||||
* or within a frame range on either side (gstep > 0)*/
|
||||
if (gpl->gstep) {
|
||||
bGPDframe *gf;
|
||||
float fac;
|
||||
|
||||
/* draw previous frames first */
|
||||
for (gf = gpf->prev; gf; gf = gf->prev) {
|
||||
/* check if frame is drawable */
|
||||
if ((gpf->framenum - gf->framenum) <= gpl->gstep) {
|
||||
/* alpha decreases with distance from curframe index */
|
||||
fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
|
||||
tcolor[3] = color[3] * fac * 0.66f;
|
||||
gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* now draw next frames */
|
||||
for (gf = gpf->next; gf; gf = gf->next) {
|
||||
/* check if frame is drawable */
|
||||
if ((gf->framenum - gpf->framenum) <= gpl->gstep) {
|
||||
/* alpha decreases with distance from curframe index */
|
||||
fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep + 1));
|
||||
tcolor[3] = color[3] * fac * 0.66f;
|
||||
gp_draw_strokes(gf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* restore alpha */
|
||||
glColor4fv(color);
|
||||
}
|
||||
else {
|
||||
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
|
||||
if (gpf->prev) {
|
||||
tcolor[3] = (color[3] / 7);
|
||||
gp_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
|
||||
}
|
||||
|
||||
if (gpf->next) {
|
||||
tcolor[3] = (color[3] / 4);
|
||||
gp_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
|
||||
}
|
||||
|
||||
/* restore alpha */
|
||||
glColor4fv(color);
|
||||
}
|
||||
if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) {
|
||||
/* Drawing method - only immediately surrounding (gstep = 0),
|
||||
* or within a frame range on either side (gstep > 0)
|
||||
*/
|
||||
gp_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, cfra, dflag, debug, lthick);
|
||||
}
|
||||
|
||||
/* draw the strokes already in active frame */
|
||||
tcolor[3] = color[3];
|
||||
gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, tcolor);
|
||||
gp_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, debug, lthick, gpl->color, gpl->fill);
|
||||
|
||||
/* Draw verts of selected strokes
|
||||
* - locked layers can't be edited, so there's no point showing these verts
|
||||
* as they will have no bearings on what gets edited
|
||||
*/
|
||||
/* XXX: perhaps we don't want to show these when users are drawing... */
|
||||
if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
|
||||
gp_draw_strokes_edit(gpf, offsx, offsy, winx, winy, dflag,
|
||||
(gpl->color[3] < 0.95f) ? gpl->color : NULL);
|
||||
}
|
||||
|
||||
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
|
||||
* that is being edited. (Stroke buffer is currently stored in gp-data)
|
||||
@@ -652,8 +1019,17 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
|
||||
(gpf->flag & GP_FRAME_PAINT))
|
||||
{
|
||||
/* Buffer stroke needs to be drawn with a different linestyle
|
||||
* to help differentiate them from normal strokes. */
|
||||
gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
|
||||
* to help differentiate them from normal strokes.
|
||||
*
|
||||
* It should also be noted that sbuffer contains temporary point types
|
||||
* i.e. tGPspoints NOT bGPDspoints
|
||||
*/
|
||||
if (gpl->flag & GP_LAYER_VOLUMETRIC) {
|
||||
gp_draw_stroke_volumetric_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
|
||||
}
|
||||
else {
|
||||
gp_draw_stroke_buffer(gpd->sbuffer, gpd->sbuffer_size, lthick, dflag, gpd->sbuffer_sflag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -253,6 +253,23 @@ void ED_gplayer_frames_duplicate(bGPDlayer *gpl)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set keyframe type for selected frames from given gp-layer
|
||||
* \param type The type of keyframe (eBezTriple_KeyframeType) to set selected frames to
|
||||
*/
|
||||
void ED_gplayer_frames_keytype_set(bGPDlayer *gpl, short type)
|
||||
{
|
||||
bGPDframe *gpf;
|
||||
|
||||
if (gpl == NULL)
|
||||
return;
|
||||
|
||||
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
|
||||
if (gpf->flag & GP_FRAME_SELECT) {
|
||||
gpf->key_type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // XXX disabled until grease pencil code stabilises again
|
||||
/* -------------------------------------- */
|
||||
/* Copy and Paste Tools */
|
||||
|
@@ -145,13 +145,12 @@ static void gp_drawui_layer(uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl, cons
|
||||
/* active */
|
||||
block = uiLayoutGetBlock(sub);
|
||||
icon = (gpl->flag & GP_LAYER_ACTIVE) ? ICON_RADIOBUT_ON : ICON_RADIOBUT_OFF;
|
||||
but = uiDefIconButBitI(block, TOG, GP_LAYER_ACTIVE, 0, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y,
|
||||
but = uiDefIconButBitS(block, TOG, GP_LAYER_ACTIVE, 0, icon, 0, 0, UI_UNIT_X, UI_UNIT_Y,
|
||||
&gpl->flag, 0.0, 0.0, 0.0, 0.0, TIP_("Set active layer"));
|
||||
uiButSetFunc(but, gp_ui_activelayer_cb, gpd, gpl);
|
||||
|
||||
/* locked */
|
||||
icon = (gpl->flag & GP_LAYER_LOCKED) ? ICON_LOCKED : ICON_UNLOCKED;
|
||||
uiItemR(sub, &ptr, "lock", 0, "", icon);
|
||||
uiItemR(sub, &ptr, "lock", 0, "", ICON_NONE);
|
||||
|
||||
/* when layer is locked or hidden, only draw header */
|
||||
if (gpl->flag & (GP_LAYER_LOCKED | GP_LAYER_HIDE)) {
|
||||
@@ -159,7 +158,7 @@ static void gp_drawui_layer(uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl, cons
|
||||
|
||||
/* visibility button (only if hidden but not locked!) */
|
||||
if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED))
|
||||
uiItemR(sub, &ptr, "hide", 0, "", ICON_RESTRICT_VIEW_ON);
|
||||
uiItemR(sub, &ptr, "hide", 0, "", ICON_NONE);
|
||||
|
||||
/* name */
|
||||
if (gpl->flag & GP_LAYER_HIDE)
|
||||
@@ -184,7 +183,7 @@ static void gp_drawui_layer(uiLayout *layout, bGPdata *gpd, bGPDlayer *gpl, cons
|
||||
else {
|
||||
/* draw rest of header -------------------------------- */
|
||||
/* visibility button */
|
||||
uiItemR(sub, &ptr, "hide", 0, "", ICON_RESTRICT_VIEW_OFF);
|
||||
uiItemR(sub, &ptr, "hide", 0, "", ICON_NONE);
|
||||
|
||||
/* frame locking */
|
||||
/* TODO: this needs its own icons... */
|
||||
|
@@ -86,35 +86,51 @@
|
||||
/* ************************************************ */
|
||||
/* Context Wrangling... */
|
||||
|
||||
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
|
||||
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
|
||||
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it,
|
||||
* when context info is not available.
|
||||
*/
|
||||
bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob, PointerRNA *ptr)
|
||||
{
|
||||
ID *screen_id = (ID *)CTX_wm_screen(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
|
||||
/* if there's an active area, check if the particular editor may
|
||||
* have defined any special Grease Pencil context for editing...
|
||||
*/
|
||||
if (sa) {
|
||||
SpaceLink *sl = sa->spacedata.first;
|
||||
|
||||
switch (sa->spacetype) {
|
||||
case SPACE_VIEW3D: /* 3D-View */
|
||||
case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
/* TODO: we can include other data-types such as bones later if need be... */
|
||||
|
||||
/* just in case no active/selected object */
|
||||
if (ob && (ob->flag & SELECT)) {
|
||||
/* for now, as long as there's an object, default to using that in 3D-View */
|
||||
if (ptr) RNA_id_pointer_create(&ob->id, ptr);
|
||||
/* default to using scene's data, unless it doesn't exist (and object's does instead) */
|
||||
/* XXX: this will require a toggle switch later to be more predictable */
|
||||
bool scene_ok = (scene != NULL);
|
||||
bool ob_ok = ((ob) && (ob->flag & SELECT) && (ob->gpd));
|
||||
|
||||
if (ob_ok || !scene_ok) {
|
||||
/* Object Case (not good for users):
|
||||
* - For existing files with object-level already,
|
||||
* or where user has explicitly assigned to object,
|
||||
* we can use the object as the host...
|
||||
*
|
||||
* - If there is no scene data provided (rare/impossible)
|
||||
* we will also be forced to use the object
|
||||
*/
|
||||
if (ptr) RNA_id_pointer_create((ID *)ob, ptr);
|
||||
return &ob->gpd;
|
||||
}
|
||||
else {
|
||||
/* Scene Case (default):
|
||||
* This is the new (as of 2014-Oct-13, for 2.73) default setting
|
||||
* which should work better for most users.
|
||||
*/
|
||||
if (ptr) RNA_id_pointer_create((ID *)scene, ptr);
|
||||
return &scene->gpd;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPACE_NODE: /* Nodes Editor */
|
||||
{
|
||||
SpaceNode *snode = (SpaceNode *)CTX_wm_space_data(C);
|
||||
SpaceNode *snode = (SpaceNode *)sl;
|
||||
|
||||
/* return the GP data for the active node block/node */
|
||||
if (snode && snode->nodetree) {
|
||||
@@ -128,7 +144,7 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
|
||||
}
|
||||
case SPACE_SEQ: /* Sequencer */
|
||||
{
|
||||
SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
|
||||
SpaceSeq *sseq = (SpaceSeq *)sl;
|
||||
|
||||
/* for now, Grease Pencil data is associated with the space (actually preview region only) */
|
||||
/* XXX our convention for everything else is to link to data though... */
|
||||
@@ -137,7 +153,7 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
|
||||
}
|
||||
case SPACE_IMAGE: /* Image/UV Editor */
|
||||
{
|
||||
SpaceImage *sima = (SpaceImage *)CTX_wm_space_data(C);
|
||||
SpaceImage *sima = (SpaceImage *)sl;
|
||||
|
||||
/* for now, Grease Pencil data is associated with the space... */
|
||||
/* XXX our convention for everything else is to link to data though... */
|
||||
@@ -146,7 +162,7 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
|
||||
}
|
||||
case SPACE_CLIP: /* Nodes Editor */
|
||||
{
|
||||
SpaceClip *sc = (SpaceClip *)CTX_wm_space_data(C);
|
||||
SpaceClip *sc = (SpaceClip *)sl;
|
||||
MovieClip *clip = ED_space_clip_get_clip(sc);
|
||||
|
||||
if (clip) {
|
||||
@@ -180,6 +196,26 @@ bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
|
||||
return (scene) ? &scene->gpd : NULL;
|
||||
}
|
||||
|
||||
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
|
||||
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
|
||||
{
|
||||
ID *screen_id = (ID *)CTX_wm_screen(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
return ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, ptr);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
/* Get the active Grease Pencil datablock, when context is not available */
|
||||
bGPdata *ED_gpencil_data_get_active_direct(ID *screen_id, Scene *scene, ScrArea *sa, Object *ob)
|
||||
{
|
||||
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(screen_id, scene, sa, ob, NULL);
|
||||
return (gpd_ptr) ? *(gpd_ptr) : NULL;
|
||||
}
|
||||
|
||||
/* Get the active Grease Pencil datablock */
|
||||
bGPdata *ED_gpencil_data_get_active(const bContext *C)
|
||||
{
|
||||
@@ -187,6 +223,8 @@ bGPdata *ED_gpencil_data_get_active(const bContext *C)
|
||||
return (gpd_ptr) ? *(gpd_ptr) : NULL;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
bGPdata *ED_gpencil_data_get_active_v3d(Scene *scene, View3D *v3d)
|
||||
{
|
||||
Base *base = scene->basact;
|
||||
@@ -211,6 +249,15 @@ static int gp_add_poll(bContext *C)
|
||||
return ED_gpencil_data_get_pointers(C, NULL) != NULL;
|
||||
}
|
||||
|
||||
/* poll callback for checking if there is an active layer */
|
||||
static int gp_active_layer_poll(bContext *C)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
return (gpl != NULL);
|
||||
}
|
||||
|
||||
/* ******************* Add New Data ************************ */
|
||||
|
||||
/* add new datablock - wrapper around API */
|
||||
@@ -327,13 +374,268 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
|
||||
ot->name = "Add New Layer";
|
||||
ot->idname = "GPENCIL_OT_layer_add";
|
||||
ot->description = "Add new Grease Pencil layer for the active Grease Pencil datablock";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = gp_layer_add_exec;
|
||||
ot->poll = gp_add_poll;
|
||||
}
|
||||
|
||||
/* ******************* Remove Active Layer ************************* */
|
||||
|
||||
static int gp_layer_remove_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM(NULL, gpd, gpl))
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
if (gpl->flag & GP_LAYER_LOCKED) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Cannot delete locked layers");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* make the layer before this the new active layer
|
||||
* - use the one after if this is the first
|
||||
* - if this is the only layer, this naturally becomes NULL
|
||||
*/
|
||||
if (gpl->prev)
|
||||
gpencil_layer_setactive(gpd, gpl->prev);
|
||||
else
|
||||
gpencil_layer_setactive(gpd, gpl->next);
|
||||
|
||||
/* delete the layer now... */
|
||||
gpencil_layer_delete(gpd, gpl);
|
||||
|
||||
/* notifiers */
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_layer_remove(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Remove Layer";
|
||||
ot->idname = "GPENCIL_OT_layer_remove";
|
||||
ot->description = "Remove active Grease Pencil layer";
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = gp_layer_remove_exec;
|
||||
ot->poll = gp_active_layer_poll;
|
||||
}
|
||||
|
||||
/* ******************* Move Layer Up/Down ************************** */
|
||||
|
||||
enum {
|
||||
GP_LAYER_MOVE_UP = -1,
|
||||
GP_LAYER_MOVE_DOWN = 1
|
||||
};
|
||||
|
||||
static int gp_layer_move_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
int direction = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM(NULL, gpd, gpl))
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
/* up or down? */
|
||||
if (direction == GP_LAYER_MOVE_UP) {
|
||||
/* up */
|
||||
BLI_remlink(&gpd->layers, gpl);
|
||||
BLI_insertlinkbefore(&gpd->layers, gpl->prev, gpl);
|
||||
}
|
||||
else {
|
||||
/* down */
|
||||
BLI_remlink(&gpd->layers, gpl);
|
||||
BLI_insertlinkafter(&gpd->layers, gpl->next, gpl);
|
||||
}
|
||||
|
||||
/* notifiers */
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_layer_move(wmOperatorType *ot)
|
||||
{
|
||||
static EnumPropertyItem slot_move[] = {
|
||||
{GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
|
||||
{GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Move Grease Pencil Layer";
|
||||
ot->idname = "GPENCIL_OT_layer_move";
|
||||
ot->description = "Move the active Grease Pencil layer up/down in the list";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = gp_layer_move_exec;
|
||||
ot->poll = gp_active_layer_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
|
||||
}
|
||||
|
||||
/* ******************* Copy Selected Strokes *********************** */
|
||||
|
||||
static int gp_strokes_copy_poll(bContext *C)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
/* only if there's an active layer with an active frame */
|
||||
/* TODO: we probably require some selected strokes too? */
|
||||
return (gpl && gpl->actframe);
|
||||
}
|
||||
|
||||
/* Make copies of selected point segments in a selected stroke */
|
||||
static void gp_strokes_copy_points(const bGPDstroke *gps, ListBase *new_strokes)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
int start_idx = -1;
|
||||
|
||||
|
||||
/* Step through the original stroke's points:
|
||||
* - We accumulate selected points (from start_idx to current index)
|
||||
* and then convert that to a new stroke
|
||||
*/
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
/* searching for start, are waiting for end? */
|
||||
if (start_idx == -1) {
|
||||
/* is this the first selected point for a new island? */
|
||||
if (pt->flag & GP_SPOINT_SELECT) {
|
||||
start_idx = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t len = 0;
|
||||
|
||||
/* is this the end of current island yet?
|
||||
* 1) Point i-1 was the last one that was selected
|
||||
* 2) Point i is the last in the array
|
||||
*/
|
||||
if ((pt->flag & GP_SPOINT_SELECT) == 0) {
|
||||
len = i - start_idx;
|
||||
}
|
||||
else if (i == gps->totpoints - 1) {
|
||||
len = i - start_idx + 1;
|
||||
}
|
||||
//printf("copying from %d to %d = %d\n", start_idx, i, len);
|
||||
|
||||
/* make copies of the relevant data */
|
||||
if (len) {
|
||||
bGPDstroke *gpsd;
|
||||
|
||||
/* make a stupid copy first of the entire stroke (to get the flags too) */
|
||||
gpsd = MEM_dupallocN(gps);
|
||||
|
||||
/* now, make a new points array, and copy of the relevant parts */
|
||||
gpsd->points = MEM_callocN(sizeof(bGPDspoint) * len, "gps stroke points copy");
|
||||
memcpy(gpsd->points, gps->points + start_idx, sizeof(bGPDspoint) * len);
|
||||
gpsd->totpoints = len;
|
||||
|
||||
/* add to temp buffer */
|
||||
gpsd->next = gpsd->prev = NULL;
|
||||
BLI_addtail(new_strokes, gpsd);
|
||||
|
||||
/* cleanup + reset for next */
|
||||
start_idx = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bGPDlayer *gpl;
|
||||
|
||||
if (gpd == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* for each visible (and editable) layer's selected strokes,
|
||||
* copy the strokes into a temporary buffer, then append
|
||||
* once all done
|
||||
*/
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
|
||||
(gpl->actframe != NULL))
|
||||
{
|
||||
ListBase new_strokes = {NULL, NULL};
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
bGPDstroke *gps;
|
||||
|
||||
/* make copies of selected strokes, and deselect these once we're done */
|
||||
for (gps = gpf->strokes.first; gps; gps = gps->next) {
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
if (gps->totpoints == 1) {
|
||||
/* Special Case: If there's just a single point in this stroke... */
|
||||
bGPDstroke *gpsd;
|
||||
|
||||
/* make direct copies of the stroke and its points */
|
||||
gpsd = MEM_dupallocN(gps);
|
||||
gpsd->points = MEM_dupallocN(gps->points);
|
||||
|
||||
/* add to temp buffer */
|
||||
gpsd->next = gpsd->prev = NULL;
|
||||
BLI_addtail(&new_strokes, gpsd);
|
||||
}
|
||||
else {
|
||||
/* delegate to a helper, as there's too much to fit in here (for copying subsets)... */
|
||||
gp_strokes_copy_points(gps, &new_strokes);
|
||||
}
|
||||
|
||||
/* deselect original stroke, or else the originals get moved too
|
||||
* (when using the copy + move macro)
|
||||
*/
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
/* add all new strokes in temp buffer to the frame (preventing double-copies) */
|
||||
BLI_movelisttolist(&gpf->strokes, &new_strokes);
|
||||
BLI_assert(new_strokes.first == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* updates */
|
||||
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_strokes_copy(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Copy Strokes";
|
||||
ot->idname = "GPENCIL_OT_strokes_copy";
|
||||
ot->description = "Duplicate the selected Grease Pencil strokes";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = gp_strokes_copy_exec;
|
||||
ot->poll = gp_strokes_copy_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ******************* Delete Active Frame ************************ */
|
||||
|
||||
static int gp_actframe_delete_poll(bContext *C)
|
||||
|
@@ -31,14 +31,73 @@
|
||||
#ifndef __GPENCIL_INTERN_H__
|
||||
#define __GPENCIL_INTERN_H__
|
||||
|
||||
|
||||
#include "DNA_vec_types.h"
|
||||
|
||||
|
||||
/* internal exports only */
|
||||
struct bGPdata;
|
||||
struct bGPDstroke;
|
||||
struct bGPDspoint;
|
||||
|
||||
struct ARegion;
|
||||
struct View2D;
|
||||
struct wmOperatorType;
|
||||
|
||||
|
||||
/* ***************************************************** */
|
||||
/* Operator Defines */
|
||||
/* Internal API */
|
||||
|
||||
struct bGPdata;
|
||||
struct wmOperatorType;
|
||||
/* Stroke Coordinates API ------------------------------ */
|
||||
/* gpencil_utils.c */
|
||||
|
||||
typedef struct GP_SpaceConversion {
|
||||
struct bGPdata *gpd;
|
||||
struct bGPDlayer *gpl;
|
||||
|
||||
struct ScrArea *sa;
|
||||
struct ARegion *ar;
|
||||
struct View2D *v2d;
|
||||
|
||||
rctf *subrect; /* for using the camera rect within the 3d view */
|
||||
rctf subrect_data;
|
||||
|
||||
float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
|
||||
} GP_SpaceConversion;
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a given stroke segment is inside a circular brush
|
||||
*
|
||||
* \param mval The current screen-space coordinates (midpoint) of the brush
|
||||
* \param mvalo The previous screen-space coordinates (midpoint) of the brush (NOT CURRENTLY USED)
|
||||
* \param rad The radius of the brush
|
||||
*
|
||||
* \param x0, y0 The screen-space x and y coordinates of the start of the stroke segment
|
||||
* \param x1, y1 The screen-space x and y coordinates of the end of the stroke segment
|
||||
*/
|
||||
bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
|
||||
int rad, int x0, int y0, int x1, int y1);
|
||||
|
||||
|
||||
/**
|
||||
* Init settings for stroke point space conversions
|
||||
*
|
||||
* \param[out] r_gsc The space conversion settings struct, populated with necessary params
|
||||
*/
|
||||
void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
|
||||
|
||||
/**
|
||||
* Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
|
||||
*
|
||||
* \param[out] r_x The screen-space x-coordinate of the point
|
||||
* \param[out] r_y The screen-space y-coordinate of the point
|
||||
*/
|
||||
void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct bGPDspoint *pt,
|
||||
int *r_x, int *r_y);
|
||||
|
||||
/* ***************************************************** */
|
||||
/* Operator Defines */
|
||||
|
||||
/* drawing ---------- */
|
||||
|
||||
@@ -52,12 +111,23 @@ typedef enum eGPencil_PaintModes {
|
||||
GP_PAINTMODE_DRAW_POLY
|
||||
} eGPencil_PaintModes;
|
||||
|
||||
/* stroke editing ----- */
|
||||
|
||||
void GPENCIL_OT_select(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_select_all(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_select_circle(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_select_border(struct wmOperatorType *ot);
|
||||
|
||||
void GPENCIL_OT_strokes_copy(struct wmOperatorType *ot);
|
||||
|
||||
/* buttons editing --- */
|
||||
|
||||
void GPENCIL_OT_data_add(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_data_unlink(struct wmOperatorType *ot);
|
||||
|
||||
void GPENCIL_OT_layer_add(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_layer_remove(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_layer_move(struct wmOperatorType *ot);
|
||||
|
||||
void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot);
|
||||
|
||||
|
@@ -36,40 +36,130 @@
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "ED_gpencil.h"
|
||||
#include "ED_transform.h"
|
||||
|
||||
#include "gpencil_intern.h"
|
||||
|
||||
/* ****************************************** */
|
||||
/* Generic Editing Keymap */
|
||||
/* Grease Pencil Keymaps */
|
||||
|
||||
void ED_keymap_gpencil(wmKeyConfig *keyconf)
|
||||
/* Generic Drawing Keymap */
|
||||
static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil", 0, 0);
|
||||
wmKeyMapItem *kmi;
|
||||
|
||||
/* Draw */
|
||||
|
||||
/* Draw --------------------------------------- */
|
||||
/* draw */
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, 0, DKEY);
|
||||
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW);
|
||||
|
||||
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
|
||||
|
||||
/* draw - straight lines */
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_CTRL, DKEY);
|
||||
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_STRAIGHT);
|
||||
|
||||
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
|
||||
|
||||
/* draw - poly lines */
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, KM_CTRL, DKEY);
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", LEFTMOUSE, KM_PRESS, KM_ALT, DKEY);
|
||||
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_DRAW_POLY);
|
||||
|
||||
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
|
||||
|
||||
/* erase */
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_draw", RIGHTMOUSE, KM_PRESS, 0, DKEY);
|
||||
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
|
||||
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
|
||||
|
||||
/* Viewport Tools ------------------------------- */
|
||||
|
||||
/* Enter EditMode */
|
||||
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, 0, DKEY);
|
||||
RNA_string_set(kmi->ptr, "data_path", "gpencil_data.use_stroke_edit_mode");
|
||||
|
||||
/* Pie Menu - For standard tools */
|
||||
WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", DKEY, KM_DBL_CLICK, 0, 0);
|
||||
}
|
||||
|
||||
/* ==================== */
|
||||
|
||||
/* Poll callback for stroke editing mode */
|
||||
static int gp_stroke_editmode_poll(bContext *C)
|
||||
{
|
||||
bGPdata *gpd = CTX_data_gpencil_data(C);
|
||||
return (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE));
|
||||
}
|
||||
|
||||
/* Stroke Editing Keymap - Only when editmode is enabled */
|
||||
static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_find(keyconf, "Grease Pencil Stroke Edit Mode", 0, 0);
|
||||
wmKeyMapItem *kmi;
|
||||
|
||||
/* set poll callback - so that this keymap only gets enabled when stroke editmode is enabled */
|
||||
keymap->poll = gp_stroke_editmode_poll;
|
||||
|
||||
/* Selection ------------------------------------- */
|
||||
/* select all */
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", AKEY, KM_PRESS, 0, 0);
|
||||
RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
|
||||
RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
|
||||
|
||||
/* circle select */
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_select_circle", CKEY, KM_PRESS, 0, 0);
|
||||
|
||||
/* border select */
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_select_border", BKEY, KM_PRESS, 0, 0);
|
||||
|
||||
/* normal select */
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "extend", true);
|
||||
RNA_boolean_set(kmi->ptr, "toggle", true);
|
||||
|
||||
/* whole stroke select */
|
||||
kmi = WM_keymap_add_item(keymap, "GPENCIL_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "entire_strokes", true);
|
||||
|
||||
|
||||
/* Editing ----------------------------------------- */
|
||||
|
||||
/* duplicate and move selected points */
|
||||
WM_keymap_add_item(keymap, "GPENCIL_OT_strokes_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
|
||||
|
||||
/* Transform Tools */
|
||||
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
|
||||
RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
|
||||
RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
|
||||
RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0);
|
||||
RNA_boolean_set(kmi->ptr, "gpencil_strokes", true);
|
||||
}
|
||||
|
||||
/* ==================== */
|
||||
|
||||
void ED_keymap_gpencil(wmKeyConfig *keyconf)
|
||||
{
|
||||
ed_keymap_gpencil_general(keyconf);
|
||||
ed_keymap_gpencil_editing(keyconf);
|
||||
}
|
||||
|
||||
/* ****************************************** */
|
||||
@@ -80,12 +170,23 @@ void ED_operatortypes_gpencil(void)
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_draw);
|
||||
|
||||
/* Editing (Strokes) ------------ */
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_select);
|
||||
WM_operatortype_append(GPENCIL_OT_select_all);
|
||||
WM_operatortype_append(GPENCIL_OT_select_circle);
|
||||
WM_operatortype_append(GPENCIL_OT_select_border);
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_strokes_copy);
|
||||
|
||||
/* Editing (Buttons) ------------ */
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_data_add);
|
||||
WM_operatortype_append(GPENCIL_OT_data_unlink);
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_layer_add);
|
||||
WM_operatortype_append(GPENCIL_OT_layer_remove);
|
||||
WM_operatortype_append(GPENCIL_OT_layer_move);
|
||||
|
||||
WM_operatortype_append(GPENCIL_OT_active_frame_delete);
|
||||
|
||||
@@ -94,4 +195,17 @@ void ED_operatortypes_gpencil(void)
|
||||
/* Editing (Time) --------------- */
|
||||
}
|
||||
|
||||
void ED_operatormacros_gpencil(void)
|
||||
{
|
||||
wmOperatorType *ot;
|
||||
wmOperatorTypeMacro *otmacro;
|
||||
|
||||
ot = WM_operatortype_append_macro("GPENCIL_OT_strokes_duplicate", "Duplicate Strokes",
|
||||
"Make copies of the selected Grease Pencil strokes and move them",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
WM_operatortype_macro_define(ot, "GPENCIL_OT_strokes_copy");
|
||||
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
|
||||
RNA_enum_set(otmacro->ptr, "gpencil_strokes", true);
|
||||
}
|
||||
|
||||
/* ****************************************** */
|
||||
|
@@ -86,6 +86,8 @@ typedef struct tGPsdata {
|
||||
rctf *subrect; /* for using the camera rect within the 3d view */
|
||||
rctf subrect_data;
|
||||
|
||||
GP_SpaceConversion gsc; /* settings to pass to gp_points_to_xy() */
|
||||
|
||||
PointerRNA ownerPtr; /* pointer to owner of gp-datablock */
|
||||
bGPdata *gpd; /* gp-datablock layer comes from */
|
||||
bGPDlayer *gpl; /* layer we're working on */
|
||||
@@ -875,58 +877,6 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
|
||||
static short gp_stroke_eraser_strokeinside(const int mval[2], const int UNUSED(mvalo[2]),
|
||||
int rad, int x0, int y0, int x1, int y1)
|
||||
{
|
||||
/* simple within-radius check for now */
|
||||
const float mval_fl[2] = {mval[0], mval[1]};
|
||||
const float screen_co_a[2] = {x0, y0};
|
||||
const float screen_co_b[2] = {x1, y1};
|
||||
|
||||
if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* not inside */
|
||||
return false;
|
||||
}
|
||||
|
||||
static void gp_point_to_xy(tGPsdata *p, bGPDstroke *gps, bGPDspoint *pt,
|
||||
int *r_x, int *r_y)
|
||||
{
|
||||
ARegion *ar = p->ar;
|
||||
View2D *v2d = p->v2d;
|
||||
rctf *subrect = p->subrect;
|
||||
int xyval[2];
|
||||
|
||||
if (gps->flag & GP_STROKE_3DSPACE) {
|
||||
if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
|
||||
*r_x = xyval[0];
|
||||
*r_y = xyval[1];
|
||||
}
|
||||
else {
|
||||
*r_x = V2D_IS_CLIPPED;
|
||||
*r_y = V2D_IS_CLIPPED;
|
||||
}
|
||||
}
|
||||
else if (gps->flag & GP_STROKE_2DSPACE) {
|
||||
float vec[3] = {pt->x, pt->y, 0.0f};
|
||||
mul_m4_v3(p->mat, vec);
|
||||
UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
|
||||
}
|
||||
else {
|
||||
if (subrect == NULL) { /* normal 3D view */
|
||||
*r_x = (int)(pt->x / 100 * ar->winx);
|
||||
*r_y = (int)(pt->y / 100 * ar->winy);
|
||||
}
|
||||
else { /* camera view, use subrect */
|
||||
*r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
|
||||
*r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* eraser tool - evaluation per stroke */
|
||||
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
|
||||
@@ -945,7 +895,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
|
||||
BLI_freelinkN(&gpf->strokes, gps);
|
||||
}
|
||||
else if (gps->totpoints == 1) {
|
||||
gp_point_to_xy(p, gps, gps->points, &x0, &y0);
|
||||
gp_point_to_xy(&p->gsc, gps, gps->points, &x0, &y0);
|
||||
|
||||
/* do boundbox check first */
|
||||
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
|
||||
@@ -966,8 +916,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
|
||||
pt1 = gps->points + i;
|
||||
pt2 = gps->points + i + 1;
|
||||
|
||||
gp_point_to_xy(p, gps, pt1, &x0, &y0);
|
||||
gp_point_to_xy(p, gps, pt2, &x1, &y1);
|
||||
gp_point_to_xy(&p->gsc, gps, pt1, &x0, &y0);
|
||||
gp_point_to_xy(&p->gsc, gps, pt2, &x1, &y1);
|
||||
|
||||
/* check that point segment of the boundbox of the eraser stroke */
|
||||
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
|
||||
@@ -977,7 +927,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
|
||||
* eraser region (either within stroke painted, or on its lines)
|
||||
* - this assumes that linewidth is irrelevant
|
||||
*/
|
||||
if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
|
||||
if (gp_stroke_inside_circle(mval, mvalo, rad, x0, y0, x1, y1)) {
|
||||
if ((gp_stroke_eraser_is_occluded(p, pt1, x0, y0) == false) ||
|
||||
(gp_stroke_eraser_is_occluded(p, pt2, x1, y1) == false))
|
||||
{
|
||||
@@ -1068,6 +1018,7 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
|
||||
p->win = CTX_wm_window(C);
|
||||
|
||||
unit_m4(p->imat);
|
||||
unit_m4(p->mat);
|
||||
|
||||
switch (curarea->spacetype) {
|
||||
/* supported views first */
|
||||
@@ -1154,7 +1105,9 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
|
||||
p->imat[3][0] -= marker->pos[0];
|
||||
p->imat[3][1] -= marker->pos[1];
|
||||
}
|
||||
|
||||
invert_m4_m4(p->mat, p->imat);
|
||||
copy_m4_m4(p->gsc.mat, p->mat);
|
||||
break;
|
||||
}
|
||||
/* unsupported views */
|
||||
@@ -1290,7 +1243,21 @@ static void gp_paint_initstroke(tGPsdata *p, short paintmode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* init stroke point space-conversion settings... */
|
||||
p->gsc.gpd = p->gpd;
|
||||
p->gsc.gpl = p->gpl;
|
||||
|
||||
p->gsc.sa = p->sa;
|
||||
p->gsc.ar = p->ar;
|
||||
p->gsc.v2d = p->v2d;
|
||||
|
||||
p->gsc.subrect_data = p->subrect_data;
|
||||
p->gsc.subrect = p->subrect;
|
||||
|
||||
copy_m4_m4(p->gsc.mat, p->mat);
|
||||
|
||||
|
||||
/* check if points will need to be made in view-aligned space */
|
||||
if (p->gpd->flag & GP_DATA_VIEWALIGN) {
|
||||
switch (p->sa->spacetype) {
|
||||
@@ -1772,11 +1739,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
|
||||
else
|
||||
WM_cursor_modal_set(win, BC_PAINTBRUSHCURSOR);
|
||||
|
||||
/* special hack: if there was an initial event, then we were invoked via a hotkey, and
|
||||
* painting should start immediately. Otherwise, this was called from a toolbar, in which
|
||||
* case we should wait for the mouse to be clicked.
|
||||
*/
|
||||
if (event->val == KM_PRESS) {
|
||||
/* only start drawing immediately if we're allowed to do so... */
|
||||
if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
|
||||
/* hotkey invoked - start drawing */
|
||||
/* printf("\tGP - set first spot\n"); */
|
||||
p->status = GP_STATUS_PAINTING;
|
||||
@@ -2053,6 +2017,8 @@ void GPENCIL_OT_draw(wmOperatorType *ot)
|
||||
|
||||
/* settings for drawing */
|
||||
ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
|
||||
|
||||
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
|
||||
|
||||
/* NOTE: wait for input is enabled by default, so that all UI code can work properly without needing users to know about this */
|
||||
RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "Wait for first click instead of painting immediately");
|
||||
}
|
||||
|
658
source/blender/editors/gpencil/gpencil_select.c
Normal file
658
source/blender/editors/gpencil/gpencil_select.c
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* ***** 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) 2014, Blender Foundation
|
||||
* This is a new part of Blender
|
||||
*
|
||||
* Contributor(s): Joshua Leung
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/editors/gpencil/gpencil_select.c
|
||||
* \ingroup edgpencil
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_curve.h"
|
||||
#include "BKE_depsgraph.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "ED_gpencil.h"
|
||||
#include "ED_view3d.h"
|
||||
#include "ED_keyframing.h"
|
||||
|
||||
#include "gpencil_intern.h"
|
||||
|
||||
/* ********************************************** */
|
||||
/* Polling callbacks */
|
||||
|
||||
static int gpencil_select_poll(bContext *C)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
/* only if there's an active layer with an active frame */
|
||||
return (gpl && gpl->actframe);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Select All Operator */
|
||||
|
||||
static int gpencil_select_all_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
int action = RNA_enum_get(op->ptr, "action");
|
||||
|
||||
if (gpd == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* for "toggle", test for existing selected strokes */
|
||||
if (action == SEL_TOGGLE) {
|
||||
action = SEL_SELECT;
|
||||
|
||||
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
|
||||
{
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
action = SEL_DESELECT;
|
||||
break; // XXX: this only gets out of the inner loop...
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
}
|
||||
|
||||
/* if deselecting, we need to deselect strokes across all frames
|
||||
* - Currently, an exception is only given for deselection
|
||||
* Selecting and toggling should only affect what's visible,
|
||||
* while deselecting helps clean up unintended/forgotten
|
||||
* stuff on other frames
|
||||
*/
|
||||
if (action == SEL_DESELECT) {
|
||||
/* deselect strokes across editable layers
|
||||
* NOTE: we limit ourselves to editable layers, since once a layer is "locked/hidden
|
||||
* nothing should be able to touch it
|
||||
*/
|
||||
CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
|
||||
{
|
||||
bGPDframe *gpf;
|
||||
|
||||
/* deselect all strokes on all frames */
|
||||
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
|
||||
bGPDstroke *gps;
|
||||
|
||||
for (gps = gpf->strokes.first; gps; gps = gps->next) {
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
}
|
||||
else {
|
||||
/* select or deselect all strokes */
|
||||
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
bool selected = false;
|
||||
|
||||
/* Change selection status of all points, then make the stroke match */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
switch (action) {
|
||||
case SEL_SELECT:
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
break;
|
||||
//case SEL_DESELECT:
|
||||
// pt->flag &= ~GP_SPOINT_SELECT;
|
||||
// break;
|
||||
case SEL_INVERT:
|
||||
pt->flag ^= GP_SPOINT_SELECT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pt->flag & GP_SPOINT_SELECT)
|
||||
selected = true;
|
||||
}
|
||||
|
||||
/* Change status of stroke */
|
||||
if (selected)
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
else
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
CTX_DATA_END;
|
||||
}
|
||||
|
||||
/* updates */
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_select_all(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "(De)select All Strokes";
|
||||
ot->idname = "GPENCIL_OT_select_all";
|
||||
ot->description = "Change selection of all Grease Pencil strokes currently visible";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = gpencil_select_all_exec;
|
||||
ot->poll = gpencil_select_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
WM_operator_properties_select_all(ot);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Circle Select Operator */
|
||||
|
||||
/* Helper to check if a given stroke is within the area */
|
||||
/* NOTE: Code here is adapted (i.e. copied directly) from gpencil_paint.c::gp_stroke_eraser_dostroke()
|
||||
* It would be great to de-duplicate the logic here sometime, but that can wait...
|
||||
*/
|
||||
static bool gp_stroke_do_circle_sel(bGPDstroke *gps, GP_SpaceConversion *gsc,
|
||||
const int mx, const int my, const int radius,
|
||||
const bool select, rcti *rect)
|
||||
{
|
||||
bGPDspoint *pt1, *pt2;
|
||||
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
|
||||
int i;
|
||||
bool changed = false;
|
||||
|
||||
if (gps->totpoints == 1) {
|
||||
gp_point_to_xy(gsc, gps, gps->points, &x0, &y0);
|
||||
|
||||
/* do boundbox check first */
|
||||
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
|
||||
/* only check if point is inside */
|
||||
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
|
||||
/* change selection */
|
||||
if (select) {
|
||||
gps->points->flag |= GP_SPOINT_SELECT;
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
}
|
||||
else {
|
||||
gps->points->flag &= ~GP_SPOINT_SELECT;
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Loop over the points in the stroke, checking for intersections
|
||||
* - an intersection means that we touched the stroke
|
||||
*/
|
||||
for (i = 0; (i + 1) < gps->totpoints; i++) {
|
||||
/* get points to work with */
|
||||
pt1 = gps->points + i;
|
||||
pt2 = gps->points + i + 1;
|
||||
|
||||
gp_point_to_xy(gsc, gps, pt1, &x0, &y0);
|
||||
gp_point_to_xy(gsc, gps, pt2, &x1, &y1);
|
||||
|
||||
/* check that point segment of the boundbox of the selection stroke */
|
||||
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
|
||||
((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1)))
|
||||
{
|
||||
int mval[2] = {mx, my};
|
||||
int mvalo[2] = {mx, my}; /* dummy - this isn't used... */
|
||||
|
||||
/* check if point segment of stroke had anything to do with
|
||||
* eraser region (either within stroke painted, or on its lines)
|
||||
* - this assumes that linewidth is irrelevant
|
||||
*/
|
||||
if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) {
|
||||
/* change selection of stroke, and then of both points
|
||||
* (as the last point otherwise wouldn't get selected
|
||||
* as we only do n-1 loops through)
|
||||
*/
|
||||
if (select) {
|
||||
pt1->flag |= GP_SPOINT_SELECT;
|
||||
pt2->flag |= GP_SPOINT_SELECT;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
pt1->flag &= ~GP_SPOINT_SELECT;
|
||||
pt2->flag &= ~GP_SPOINT_SELECT;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that stroke selection is in sync with its points */
|
||||
gpencil_stroke_sync_selection(gps);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
|
||||
const int mx = RNA_int_get(op->ptr, "x");
|
||||
const int my = RNA_int_get(op->ptr, "y");
|
||||
const int radius = RNA_int_get(op->ptr, "radius");
|
||||
|
||||
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
|
||||
const bool select = (gesture_mode == GESTURE_MODAL_SELECT);
|
||||
|
||||
GP_SpaceConversion gsc = {0};
|
||||
rcti rect = {0}; /* for bounding rect around circle (for quicky intersection testing) */
|
||||
|
||||
bool changed = false;
|
||||
|
||||
|
||||
/* sanity checks */
|
||||
if (sa == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No active area");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* init space conversion stuff */
|
||||
gp_point_conversion_init(C, &gsc);
|
||||
|
||||
|
||||
/* rect is rectangle of selection circle */
|
||||
rect.xmin = mx - radius;
|
||||
rect.ymin = my - radius;
|
||||
rect.xmax = mx + radius;
|
||||
rect.ymax = my + radius;
|
||||
|
||||
|
||||
/* find visible strokes, and select if hit */
|
||||
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
|
||||
{
|
||||
changed |= gp_stroke_do_circle_sel(gps, &gsc, mx, my, radius, select, &rect);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* updates */
|
||||
if (changed) {
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_select_circle(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Circle Select";
|
||||
ot->description = "Select Grease Pencil strokes using brush selection";
|
||||
ot->idname = "GPENCIL_OT_select_circle";
|
||||
|
||||
/* callbacks */
|
||||
ot->invoke = WM_gesture_circle_invoke;
|
||||
ot->modal = WM_gesture_circle_modal;
|
||||
ot->exec = gpencil_circle_select_exec;
|
||||
ot->poll = gpencil_select_poll;
|
||||
ot->cancel = WM_gesture_circle_cancel;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
|
||||
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
|
||||
RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
|
||||
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Box Selection */
|
||||
|
||||
static int gpencil_border_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
View2D *v2d = &ar->v2d;
|
||||
|
||||
const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
|
||||
const bool select = (gesture_mode == GESTURE_MODAL_SELECT);
|
||||
const bool extend = RNA_boolean_get(op->ptr, "extend");
|
||||
|
||||
GP_SpaceConversion gsc = {0};
|
||||
rcti rect = {0};
|
||||
|
||||
bool changed = false;
|
||||
|
||||
|
||||
/* sanity checks */
|
||||
if (sa == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No active area");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* init space conversion stuff */
|
||||
gp_point_conversion_init(C, &gsc);
|
||||
|
||||
|
||||
/* deselect all strokes first? */
|
||||
if (select && !extend) {
|
||||
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
CTX_DATA_END;
|
||||
}
|
||||
|
||||
/* get settings from operator */
|
||||
WM_operator_properties_border_to_rcti(op, &rect);
|
||||
|
||||
/* select/deselect points */
|
||||
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
int x0, y0;
|
||||
|
||||
/* convert point coords to screenspace */
|
||||
gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
|
||||
|
||||
/* test if in selection rect */
|
||||
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&rect, x0, y0)) {
|
||||
if (select) {
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
}
|
||||
else {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that stroke selection is in sync with its points */
|
||||
gpencil_stroke_sync_selection(gps);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* updates */
|
||||
if (changed) {
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GPENCIL_OT_select_border(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Border Select";
|
||||
ot->description = "Select Grease Pencil strokes within a rectangular region";
|
||||
ot->idname = "GPENCIL_OT_select_border";
|
||||
|
||||
/* callbacks */
|
||||
ot->invoke = WM_border_select_invoke;
|
||||
ot->exec = gpencil_border_select_exec;
|
||||
ot->modal = WM_border_select_modal;
|
||||
ot->cancel = WM_border_select_cancel;
|
||||
|
||||
ot->poll = gpencil_select_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* rna */
|
||||
WM_operator_properties_gesture_border(ot, true);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
/* Mouse Click to Select */
|
||||
|
||||
static int gpencil_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
View2D *v2d = &ar->v2d;
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
|
||||
const float radius = 0.75f * U.widget_unit;
|
||||
const int radius_squared = (int)(radius * radius);
|
||||
|
||||
bool extend = RNA_boolean_get(op->ptr, "extend");
|
||||
bool deselect = RNA_boolean_get(op->ptr, "deselect");
|
||||
bool toggle = RNA_boolean_get(op->ptr, "toggle");
|
||||
bool whole = RNA_boolean_get(op->ptr, "entire_strokes");
|
||||
|
||||
int location[2] = {0};
|
||||
int mx, my;
|
||||
|
||||
GP_SpaceConversion gsc = {0};
|
||||
|
||||
bGPDstroke *hit_stroke = NULL;
|
||||
bGPDspoint *hit_point = NULL;
|
||||
|
||||
/* sanity checks */
|
||||
if (sa == NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "No active area");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* init space conversion stuff */
|
||||
gp_point_conversion_init(C, &gsc);
|
||||
|
||||
/* get mouse location */
|
||||
RNA_int_get_array(op->ptr, "location", location);
|
||||
|
||||
mx = location[0];
|
||||
my = location[1];
|
||||
|
||||
/* First Pass: Find stroke point which gets hit */
|
||||
/* XXX: maybe we should go from the top of the stack down instead... */
|
||||
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
|
||||
{
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
int hit_index = -1;
|
||||
|
||||
/* firstly, check for hit-point */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
int x0, y0;
|
||||
|
||||
gp_point_to_xy(&gsc, gps, pt, &x0, &y0);
|
||||
|
||||
/* do boundbox check first */
|
||||
if (!ELEM(V2D_IS_CLIPPED, x0, x0)) {
|
||||
/* only check if point is inside */
|
||||
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius_squared) {
|
||||
hit_stroke = gps;
|
||||
hit_point = pt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* skip to next stroke if nothing found */
|
||||
if (hit_index == -1)
|
||||
continue;
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
/* Abort if nothing hit... */
|
||||
if (ELEM(NULL, hit_stroke, hit_point)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* adjust selection behaviour - for toggle option */
|
||||
if (toggle) {
|
||||
deselect = (hit_point->flag & GP_SPOINT_SELECT) != 0;
|
||||
}
|
||||
|
||||
/* If not extending selection, deselect everything else */
|
||||
if (extend == false) {
|
||||
CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
|
||||
{
|
||||
/* deselect stroke and its points if selected */
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
/* deselect points */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
/* deselect stroke itself too */
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
}
|
||||
|
||||
/* Perform selection operations... */
|
||||
if (whole) {
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
/* entire stroke's points */
|
||||
for (i = 0, pt = hit_stroke->points; i < hit_stroke->totpoints; i++, pt++) {
|
||||
if (deselect == false)
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
else
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
|
||||
/* stroke too... */
|
||||
if (deselect == false)
|
||||
hit_stroke->flag |= GP_STROKE_SELECT;
|
||||
else
|
||||
hit_stroke->flag &= ~GP_STROKE_SELECT;
|
||||
}
|
||||
else {
|
||||
/* just the point (and the stroke) */
|
||||
if (deselect == false) {
|
||||
/* we're adding selection, so selection must be true */
|
||||
hit_point->flag |= GP_SPOINT_SELECT;
|
||||
hit_stroke->flag |= GP_STROKE_SELECT;
|
||||
}
|
||||
else {
|
||||
/* deselect point */
|
||||
hit_point->flag &= ~GP_SPOINT_SELECT;
|
||||
|
||||
/* ensure that stroke is selected correctly */
|
||||
gpencil_stroke_sync_selection(hit_stroke);
|
||||
}
|
||||
}
|
||||
|
||||
/* updates */
|
||||
if (hit_point != NULL) {
|
||||
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int gpencil_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
RNA_int_set_array(op->ptr, "location", event->mval);
|
||||
return gpencil_select_exec(C, op);
|
||||
}
|
||||
|
||||
void GPENCIL_OT_select(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Select";
|
||||
ot->description = "Select Grease Pencil strokes and/or stroke points";
|
||||
ot->idname = "GPENCIL_OT_select";
|
||||
|
||||
/* callbacks */
|
||||
ot->invoke = gpencil_select_invoke;
|
||||
ot->exec = gpencil_select_exec;
|
||||
ot->poll = gpencil_select_poll;
|
||||
|
||||
/* flag */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
WM_operator_properties_mouse_select(ot);
|
||||
|
||||
RNA_def_boolean(ot->srna, "entire_strokes", false, "Entire Strokes", "Select entire strokes instead of just the nearest stroke vertex");
|
||||
|
||||
prop = RNA_def_int_vector(ot->srna, "location", 2, NULL, INT_MIN, INT_MAX, "Location", "Mouse location", INT_MIN, INT_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
|
||||
|
166
source/blender/editors/gpencil/gpencil_utils.c
Normal file
166
source/blender/editors/gpencil/gpencil_utils.c
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* ***** 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) 2014, Blender Foundation
|
||||
*
|
||||
* Contributor(s): Joshua Leung
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file blender/editors/gpencil/gpencil_utils.c
|
||||
* \ingroup edgpencil
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_space_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_screen.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "ED_gpencil.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
#include "gpencil_intern.h"
|
||||
|
||||
/* ******************************************************** */
|
||||
|
||||
/* Check if part of stroke occurs within last segment drawn by eraser */
|
||||
bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
|
||||
int rad, int x0, int y0, int x1, int y1)
|
||||
{
|
||||
/* simple within-radius check for now */
|
||||
const float mval_fl[2] = {mval[0], mval[1]};
|
||||
const float screen_co_a[2] = {x0, y0};
|
||||
const float screen_co_b[2] = {x1, y1};
|
||||
|
||||
if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* not inside */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ******************************************************** */
|
||||
|
||||
/* Init handling for space-conversion function (from passed-in parameters) */
|
||||
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
|
||||
{
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
ARegion *ar = CTX_wm_region(C);
|
||||
|
||||
/* zero out the storage (just in case) */
|
||||
memset(r_gsc, 0, sizeof(GP_SpaceConversion));
|
||||
unit_m4(r_gsc->mat);
|
||||
|
||||
/* store settings */
|
||||
r_gsc->sa = sa;
|
||||
r_gsc->ar = ar;
|
||||
r_gsc->v2d = &ar->v2d;
|
||||
|
||||
/* init region-specific stuff */
|
||||
if (sa->spacetype == SPACE_VIEW3D) {
|
||||
wmWindow *win = CTX_wm_window(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
View3D *v3d = (View3D *)CTX_wm_space_data(C);
|
||||
RegionView3D *rv3d = ar->regiondata;
|
||||
|
||||
/* init 3d depth buffers */
|
||||
view3d_operator_needs_opengl(C);
|
||||
|
||||
view3d_region_operator_needs_opengl(win, ar);
|
||||
ED_view3d_autodist_init(scene, ar, v3d, 0);
|
||||
|
||||
/* for camera view set the subrect */
|
||||
if (rv3d->persp == RV3D_CAMOB) {
|
||||
ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &r_gsc->subrect_data, true); /* no shift */
|
||||
r_gsc->subrect = &r_gsc->subrect_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert Grease Pencil points to screen-space values */
|
||||
void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
|
||||
int *r_x, int *r_y)
|
||||
{
|
||||
ARegion *ar = gsc->ar;
|
||||
View2D *v2d = gsc->v2d;
|
||||
rctf *subrect = gsc->subrect;
|
||||
int xyval[2];
|
||||
|
||||
if (gps->flag & GP_STROKE_3DSPACE) {
|
||||
if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
|
||||
*r_x = xyval[0];
|
||||
*r_y = xyval[1];
|
||||
}
|
||||
else {
|
||||
*r_x = V2D_IS_CLIPPED;
|
||||
*r_y = V2D_IS_CLIPPED;
|
||||
}
|
||||
}
|
||||
else if (gps->flag & GP_STROKE_2DSPACE) {
|
||||
float vec[3] = {pt->x, pt->y, 0.0f};
|
||||
mul_m4_v3(gsc->mat, vec);
|
||||
UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
|
||||
}
|
||||
else {
|
||||
if (subrect == NULL) { /* normal 3D view */
|
||||
*r_x = (int)(pt->x / 100 * ar->winx);
|
||||
*r_y = (int)(pt->y / 100 * ar->winy);
|
||||
}
|
||||
else { /* camera view, use subrect */
|
||||
*r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
|
||||
*r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ******************************************************** */
|
@@ -30,6 +30,7 @@
|
||||
#ifndef __ED_GPENCIL_H__
|
||||
#define __ED_GPENCIL_H__
|
||||
|
||||
struct ID;
|
||||
struct ListBase;
|
||||
struct bContext;
|
||||
struct bScreen;
|
||||
@@ -38,6 +39,7 @@ struct ARegion;
|
||||
struct View3D;
|
||||
struct SpaceNode;
|
||||
struct SpaceSeq;
|
||||
struct Object;
|
||||
struct bGPdata;
|
||||
struct bGPDlayer;
|
||||
struct bGPDframe;
|
||||
@@ -65,14 +67,26 @@ typedef struct tGPspoint {
|
||||
|
||||
/* ----------- Grease Pencil Tools/Context ------------- */
|
||||
|
||||
/* Context-dependent */
|
||||
struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr);
|
||||
struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
|
||||
|
||||
/* Context independent (i.e. each required part is passed in instead) */
|
||||
struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ID *screen_id, struct Scene *scene,
|
||||
struct ScrArea *sa, struct Object *ob,
|
||||
struct PointerRNA *ptr);
|
||||
struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct Scene *scene,
|
||||
struct ScrArea *sa, struct Object *ob);
|
||||
|
||||
/* 3D View */
|
||||
struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d);
|
||||
|
||||
/* ----------- Grease Pencil Operators ----------------- */
|
||||
|
||||
void ED_keymap_gpencil(struct wmKeyConfig *keyconf);
|
||||
|
||||
void ED_operatortypes_gpencil(void);
|
||||
void ED_operatormacros_gpencil(void);
|
||||
|
||||
/* ------------ Grease-Pencil Drawing API ------------------ */
|
||||
/* drawgpencil.c */
|
||||
@@ -99,6 +113,8 @@ void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode
|
||||
bool ED_gplayer_frames_delete(struct bGPDlayer *gpl);
|
||||
void ED_gplayer_frames_duplicate(struct bGPDlayer *gpl);
|
||||
|
||||
void ED_gplayer_frames_keytype_set(struct bGPDlayer *gpl, short type);
|
||||
|
||||
void ED_gplayer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode);
|
||||
|
||||
#if 0
|
||||
|
@@ -120,8 +120,9 @@ void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Obje
|
||||
void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos);
|
||||
/* DopeSheet Summary */
|
||||
void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos);
|
||||
/* Grease Pencil Layer */
|
||||
// XXX not restored
|
||||
/* Grease Pencil datablock summary */
|
||||
void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos);
|
||||
/* Grease Pencil Layer */
|
||||
void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos);
|
||||
/* Mask Layer */
|
||||
void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos);
|
||||
@@ -139,11 +140,11 @@ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct DLRBT_Tree
|
||||
void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
/* DopeSheet Summary */
|
||||
void summary_to_keylist(struct bAnimContext *ac, struct DLRBT_Tree *keys, struct DLRBT_Tree *blocks);
|
||||
/* Grease Pencil datablock summary */
|
||||
void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct DLRBT_Tree *keys);
|
||||
/* Grease Pencil Layer */
|
||||
// XXX not restored
|
||||
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct DLRBT_Tree *keys);
|
||||
/* Mask */
|
||||
// XXX not restored
|
||||
void mask_to_keylist(struct bDopeSheet *UNUSED(ads), struct MaskLayer *masklay, struct DLRBT_Tree *keys);
|
||||
|
||||
/* ActKeyColumn API ---------------- */
|
||||
|
@@ -99,6 +99,7 @@ enum TfmMode {
|
||||
#define CTX_MOVIECLIP (1 << 6)
|
||||
#define CTX_MASK (1 << 7)
|
||||
#define CTX_PAINT_CURVE (1 << 8)
|
||||
#define CTX_GPENCIL_STROKES (1 << 9)
|
||||
|
||||
/* Standalone call to get the transformation center corresponding to the current situation
|
||||
* returns 1 if successful, 0 otherwise (usually means there's no selection)
|
||||
@@ -146,6 +147,7 @@ int BIF_countTransformOrientation(const struct bContext *C);
|
||||
#define P_CORRECT_UV (1 << 8)
|
||||
#define P_NO_DEFAULTS (1 << 10)
|
||||
#define P_NO_TEXSPACE (1 << 11)
|
||||
#define P_GPENCIL_EDIT (1 << 12)
|
||||
|
||||
void Transform_Properties(struct wmOperatorType *ot, int flags);
|
||||
|
||||
|
@@ -1352,8 +1352,18 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
|
||||
}
|
||||
if (flag & ED_KEYMAP_GPENCIL) {
|
||||
/* grease pencil */
|
||||
wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap);
|
||||
/* NOTE: This is now 2 keymaps - One for basic functionality,
|
||||
* and one that only applies when "Edit Mode" is enabled
|
||||
* for strokes.
|
||||
*
|
||||
* For now, it's easier to just include both,
|
||||
* since you hardly want one without the other.
|
||||
*/
|
||||
wmKeyMap *keymap_general = WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0);
|
||||
wmKeyMap *keymap_edit = WM_keymap_find(wm->defaultconf, "Grease Pencil Stroke Edit Mode", 0, 0);
|
||||
|
||||
WM_event_add_keymap_handler(handlers, keymap_general);
|
||||
WM_event_add_keymap_handler(handlers, keymap_edit);
|
||||
}
|
||||
if (flag & ED_KEYMAP_HEADER) {
|
||||
/* standard keymap for headers regions */
|
||||
|
@@ -26,12 +26,13 @@
|
||||
* \ingroup edscr
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
@@ -45,11 +46,13 @@
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_action.h"
|
||||
#include "BKE_armature.h"
|
||||
#include "BKE_gpencil.h"
|
||||
#include "BKE_sequencer.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_gpencil.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "UI_interface.h"
|
||||
@@ -66,12 +69,16 @@ const char *screen_context_dir[] = {
|
||||
"sculpt_object", "vertex_paint_object", "weight_paint_object",
|
||||
"image_paint_object", "particle_edit_object",
|
||||
"sequences", "selected_sequences", "selected_editable_sequences", /* sequencer */
|
||||
"gpencil_data", "gpencil_data_owner", /* grease pencil data */
|
||||
"visible_gpencil_layers", "editable_gpencil_layers", "editable_gpencil_strokes",
|
||||
"active_gpencil_layer", "active_gpencil_frame",
|
||||
"active_operator",
|
||||
NULL};
|
||||
|
||||
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
|
||||
{
|
||||
bScreen *sc = CTX_wm_screen(C);
|
||||
ScrArea *sa = CTX_wm_area(C);
|
||||
Scene *scene = sc->scene;
|
||||
Base *base;
|
||||
unsigned int lay = scene->lay;
|
||||
@@ -392,6 +399,112 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "gpencil_data")) {
|
||||
/* FIXME: for some reason, CTX_data_active_object(C) returns NULL when called from these situations
|
||||
* (as outlined above - see Campbell's #ifdefs). That causes the get active function to fail when
|
||||
* called from context. For that reason, we end up using an alternative where we pass everything in!
|
||||
*/
|
||||
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
|
||||
|
||||
if (gpd) {
|
||||
CTX_data_id_pointer_set(result, &gpd->id);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "gpencil_data_owner")) {
|
||||
/* pointer to which data/datablock owns the reference to the Grease Pencil data being used (as gpencil_data)
|
||||
* XXX: see comment for gpencil_data case...
|
||||
*/
|
||||
bGPdata **gpd_ptr = NULL;
|
||||
PointerRNA ptr;
|
||||
|
||||
/* get pointer to Grease Pencil Data */
|
||||
gpd_ptr = ED_gpencil_data_get_pointers_direct((ID *)sc, scene, sa, obact, &ptr);
|
||||
|
||||
if (gpd_ptr) {
|
||||
CTX_data_pointer_set(result, ptr.id.data, ptr.type, ptr.data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "active_gpencil_layer")) {
|
||||
/* XXX: see comment for gpencil_data case... */
|
||||
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
|
||||
|
||||
if (gpd) {
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
if (gpl) {
|
||||
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "active_gpencil_frame")) {
|
||||
/* XXX: see comment for gpencil_data case... */
|
||||
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
|
||||
|
||||
if (gpd) {
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
if (gpl) {
|
||||
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "visible_gpencil_layers")) {
|
||||
/* XXX: see comment for gpencil_data case... */
|
||||
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
|
||||
|
||||
if (gpd) {
|
||||
bGPDlayer *gpl;
|
||||
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
if ((gpl->flag & GP_LAYER_HIDE) == 0) {
|
||||
CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
|
||||
}
|
||||
}
|
||||
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "editable_gpencil_layers")) {
|
||||
/* XXX: see comment for gpencil_data case... */
|
||||
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
|
||||
|
||||
if (gpd) {
|
||||
bGPDlayer *gpl;
|
||||
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0) {
|
||||
CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
|
||||
}
|
||||
}
|
||||
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "editable_gpencil_strokes")) {
|
||||
/* XXX: see comment for gpencil_data case... */
|
||||
bGPdata *gpd = ED_gpencil_data_get_active_direct((ID *)sc, scene, sa, obact);
|
||||
|
||||
if (gpd) {
|
||||
bGPDlayer *gpl;
|
||||
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 && (gpl->actframe)) {
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
bGPDstroke *gps;
|
||||
|
||||
for (gps = gpf->strokes.first; gps; gps = gps->next) {
|
||||
CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (CTX_data_equals(member, "active_operator")) {
|
||||
wmOperator *op = NULL;
|
||||
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include "DNA_lattice_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_meta_types.h"
|
||||
#include "DNA_mask_types.h"
|
||||
@@ -2150,6 +2151,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
bGPdata *gpd = CTX_data_gpencil_data(C);
|
||||
bDopeSheet ads = {NULL};
|
||||
DLRBT_Tree keys;
|
||||
ActKeyColumn *ak;
|
||||
@@ -2177,7 +2179,9 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
|
||||
|
||||
if (ob)
|
||||
ob_to_keylist(&ads, ob, &keys, NULL);
|
||||
|
||||
|
||||
gpencil_to_keylist(&ads, gpd, &keys);
|
||||
|
||||
{
|
||||
Mask *mask = CTX_data_edit_mask(C);
|
||||
if (mask) {
|
||||
|
@@ -965,8 +965,11 @@ static int actkeys_clean_exec(bContext *C, wmOperator *op)
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
||||
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not implemented");
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* get cleaning threshold */
|
||||
thresh = RNA_float_get(op->ptr, "threshold");
|
||||
@@ -1025,15 +1028,18 @@ static void sample_action_keys(bAnimContext *ac)
|
||||
|
||||
/* ------------------- */
|
||||
|
||||
static int actkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
static int actkeys_sample_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
||||
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not implemented");
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* sample keyframes */
|
||||
sample_action_keys(&ac);
|
||||
@@ -1138,8 +1144,11 @@ static int actkeys_expo_exec(bContext *C, wmOperator *op)
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
||||
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not implemented");
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* get handle setting mode */
|
||||
mode = RNA_enum_get(op->ptr, "type");
|
||||
@@ -1209,8 +1218,11 @@ static int actkeys_ipo_exec(bContext *C, wmOperator *op)
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
||||
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not implemented");
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* get handle setting mode */
|
||||
mode = RNA_enum_get(op->ptr, "type");
|
||||
@@ -1288,8 +1300,11 @@ static int actkeys_handletype_exec(bContext *C, wmOperator *op)
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
||||
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not implemented");
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* get handle setting mode */
|
||||
mode = RNA_enum_get(op->ptr, "type");
|
||||
@@ -1324,7 +1339,7 @@ void ACTION_OT_handle_type(wmOperatorType *ot)
|
||||
|
||||
/* ******************** Set Keyframe-Type Operator *********************** */
|
||||
|
||||
/* this function is responsible for setting interpolation mode for keyframes */
|
||||
/* this function is responsible for setting keyframe type for keyframes */
|
||||
static void setkeytype_action_keys(bAnimContext *ac, short mode)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
@@ -1349,6 +1364,29 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode)
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
/* this function is responsible for setting the keyframe type for Grease Pencil frames */
|
||||
static void setkeytype_gpencil_keys(bAnimContext *ac, short mode)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
bAnimListElem *ale;
|
||||
int filter;
|
||||
|
||||
/* filter data */
|
||||
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
|
||||
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
||||
|
||||
/* loop through each layer */
|
||||
for (ale = anim_data.first; ale; ale = ale->next) {
|
||||
if (ale->type == ANIMTYPE_GPLAYER) {
|
||||
ED_gplayer_frames_keytype_set(ale->data, mode);
|
||||
ale->update |= ANIM_UPDATE_DEPS;
|
||||
}
|
||||
}
|
||||
|
||||
ANIM_animdata_update(ac, &anim_data);
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
/* ------------------- */
|
||||
|
||||
static int actkeys_keytype_exec(bContext *C, wmOperator *op)
|
||||
@@ -1359,14 +1397,22 @@ static int actkeys_keytype_exec(bContext *C, wmOperator *op)
|
||||
/* get editor data */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
||||
|
||||
if (ac.datatype == ANIMCONT_MASK) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Not implemented for Masks");
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* get handle setting mode */
|
||||
mode = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
/* set handle type */
|
||||
setkeytype_action_keys(&ac, mode);
|
||||
if (ac.datatype == ANIMCONT_GPENCIL) {
|
||||
setkeytype_gpencil_keys(&ac, mode);
|
||||
}
|
||||
else {
|
||||
setkeytype_action_keys(&ac, mode);
|
||||
}
|
||||
|
||||
/* set notifier that keyframe properties have changed */
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
|
||||
|
@@ -155,6 +155,7 @@ void ED_spacemacros_init(void)
|
||||
ED_operatormacros_mask();
|
||||
ED_operatormacros_sequencer();
|
||||
ED_operatormacros_paint();
|
||||
ED_operatormacros_gpencil();
|
||||
|
||||
/* register dropboxes (can use macros) */
|
||||
spacetypes = BKE_spacetypes_list();
|
||||
|
@@ -69,15 +69,18 @@
|
||||
|
||||
/* Panels */
|
||||
|
||||
#if 0
|
||||
static int clip_grease_pencil_panel_poll(const bContext *C, PanelType *UNUSED(pt))
|
||||
{
|
||||
SpaceClip *sc = CTX_wm_space_clip(C);
|
||||
|
||||
return sc->view == SC_VIEW_CLIP;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ED_clip_buttons_register(ARegionType *art)
|
||||
{
|
||||
#if 0
|
||||
PanelType *pt;
|
||||
|
||||
pt = MEM_callocN(sizeof(PanelType), "spacetype clip panel gpencil");
|
||||
@@ -89,6 +92,7 @@ void ED_clip_buttons_register(ARegionType *art)
|
||||
pt->flag |= PNL_DEFAULT_CLOSED;
|
||||
pt->poll = clip_grease_pencil_panel_poll;
|
||||
BLI_addtail(&art->paneltypes, pt);
|
||||
#endif
|
||||
}
|
||||
|
||||
/********************* MovieClip Template ************************/
|
||||
|
@@ -979,6 +979,7 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser
|
||||
|
||||
void image_buttons_register(ARegionType *art)
|
||||
{
|
||||
#if 0
|
||||
PanelType *pt;
|
||||
const char *category = "Grease Pencil";
|
||||
|
||||
@@ -990,6 +991,7 @@ void image_buttons_register(ARegionType *art)
|
||||
pt->draw = ED_gpencil_panel_standard;
|
||||
BLI_strncpy(pt->category, category, BLI_strlen_utf8(category));
|
||||
BLI_addtail(&art->paneltypes, pt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int image_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
@@ -57,6 +57,7 @@
|
||||
|
||||
/* ******************* node space & buttons ************** */
|
||||
|
||||
#if 0
|
||||
/* poll for active nodetree */
|
||||
static int active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt))
|
||||
{
|
||||
@@ -64,6 +65,7 @@ static int active_nodetree_poll(const bContext *C, PanelType *UNUSED(pt))
|
||||
|
||||
return (snode && snode->nodetree);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
|
||||
{
|
||||
@@ -198,6 +200,7 @@ void node_buttons_register(ARegionType *art)
|
||||
pt->poll = node_tree_interface_poll;
|
||||
BLI_addtail(&art->paneltypes, pt);
|
||||
|
||||
#if 0
|
||||
pt = MEM_callocN(sizeof(PanelType), "spacetype node panel gpencil");
|
||||
strcpy(pt->idname, "NODE_PT_gpencil");
|
||||
strcpy(pt->label, N_("Grease Pencil"));
|
||||
@@ -206,6 +209,7 @@ void node_buttons_register(ARegionType *art)
|
||||
pt->draw = ED_gpencil_panel_standard;
|
||||
pt->poll = active_nodetree_poll;
|
||||
BLI_addtail(&art->paneltypes, pt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int node_properties_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
@@ -515,6 +515,11 @@ static void node_area_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
|
||||
ED_area_tag_refresh(sa);
|
||||
}
|
||||
break;
|
||||
case NC_GPENCIL:
|
||||
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
|
||||
ED_area_tag_refresh(sa);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -52,6 +52,7 @@
|
||||
|
||||
/* **************************** buttons ********************************* */
|
||||
|
||||
#if 0
|
||||
static int sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNUSED(pt))
|
||||
{
|
||||
SpaceSeq *sseq = CTX_wm_space_seq(C);
|
||||
@@ -59,9 +60,11 @@ static int sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNUS
|
||||
/* don't show the gpencil if we are not showing the image */
|
||||
return ED_space_sequencer_check_show_imbuf(sseq);
|
||||
}
|
||||
#endif
|
||||
|
||||
void sequencer_buttons_register(ARegionType *art)
|
||||
{
|
||||
#if 0
|
||||
PanelType *pt;
|
||||
|
||||
pt = MEM_callocN(sizeof(PanelType), "spacetype sequencer panel gpencil");
|
||||
@@ -72,6 +75,7 @@ void sequencer_buttons_register(ARegionType *art)
|
||||
pt->draw = ED_gpencil_panel_standard;
|
||||
pt->poll = sequencer_grease_pencil_panel_poll;
|
||||
BLI_addtail(&art->paneltypes, pt);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* **************** operator to open/close properties view ************* */
|
||||
|
@@ -585,7 +585,7 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
|
||||
/* context changes */
|
||||
switch (wmn->category) {
|
||||
case NC_GPENCIL:
|
||||
if (wmn->action == NA_EDITED) {
|
||||
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
break;
|
||||
@@ -641,7 +641,7 @@ static void sequencer_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
|
||||
/* context changes */
|
||||
switch (wmn->category) {
|
||||
case NC_GPENCIL:
|
||||
if (wmn->data == ND_DATA) {
|
||||
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
break;
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "DNA_gpencil_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
@@ -310,6 +311,9 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
|
||||
case ID_OB:
|
||||
ob_to_keylist(&ads, (Object *)id, &keys, NULL);
|
||||
break;
|
||||
case ID_GD:
|
||||
gpencil_to_keylist(&ads, (bGPdata *)id, &keys);
|
||||
break;
|
||||
}
|
||||
|
||||
/* build linked-list for searching */
|
||||
@@ -339,9 +343,16 @@ static void time_draw_keyframes(const bContext *C, ARegion *ar)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
bGPdata *gpd = CTX_data_gpencil_data(C);
|
||||
View2D *v2d = &ar->v2d;
|
||||
bool onlysel = ((scene->flag & SCE_KEYS_NO_SELONLY) == 0);
|
||||
|
||||
/* draw grease pencil keyframes (if available) */
|
||||
if (gpd) {
|
||||
glColor3ub(0xB5, 0xE6, 0x1D);
|
||||
time_draw_idblock_keyframes(v2d, (ID *)gpd, onlysel);
|
||||
}
|
||||
|
||||
/* draw scene keyframes first
|
||||
* - don't try to do this when only drawing active/selected data keyframes,
|
||||
* since this can become quite slow
|
||||
|
@@ -950,8 +950,9 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
|
||||
|
||||
break;
|
||||
case NC_GPENCIL:
|
||||
if (wmn->action == NA_EDITED)
|
||||
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
|
||||
ED_region_tag_redraw(ar);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -1185,6 +1185,7 @@ void view3d_buttons_register(ARegionType *art)
|
||||
pt->poll = view3d_panel_transform_poll;
|
||||
BLI_addtail(&art->paneltypes, pt);
|
||||
|
||||
#if 0
|
||||
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel gpencil");
|
||||
strcpy(pt->idname, "VIEW3D_PT_gpencil");
|
||||
strcpy(pt->label, N_("Grease Pencil")); /* XXX C panels are not available through RNA (bpy.types)! */
|
||||
@@ -1192,6 +1193,7 @@ void view3d_buttons_register(ARegionType *art)
|
||||
pt->draw_header = ED_gpencil_panel_standard_header;
|
||||
pt->draw = ED_gpencil_panel_standard;
|
||||
BLI_addtail(&art->paneltypes, pt);
|
||||
#endif
|
||||
|
||||
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup");
|
||||
strcpy(pt->idname, "VIEW3D_PT_vgroup");
|
||||
|
@@ -2032,6 +2032,12 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
||||
options |= CTX_TEXTURE;
|
||||
}
|
||||
}
|
||||
|
||||
if ((prop = RNA_struct_find_property(op->ptr, "gpencil_strokes")) && RNA_property_is_set(op->ptr, prop)) {
|
||||
if (RNA_property_boolean_get(op->ptr, prop)) {
|
||||
options |= CTX_GPENCIL_STROKES;
|
||||
}
|
||||
}
|
||||
|
||||
t->options = options;
|
||||
|
||||
|
@@ -107,6 +107,7 @@
|
||||
#include "ED_uvedit.h"
|
||||
#include "ED_clip.h"
|
||||
#include "ED_mask.h"
|
||||
#include "ED_gpencil.h"
|
||||
|
||||
#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
|
||||
#include "WM_types.h"
|
||||
@@ -5878,6 +5879,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
|
||||
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
|
||||
|
||||
}
|
||||
else if (t->options & CTX_GPENCIL_STROKES) {
|
||||
/* pass */
|
||||
}
|
||||
else if (t->options & CTX_PAINT_CURVE) {
|
||||
/* pass */
|
||||
}
|
||||
@@ -7227,6 +7231,179 @@ void flushTransPaintCurve(TransInfo *t)
|
||||
}
|
||||
|
||||
|
||||
static void createTransGPencil(bContext *C, TransInfo *t)
|
||||
{
|
||||
bGPdata *gpd = ED_gpencil_data_get_active(C);
|
||||
bGPDlayer *gpl;
|
||||
TransData *td = NULL;
|
||||
float mtx[3][3], smtx[3][3];
|
||||
|
||||
const int propedit = (t->flag & T_PROP_EDIT);
|
||||
const int propedit_connected = (t->flag & T_PROP_CONNECTED);
|
||||
|
||||
|
||||
/* == Grease Pencil Strokes to Transform Data ==
|
||||
* Grease Pencil stroke points can be a mixture of 2D (screen-space),
|
||||
* or 3D coordinates. However, they're always saved as 3D points.
|
||||
* For now, we just do these without creating TransData2D for the 2D
|
||||
* strokes. This may cause issues in future though.
|
||||
*/
|
||||
t->total = 0;
|
||||
|
||||
if (gpd == NULL)
|
||||
return;
|
||||
|
||||
/* First Pass: Count the number of datapoints required for the strokes,
|
||||
* (and additional info about the configuration - e.g. 2D/3D?)
|
||||
*/
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
/* only editable and visible layers are considered */
|
||||
if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
|
||||
(gpl->actframe != NULL))
|
||||
{
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
bGPDstroke *gps;
|
||||
|
||||
for (gps = gpf->strokes.first; gps; gps = gps->next) {
|
||||
if (propedit) {
|
||||
/* Proportional Editing... */
|
||||
if (propedit_connected) {
|
||||
/* connected only - so only if selected */
|
||||
if (gps->flag & GP_STROKE_SELECT)
|
||||
t->total += gps->totpoints;
|
||||
}
|
||||
else {
|
||||
/* everything goes - connection status doesn't matter */
|
||||
t->total += gps->totpoints;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* only selected stroke points are considered */
|
||||
if (gps->flag & GP_STROKE_SELECT) {
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
// TODO: 2D vs 3D?
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
if (pt->flag & GP_SPOINT_SELECT)
|
||||
t->total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Stop trying if nothing selected */
|
||||
if (t->total == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate memory for data */
|
||||
t->data = MEM_callocN(t->total * sizeof(TransData), "TransData(GPencil)");
|
||||
td = t->data;
|
||||
|
||||
unit_m3(smtx);
|
||||
unit_m3(mtx);
|
||||
|
||||
/* Second Pass: Build transdata array */
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
/* only editable and visible layers are considered */
|
||||
if ((gpl->flag & (GP_LAYER_HIDE | GP_LAYER_LOCKED)) == 0 &&
|
||||
(gpl->actframe != NULL))
|
||||
{
|
||||
bGPDframe *gpf = gpl->actframe;
|
||||
bGPDstroke *gps;
|
||||
|
||||
for (gps = gpf->strokes.first; gps; gps = gps->next) {
|
||||
TransData *head = td;
|
||||
TransData *tail = td;
|
||||
bool stroke_ok;
|
||||
|
||||
/* What we need to include depends on proportional editing settings... */
|
||||
if (propedit) {
|
||||
if (propedit_connected) {
|
||||
/* A) "Connected" - Only those in selected strokes */
|
||||
stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
|
||||
}
|
||||
else {
|
||||
/* B) All points, always */
|
||||
stroke_ok = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* C) Only selected points in selected strokes */
|
||||
stroke_ok = (gps->flag & GP_STROKE_SELECT) != 0;
|
||||
}
|
||||
|
||||
/* Do stroke... */
|
||||
if (stroke_ok && gps->totpoints) {
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
#if 0 /* XXX: this isn't needed anymore; cannot calculate center this way or propedit breaks */
|
||||
const float ninv = 1.0f / gps->totpoints;
|
||||
float center[3] = {0.0f};
|
||||
|
||||
/* compute midpoint of stroke */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
madd_v3_v3v3fl(center, center, &pt->x, ninv);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* add all necessary points... */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
bool point_ok;
|
||||
|
||||
/* include point? */
|
||||
if (propedit) {
|
||||
/* Always all points in strokes that get included */
|
||||
point_ok = true;
|
||||
}
|
||||
else {
|
||||
/* Only selected points in selected strokes */
|
||||
point_ok = (pt->flag & GP_SPOINT_SELECT) != 0;
|
||||
}
|
||||
|
||||
/* do point... */
|
||||
if (point_ok) {
|
||||
copy_v3_v3(td->iloc, &pt->x);
|
||||
copy_v3_v3(td->center, &pt->x); // XXX: what about t->around == local?
|
||||
|
||||
td->loc = &pt->x;
|
||||
|
||||
td->flag = 0;
|
||||
|
||||
if (pt->flag & GP_SPOINT_SELECT)
|
||||
td->flag |= TD_SELECTED;
|
||||
|
||||
/* configure 2D points so that they don't play up... */
|
||||
if (gps->flag & (GP_STROKE_2DSPACE | GP_STROKE_2DIMAGE)) {
|
||||
td->protectflag = OB_LOCK_LOCZ | OB_LOCK_ROTZ | OB_LOCK_SCALEZ;
|
||||
// XXX: matrices may need to be different?
|
||||
}
|
||||
|
||||
copy_m3_m3(td->smtx, smtx);
|
||||
copy_m3_m3(td->mtx, mtx);
|
||||
unit_m3(td->axismtx); // XXX?
|
||||
|
||||
td++;
|
||||
tail++;
|
||||
}
|
||||
}
|
||||
|
||||
/* March over these points, and calculate the proportional editing distances */
|
||||
if (propedit && (head != tail)) {
|
||||
/* XXX: for now, we are similar enough that this works... */
|
||||
calc_distanceCurveVerts(head, tail - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void createTransData(bContext *C, TransInfo *t)
|
||||
{
|
||||
Scene *scene = t->scene;
|
||||
@@ -7247,6 +7424,16 @@ void createTransData(bContext *C, TransInfo *t)
|
||||
sort_trans_data_dist(t);
|
||||
}
|
||||
}
|
||||
else if (t->options & CTX_GPENCIL_STROKES) {
|
||||
t->flag |= T_POINTS; // XXX...
|
||||
createTransGPencil(C, t);
|
||||
|
||||
if (t->data && (t->flag & T_PROP_EDIT)) {
|
||||
sort_trans_data(t); // makes selected become first in array
|
||||
set_prop_dist(t, 1);
|
||||
sort_trans_data_dist(t);
|
||||
}
|
||||
}
|
||||
else if (t->spacetype == SPACE_IMAGE) {
|
||||
t->flag |= T_POINTS | T_2D_EDIT;
|
||||
if (t->options & CTX_MASK) {
|
||||
|
@@ -975,6 +975,9 @@ void recalcData(TransInfo *t)
|
||||
else if (t->options & CTX_PAINT_CURVE) {
|
||||
flushTransPaintCurve(t);
|
||||
}
|
||||
else if (t->options & CTX_GPENCIL_STROKES) {
|
||||
/* pass? */
|
||||
}
|
||||
else if (t->spacetype == SPACE_IMAGE) {
|
||||
recalcData_image(t);
|
||||
}
|
||||
|
@@ -543,7 +543,11 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (flags & P_GPENCIL_EDIT) {
|
||||
RNA_def_boolean(ot->srna, "gpencil_strokes", 0, "Edit Grease Pencil", "Edit selected Grease Pencil strokes");
|
||||
}
|
||||
|
||||
if ((flags & P_OPTIONS) && !(flags & P_NO_TEXSPACE)) {
|
||||
RNA_def_boolean(ot->srna, "texture_space", 0, "Edit Texture Space", "Edit Object data texture space");
|
||||
prop = RNA_def_boolean(ot->srna, "remove_on_cancel", 0, "Remove on Cancel", "Remove elements on cancel");
|
||||
@@ -578,7 +582,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
|
||||
|
||||
RNA_def_float_vector_xyz(ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
||||
|
||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS);
|
||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
||||
@@ -598,7 +602,7 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
||||
|
||||
RNA_def_float_vector(ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX);
|
||||
|
||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS);
|
||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_OPTIONS | P_GPENCIL_EDIT);
|
||||
}
|
||||
|
||||
static int skin_resize_poll(bContext *C)
|
||||
@@ -652,7 +656,7 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
|
||||
prop = RNA_def_float_vector(ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
|
||||
RNA_def_property_subtype(prop, PROP_ANGLE);
|
||||
|
||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
|
||||
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
|
||||
@@ -675,7 +679,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
|
||||
prop = RNA_def_float(ot->srna, "value", 0.0f, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
|
||||
RNA_def_property_subtype(prop, PROP_ANGLE);
|
||||
|
||||
Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP);
|
||||
Transform_Properties(ot, P_AXIS | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP | P_GPENCIL_EDIT);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
|
||||
@@ -821,7 +825,7 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
|
||||
ot->cancel = transform_cancel;
|
||||
ot->poll = ED_operator_screenactive;
|
||||
|
||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL);
|
||||
Transform_Properties(ot, P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
|
||||
|
@@ -42,8 +42,15 @@ typedef struct bGPDspoint {
|
||||
float x, y, z; /* co-ordinates of point (usually 2d, but can be 3d as well) */
|
||||
float pressure; /* pressure of input device (from 0 to 1) at this point */
|
||||
float time; /* seconds since start of stroke */
|
||||
int flag; /* additional options (NOTE: can shrink this field down later if needed) */
|
||||
} bGPDspoint;
|
||||
|
||||
/* bGPDspoint->flag */
|
||||
typedef enum eGPDspoint_Flag {
|
||||
/* stroke point is selected (for editing) */
|
||||
GP_SPOINT_SELECT = (1 << 0)
|
||||
} eGPSPoint_Flag;
|
||||
|
||||
/* Grease-Pencil Annotations - 'Stroke'
|
||||
* -> A stroke represents a (simplified version) of the curve
|
||||
* drawn by the user in one 'mousedown'->'mouseup' operation
|
||||
@@ -61,15 +68,18 @@ typedef struct bGPDstroke {
|
||||
} bGPDstroke;
|
||||
|
||||
/* bGPDstroke->flag */
|
||||
typedef enum eGPDstroke_Flag {
|
||||
/* stroke is in 3d-space */
|
||||
#define GP_STROKE_3DSPACE (1<<0)
|
||||
GP_STROKE_3DSPACE = (1 << 0),
|
||||
/* stroke is in 2d-space */
|
||||
#define GP_STROKE_2DSPACE (1<<1)
|
||||
GP_STROKE_2DSPACE = (1 << 1),
|
||||
/* stroke is in 2d-space (but with special 'image' scaling) */
|
||||
#define GP_STROKE_2DIMAGE (1<<2)
|
||||
GP_STROKE_2DIMAGE = (1 << 2),
|
||||
/* stroke is selected */
|
||||
GP_STROKE_SELECT = (1 << 3),
|
||||
/* only for use with stroke-buffer (while drawing eraser) */
|
||||
#define GP_STROKE_ERASER (1<<15)
|
||||
|
||||
GP_STROKE_ERASER = (1 << 15)
|
||||
} eGPDstroke_Flag;
|
||||
|
||||
/* Grease-Pencil Annotations - 'Frame'
|
||||
* -> Acts as storage for the 'image' formed by strokes
|
||||
@@ -80,15 +90,18 @@ typedef struct bGPDframe {
|
||||
ListBase strokes; /* list of the simplified 'strokes' that make up the frame's data */
|
||||
|
||||
int framenum; /* frame number of this frame */
|
||||
int flag; /* temp settings */
|
||||
|
||||
short flag; /* temp settings */
|
||||
short key_type; /* keyframe type (eBezTriple_KeyframeType) */
|
||||
} bGPDframe;
|
||||
|
||||
/* bGPDframe->flag */
|
||||
/* bGPDframe->flag */
|
||||
typedef enum eGPDframe_Flag {
|
||||
/* frame is being painted on */
|
||||
#define GP_FRAME_PAINT (1<<0)
|
||||
GP_FRAME_PAINT = (1 << 0),
|
||||
/* for editing in Action Editor */
|
||||
#define GP_FRAME_SELECT (1<<1)
|
||||
|
||||
GP_FRAME_SELECT = (1 << 1)
|
||||
} eGPDframe_Flag;
|
||||
|
||||
/* Grease-Pencil Annotations - 'Layer' */
|
||||
typedef struct bGPDlayer {
|
||||
@@ -97,34 +110,47 @@ typedef struct bGPDlayer {
|
||||
ListBase frames; /* list of annotations to display for frames (bGPDframe list) */
|
||||
bGPDframe *actframe; /* active frame (should be the frame that is currently being displayed) */
|
||||
|
||||
int flag; /* settings for layer */
|
||||
short flag; /* settings for layer */
|
||||
short thickness; /* current thickness to apply to strokes */
|
||||
short gstep; /* max number of frames between active and ghost to show (0=only those on either side) */
|
||||
|
||||
short gstep; /* Ghosts Before: max number of ghost frames to show between active frame and the one before it (0 = only the ghost itself) */
|
||||
short gstep_next; /* Ghosts After: max number of ghost frames to show after active frame and the following it (0 = only the ghost itself) */
|
||||
|
||||
float gcolor_prev[3]; /* optional color for ghosts before the active frame */
|
||||
float gcolor_next[3]; /* optional color for ghosts after the active frame */
|
||||
|
||||
float color[4]; /* color that should be used to draw all the strokes in this layer */
|
||||
float fill[4]; /* color that should be used for drawing "fills" for strokes */
|
||||
|
||||
char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3")
|
||||
* this is used for the name of the layer too and kept unique. */
|
||||
} bGPDlayer;
|
||||
|
||||
/* bGPDlayer->flag */
|
||||
typedef enum eGPDlayer_Flag {
|
||||
/* don't display layer */
|
||||
#define GP_LAYER_HIDE (1<<0)
|
||||
GP_LAYER_HIDE = (1 << 0),
|
||||
/* protected from further editing */
|
||||
#define GP_LAYER_LOCKED (1<<1)
|
||||
GP_LAYER_LOCKED = (1 << 1),
|
||||
/* layer is 'active' layer being edited */
|
||||
#define GP_LAYER_ACTIVE (1<<2)
|
||||
GP_LAYER_ACTIVE = (1 << 2),
|
||||
/* draw points of stroke for debugging purposes */
|
||||
#define GP_LAYER_DRAWDEBUG (1<<3)
|
||||
/* do onionskinning */
|
||||
#define GP_LAYER_ONIONSKIN (1<<4)
|
||||
GP_LAYER_DRAWDEBUG = (1 << 3),
|
||||
/* do onion skinning */
|
||||
GP_LAYER_ONIONSKIN = (1 << 4),
|
||||
/* for editing in Action Editor */
|
||||
#define GP_LAYER_SELECT (1<<5)
|
||||
GP_LAYER_SELECT = (1 << 5),
|
||||
/* current frame for layer can't be changed */
|
||||
#define GP_LAYER_FRAMELOCK (1<<6)
|
||||
GP_LAYER_FRAMELOCK = (1 << 6),
|
||||
/* don't render xray (which is default) */
|
||||
#define GP_LAYER_NO_XRAY (1<<7)
|
||||
|
||||
GP_LAYER_NO_XRAY = (1 << 7),
|
||||
/* use custom color for ghosts before current frame */
|
||||
GP_LAYER_GHOST_PREVCOL = (1 << 8),
|
||||
/* use custom color for ghosts after current frame */
|
||||
GP_LAYER_GHOST_NEXTCOL = (1 << 9),
|
||||
/* "volumetric" strokes (i.e. GLU Quadric discs in 3D) */
|
||||
GP_LAYER_VOLUMETRIC = (1 << 10),
|
||||
} eGPDlayer_Flag;
|
||||
|
||||
/* Grease-Pencil Annotations - 'DataBlock' */
|
||||
typedef struct bGPdata {
|
||||
@@ -144,23 +170,33 @@ typedef struct bGPdata {
|
||||
} bGPdata;
|
||||
|
||||
/* bGPdata->flag */
|
||||
// XXX many of these flags should be deprecated for more general ideas in 2.5
|
||||
/* NOTE: A few flags have been deprecated since early 2.5,
|
||||
* since they have been made redundant by interaction
|
||||
* changes made during the porting process.
|
||||
*/
|
||||
typedef enum eGPdata_Flag {
|
||||
/* don't allow painting to occur at all */
|
||||
// XXX is deprecated - not well understood
|
||||
// #define GP_DATA_LMBPLOCK (1<<0)
|
||||
/* GP_DATA_LMBPLOCK = (1 << 0), */
|
||||
|
||||
/* show debugging info in viewport (i.e. status print) */
|
||||
#define GP_DATA_DISPINFO (1<<1)
|
||||
GP_DATA_DISPINFO = (1 << 1),
|
||||
/* in Action Editor, show as expanded channel */
|
||||
#define GP_DATA_EXPAND (1<<2)
|
||||
GP_DATA_EXPAND = (1 << 2),
|
||||
|
||||
/* is the block overriding all clicks? */
|
||||
// XXX is deprecated - nasty old concept
|
||||
// #define GP_DATA_EDITPAINT (1<<3)
|
||||
/* GP_DATA_EDITPAINT = (1 << 3), */
|
||||
|
||||
/* new strokes are added in viewport space */
|
||||
#define GP_DATA_VIEWALIGN (1<<4)
|
||||
/* Project into the screens Z values */
|
||||
#define GP_DATA_DEPTH_VIEW (1<<5)
|
||||
#define GP_DATA_DEPTH_STROKE (1<<6)
|
||||
GP_DATA_VIEWALIGN = (1 << 4),
|
||||
|
||||
/* Project into the screen's Z values */
|
||||
GP_DATA_DEPTH_VIEW = (1 << 5),
|
||||
GP_DATA_DEPTH_STROKE = (1 << 6),
|
||||
|
||||
#define GP_DATA_DEPTH_STROKE_ENDPOINTS (1<<7)
|
||||
GP_DATA_DEPTH_STROKE_ENDPOINTS = (1 << 7),
|
||||
|
||||
/* Stroke Editing Mode - Toggle to enable alternative keymap for easier editing of stroke points */
|
||||
GP_DATA_STROKE_EDITMODE = (1 << 8)
|
||||
} eGPdata_Flag;
|
||||
|
||||
#endif /* __DNA_GPENCIL_TYPES_H__ */
|
||||
|
@@ -44,6 +44,8 @@
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "BKE_gpencil.h"
|
||||
@@ -64,9 +66,30 @@ static int rna_GPencilLayer_active_frame_editable(PointerRNA *ptr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void rna_GPencilLayer_line_width_range(PointerRNA *ptr, int *min, int *max,
|
||||
int *UNUSED(softmin), int *UNUSED(softmax))
|
||||
{
|
||||
bGPDlayer *gpl = ptr->data;
|
||||
|
||||
/* The restrictions on max width here are due to OpenGL on Windows not supporting
|
||||
* any widths greater than 10 (for driver-drawn) strokes/points.
|
||||
*
|
||||
* Although most of our 2D strokes also don't suffer from this restriction,
|
||||
* it's relatively hard to test for that. So, for now, only volumetric strokes
|
||||
* get to be larger...
|
||||
*/
|
||||
if (gpl->flag & GP_LAYER_VOLUMETRIC) {
|
||||
*min = 1;
|
||||
*max = 300;
|
||||
}
|
||||
else {
|
||||
*min = 1;
|
||||
*max = 10;
|
||||
}
|
||||
}
|
||||
|
||||
static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr)
|
||||
{
|
||||
|
||||
bGPdata *gpd = ptr->id.data;
|
||||
|
||||
if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */
|
||||
@@ -106,6 +129,33 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value)
|
||||
}
|
||||
}
|
||||
|
||||
static int rna_GPencil_active_layer_index_get(PointerRNA *ptr)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ptr->id.data;
|
||||
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
|
||||
|
||||
return BLI_findindex(&gpd->layers, gpl);
|
||||
}
|
||||
|
||||
static void rna_GPencil_active_layer_index_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ptr->id.data;
|
||||
bGPDlayer *gpl = BLI_findlink(&gpd->layers, value);
|
||||
|
||||
gpencil_layer_setactive(gpd, gpl);
|
||||
}
|
||||
|
||||
static void rna_GPencil_active_layer_index_range(PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax)
|
||||
{
|
||||
bGPdata *gpd = (bGPdata *)ptr->id.data;
|
||||
|
||||
*min = 0;
|
||||
*max = max_ii(0, BLI_countlist(&gpd->layers) - 1);
|
||||
|
||||
*softmin = *min;
|
||||
*softmax = *max;
|
||||
}
|
||||
|
||||
static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
|
||||
{
|
||||
bGPdata *gpd = ptr->id.data;
|
||||
@@ -117,6 +167,63 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value)
|
||||
BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info));
|
||||
}
|
||||
|
||||
|
||||
static bGPDstroke *rna_GPencil_stroke_point_find_stroke(const bGPdata *gpd, const bGPDspoint *pt, bGPDlayer **r_gpl, bGPDframe **r_gpf)
|
||||
{
|
||||
bGPDlayer *gpl;
|
||||
bGPDstroke *gps;
|
||||
|
||||
/* sanity checks */
|
||||
if (ELEM(NULL, gpd, pt)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r_gpl) *r_gpl = NULL;
|
||||
if (r_gpf) *r_gpf = NULL;
|
||||
|
||||
/* there's no faster alternative than just looping over everything... */
|
||||
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
|
||||
if (gpl->actframe) {
|
||||
for (gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
|
||||
if ((pt >= gps->points) && (pt < &gps->points[gps->totpoints])) {
|
||||
/* found it */
|
||||
if (r_gpl) *r_gpl = gpl;
|
||||
if (r_gpf) *r_gpf = gpl->actframe;
|
||||
|
||||
return gps;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* didn't find it */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rna_GPencil_stroke_point_select_set(PointerRNA *ptr, const int value)
|
||||
{
|
||||
bGPdata *gpd = ptr->id.data;
|
||||
bGPDspoint *pt = ptr->data;
|
||||
bGPDstroke *gps = NULL;
|
||||
|
||||
/* Ensure that corresponding stroke is set
|
||||
* - Since we don't have direct access, we're going to have to search
|
||||
* - We don't apply selection value unless we can find the corresponding
|
||||
* stroke, so that they don't get out of sync
|
||||
*/
|
||||
gps = rna_GPencil_stroke_point_find_stroke(gpd, pt, NULL, NULL);
|
||||
if (gps) {
|
||||
/* Set the new selection state for the point */
|
||||
if (value)
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
else
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
|
||||
/* Check if the stroke should be selected or not... */
|
||||
gpencil_stroke_sync_selection(gps);
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count)
|
||||
{
|
||||
if (count > 0) {
|
||||
@@ -180,6 +287,27 @@ static void rna_GPencil_stroke_remove(bGPDframe *frame, ReportList *reports, Poi
|
||||
WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
static void rna_GPencil_stroke_select_set(PointerRNA *ptr, const int value)
|
||||
{
|
||||
bGPDstroke *gps = ptr->data;
|
||||
bGPDspoint *pt;
|
||||
int i;
|
||||
|
||||
/* set new value */
|
||||
if (value)
|
||||
gps->flag |= GP_STROKE_SELECT;
|
||||
else
|
||||
gps->flag &= ~GP_STROKE_SELECT;
|
||||
|
||||
/* ensure that the stroke's points are selected in the same way */
|
||||
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
|
||||
if (value)
|
||||
pt->flag |= GP_SPOINT_SELECT;
|
||||
else
|
||||
pt->flag &= ~GP_SPOINT_SELECT;
|
||||
}
|
||||
}
|
||||
|
||||
static bGPDframe *rna_GPencil_frame_new(bGPDlayer *layer, ReportList *reports, int frame_number)
|
||||
{
|
||||
bGPDframe *frame;
|
||||
@@ -291,6 +419,12 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Pressure", "Pressure of tablet at point when drawing it");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_SPOINT_SELECT);
|
||||
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_point_select_set");
|
||||
RNA_def_property_ui_text(prop, "Select", "Point is selected for viewport editing");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
@@ -338,12 +472,19 @@ static void rna_def_gpencil_stroke(BlenderRNA *brna)
|
||||
RNA_def_property_struct_type(prop, "GPencilStrokePoint");
|
||||
RNA_def_property_ui_text(prop, "Stroke Points", "Stroke data points");
|
||||
rna_def_gpencil_stroke_points_api(brna, prop);
|
||||
|
||||
|
||||
/* Settings */
|
||||
prop = RNA_def_property(srna, "draw_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
|
||||
RNA_def_property_enum_items(prop, stroke_draw_mode_items);
|
||||
RNA_def_property_ui_text(prop, "Draw Mode", "");
|
||||
RNA_def_property_update(prop, 0, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_STROKE_SELECT);
|
||||
RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencil_stroke_select_set");
|
||||
RNA_def_property_ui_text(prop, "Select", "Stroke is selected for viewport editing");
|
||||
RNA_def_property_update(prop, 0, "rna_GPencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
@@ -477,7 +618,14 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
|
||||
RNA_def_property_editable_func(prop, "rna_GPencilLayer_active_frame_editable");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
|
||||
|
||||
/* Drawing Color */
|
||||
/* Draw Style */
|
||||
// TODO: replace these with a "draw type" combo (i.e. strokes only, filled strokes, strokes + fills, volumetric)?
|
||||
prop = RNA_def_property(srna, "use_volumetric_strokes", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_VOLUMETRIC);
|
||||
RNA_def_property_ui_text(prop, "Volumetric Strokes", "Draw strokes as a series of circular blobs, resulting in a volumetric effect");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
/* Stroke Drawing Color */
|
||||
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
@@ -486,14 +634,29 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "color[3]");
|
||||
RNA_def_property_range(prop, 0.3, 1.0f);
|
||||
RNA_def_property_range(prop, 0.0, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Opacity", "Layer Opacity");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
/* Fill Drawing Color */
|
||||
prop = RNA_def_property(srna, "fill_color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "fill");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Fill Color", "Color for filling region bounded by each stroke");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fill_alpha", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "fill[3]");
|
||||
RNA_def_property_range(prop, 0.0, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Fill Opacity", "Opacity for filling region bounded by each stroke");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
/* Line Thickness */
|
||||
prop = RNA_def_property(srna, "line_width", PROP_INT, PROP_PIXEL);
|
||||
RNA_def_property_int_sdna(prop, NULL, "thickness");
|
||||
RNA_def_property_range(prop, 1, 10);
|
||||
//RNA_def_property_range(prop, 1, 10); /* 10 px limit comes from Windows OpenGL limits for natively-drawn strokes */
|
||||
RNA_def_property_int_funcs(prop, NULL, NULL, "rna_GPencilLayer_line_width_range");
|
||||
RNA_def_property_ui_text(prop, "Thickness", "Thickness of strokes (in pixels)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
@@ -503,27 +666,57 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Onion Skinning", "Ghost frames on either side of frame");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ghost_range_max", PROP_INT, PROP_NONE);
|
||||
prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "gstep");
|
||||
RNA_def_property_range(prop, 0, 120);
|
||||
RNA_def_property_ui_text(prop, "Max Ghost Range",
|
||||
"Maximum number of frames on either side of the active frame to show "
|
||||
"(0 = show the 'first' available sketch on either side)");
|
||||
RNA_def_property_ui_text(prop, "Frames Before",
|
||||
"Maximum number of frames to show before current frame "
|
||||
"(0 = show only the previous sketch)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "gstep_next");
|
||||
RNA_def_property_range(prop, 0, 120);
|
||||
RNA_def_property_ui_text(prop, "Frames After",
|
||||
"Maximum number of frames to show after current frame "
|
||||
"(0 = show only the next sketch)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_PREVCOL | GP_LAYER_GHOST_NEXTCOL);
|
||||
RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "gcolor_prev");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR_GAMMA);
|
||||
RNA_def_property_float_sdna(prop, NULL, "gcolor_next");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
/* Flags */
|
||||
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
|
||||
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 1);
|
||||
RNA_def_property_ui_text(prop, "Hide", "Set layer Visibility");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "lock", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_LOCKED);
|
||||
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
|
||||
RNA_def_property_ui_text(prop, "Locked", "Protect layer from further editing and/or frame changes");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "lock_frame", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_FRAMELOCK);
|
||||
RNA_def_property_ui_icon(prop, ICON_UNLOCKED, 1);
|
||||
RNA_def_property_ui_text(prop, "Frame Locked", "Lock current frame displayed by layer");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
|
||||
|
||||
@@ -592,6 +785,14 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Active Layer", "Active grease pencil layer");
|
||||
|
||||
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
|
||||
|
||||
RNA_def_property_int_funcs(prop,
|
||||
"rna_GPencil_active_layer_index_get",
|
||||
"rna_GPencil_active_layer_index_set",
|
||||
"rna_GPencil_active_layer_index_range");
|
||||
RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer");
|
||||
}
|
||||
|
||||
static void rna_def_gpencil_data(BlenderRNA *brna)
|
||||
@@ -631,7 +832,13 @@ static void rna_def_gpencil_data(BlenderRNA *brna)
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_DEPTH_STROKE_ENDPOINTS);
|
||||
RNA_def_property_ui_text(prop, "Only Endpoints", "Only use the first and last parts of the stroke for snapping");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
|
||||
|
||||
|
||||
prop = RNA_def_property(srna, "use_stroke_edit_mode", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_DATA_STROKE_EDITMODE);
|
||||
RNA_def_property_ui_text(prop, "Stroke Edit Mode", "Enable alternative keymap to make editing stroke points easier");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
|
||||
|
||||
/* API Functions */
|
||||
func = RNA_def_function(srna, "clear", "rna_GPencil_clear");
|
||||
RNA_def_function_ui_description(func, "Remove all the grease pencil data");
|
||||
}
|
||||
|
@@ -317,8 +317,8 @@ static void rna_def_movieclip(BlenderRNA *brna)
|
||||
/* grease pencil */
|
||||
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencil");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this movie clip");
|
||||
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
|
||||
|
||||
|
@@ -7572,8 +7572,8 @@ static void rna_def_nodetree(BlenderRNA *brna)
|
||||
/* Grease Pencil */
|
||||
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencil");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock");
|
||||
RNA_def_property_update(prop, NC_NODE, NULL);
|
||||
|
||||
|
@@ -2726,16 +2726,16 @@ static void rna_def_object(BlenderRNA *brna)
|
||||
/* Grease Pencil */
|
||||
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencil");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
|
||||
|
||||
/* pose */
|
||||
prop = RNA_def_property(srna, "pose_library", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "poselib");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "Action");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Pose Library", "Action used as a pose library for armatures");
|
||||
|
||||
prop = RNA_def_property(srna, "pose", PROP_POINTER, PROP_NONE);
|
||||
|
@@ -5738,8 +5738,8 @@ void RNA_def_scene(BlenderRNA *brna)
|
||||
/* Grease Pencil */
|
||||
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencil");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil Data", "Grease Pencil datablock");
|
||||
RNA_def_property_update(prop, NC_SCENE, NULL);
|
||||
|
||||
|
@@ -2425,8 +2425,8 @@ static void rna_def_space_image(BlenderRNA *brna)
|
||||
/* grease pencil */
|
||||
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencil");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
|
||||
|
||||
@@ -2594,8 +2594,8 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
|
||||
/* grease pencil */
|
||||
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencil");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this space");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
|
||||
|
||||
|
@@ -1435,8 +1435,8 @@ static void rna_def_trackingTrack(BlenderRNA *brna)
|
||||
/* grease pencil */
|
||||
prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_pointer_sdna(prop, NULL, "gpd");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_struct_type(prop, "GreasePencil");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT);
|
||||
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this track");
|
||||
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
|
||||
|
||||
|
@@ -4645,6 +4645,7 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf)
|
||||
WM_modalkeymap_assign(keymap, "CLIP_OT_select_circle");
|
||||
WM_modalkeymap_assign(keymap, "MASK_OT_select_circle");
|
||||
WM_modalkeymap_assign(keymap, "NODE_OT_select_circle");
|
||||
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle");
|
||||
|
||||
}
|
||||
|
||||
@@ -4741,6 +4742,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
|
||||
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border");
|
||||
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
|
||||
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
|
||||
WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_border");
|
||||
}
|
||||
|
||||
/* zoom to border modal operators */
|
||||
|
Reference in New Issue
Block a user