ff2ced7704faf5807e28725ad12e9c0eefae18e3
[blender.git] / release / scripts / startup / bl_ui / properties_physics_dynamicpaint.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 import bpy
22 from bpy.types import (
23     Panel,
24     UIList,
25 )
26 from .properties_physics_common import (
27     point_cache_ui,
28     effector_weights_ui,
29 )
30
31
32 class PHYSICS_UL_dynapaint_surfaces(UIList):
33     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
34         # assert(isinstance(item, bpy.types.DynamicPaintSurface)
35         surf = item
36         sticon = layout.enum_item_icon(surf, "surface_type", surf.surface_type)
37
38         if self.layout_type in {'DEFAULT', 'COMPACT'}:
39             row = layout.row(align=True)
40             row.label(text="", icon_value=icon)
41             row.prop(surf, "name", text="", emboss=False, icon_value=sticon)
42             row = layout.row(align=True)
43
44             if surf.use_color_preview:
45                 row.prop(
46                     surf, "show_preview", text="", emboss=False,
47                     icon='RESTRICT_VIEW_OFF' if surf.show_preview else 'RESTRICT_VIEW_ON'
48                 )
49             row.prop(surf, "is_active", text="")
50
51         elif self.layout_type == 'GRID':
52             layout.alignment = 'CENTER'
53             row = layout.row(align=True)
54             row.label(text="", icon_value=icon)
55             row.label(text="", icon_value=sticon)
56
57
58 class PhysicButtonsPanel:
59     bl_space_type = 'PROPERTIES'
60     bl_region_type = 'WINDOW'
61     bl_context = "physics"
62
63     def poll_dyn_paint(context):
64         ob = context.object
65         return (ob and ob.type == 'MESH') and context.dynamic_paint
66
67     def poll_dyn_canvas(context):
68         if not PhysicButtonsPanel.poll_dyn_paint(context):
69             return False
70
71         md = context.dynamic_paint
72         return (md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active)
73
74     def poll_dyn_canvas_paint(context):
75         if not PhysicButtonsPanel.poll_dyn_canvas(context):
76             return False
77
78         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
79         return (surface.surface_type == 'PAINT')
80
81     def poll_dyn_canvas_brush(context):
82         if not PhysicButtonsPanel.poll_dyn_paint(context):
83             return False
84
85         md = context.dynamic_paint
86         return (md and md.ui_type == 'BRUSH' and md.brush_settings)
87
88     def poll_dyn_output(context):
89         if not PhysicButtonsPanel.poll_dyn_canvas(context):
90             return False
91
92         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
93         return (not (surface.surface_format == 'VERTEX' and (surface.surface_type in {'DISPLACE', 'WAVE'})))
94
95     def poll_dyn_output_maps(context):
96         if not PhysicButtonsPanel.poll_dyn_output(context):
97             return False
98
99         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
100         return (surface.surface_format == 'IMAGE' and surface.surface_type == 'PAINT')
101
102
103 class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
104     bl_label = "Dynamic Paint"
105     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
106
107     @classmethod
108     def poll(cls, context):
109         if not PhysicButtonsPanel.poll_dyn_paint(context):
110             return False
111
112         return (context.engine in cls.COMPAT_ENGINES)
113
114     def draw(self, context):
115         layout = self.layout
116         layout.use_property_split = True
117
118         md = context.dynamic_paint
119
120         layout.prop(md, "ui_type")
121
122
123 class PHYSICS_PT_dynamic_paint_settings(PhysicButtonsPanel, Panel):
124     bl_label = "Settings"
125     bl_parent_id = 'PHYSICS_PT_dynamic_paint'
126     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
127
128     @classmethod
129     def poll(cls, context):
130         if not PhysicButtonsPanel.poll_dyn_paint(context):
131             return False
132
133         return (context.engine in cls.COMPAT_ENGINES)
134
135     def draw(self, context):
136         layout = self.layout
137
138         md = context.dynamic_paint
139
140         if md.ui_type == 'CANVAS':
141             canvas = md.canvas_settings
142
143             if canvas is None:
144                 layout.operator("dpaint.type_toggle", text="Add Canvas").type = 'CANVAS'
145                 return  # do nothing.
146
147             layout.operator("dpaint.type_toggle", text="Remove Canvas", icon='X').type = 'CANVAS'
148
149             surface = canvas.canvas_surfaces.active
150
151             row = layout.row()
152             row.template_list(
153                 "PHYSICS_UL_dynapaint_surfaces", "", canvas, "canvas_surfaces",
154                 canvas.canvas_surfaces, "active_index", rows=1
155             )
156
157             col = row.column(align=True)
158             col.operator("dpaint.surface_slot_add", icon='ZOOMIN', text="")
159             col.operator("dpaint.surface_slot_remove", icon='ZOOMOUT', text="")
160
161             layout.separator()
162
163             layout.use_property_split = True
164
165             if surface:
166                 flow = layout.grid_flow(
167                     row_major=True, columns=0, even_columns=True, even_rows=False, align=False
168                 )
169                 col = flow.column()
170
171                 col.prop(surface, "surface_format")
172
173                 if surface.surface_format != 'VERTEX':
174                     col.prop(surface, "image_resolution")
175                 col.prop(surface, "use_antialiasing")
176
177                 col = flow.column(align=True)
178                 col.prop(surface, "frame_start", text="Frame Start")
179                 col.prop(surface, "frame_end", text="End")
180
181                 col.prop(surface, "frame_substeps")
182
183         elif md.ui_type == 'BRUSH':
184             brush = md.brush_settings
185
186             if brush is None:
187                 layout.operator("dpaint.type_toggle", text="Add Brush").type = 'BRUSH'
188                 return  # do nothing.
189
190             layout.operator("dpaint.type_toggle", text="Remove Brush", icon='X').type = 'BRUSH'
191
192             layout.use_property_split = True
193
194             flow = layout.grid_flow(
195                 row_major=True, columns=0, even_columns=True, even_rows=False, align=False
196             )
197             col = flow.column()
198             col.prop(brush, "paint_color")
199             col.prop(brush, "paint_alpha", text="Alpha", slider=True)
200
201             col = flow.column()
202             col.prop(brush, "paint_wetness", text="Wetness", slider=True)
203             col.prop(brush, "use_absolute_alpha")
204             col.prop(brush, "use_paint_erase")
205
206
207 class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel):
208     bl_label = "Advanced"
209     bl_parent_id = "PHYSICS_PT_dynamic_paint"
210     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
211
212     @classmethod
213     def poll(cls, context):
214         if not PhysicButtonsPanel.poll_dyn_canvas(context):
215             return False
216
217         return (context.engine in cls.COMPAT_ENGINES)
218
219     def draw(self, context):
220         layout = self.layout
221         layout.use_property_split = True
222
223         canvas = context.dynamic_paint.canvas_settings
224         surface = canvas.canvas_surfaces.active
225         surface_type = surface.surface_type
226
227         layout.prop(surface, "surface_type")
228
229         layout.separator()
230
231         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
232
233         # per type settings
234         if surface_type == 'DISPLACE':
235             col = flow.column()
236
237             if surface.surface_format == 'VERTEX':
238                 col.prop(surface, "depth_clamp")
239                 col.prop(surface, "displace_factor")
240
241             col.prop(surface, "use_incremental_displace")
242             col.separator()
243
244         elif surface_type == 'WAVE':
245             col = flow.column()
246             col.prop(surface, "use_wave_open_border")
247             col.prop(surface, "wave_timescale")
248             col.prop(surface, "wave_speed")
249
250             col.separator()
251
252             col = flow.column()
253             col.prop(surface, "wave_damping")
254             col.prop(surface, "wave_spring")
255             col.prop(surface, "wave_smoothness")
256
257             col.separator()
258
259         col = flow.column()
260         col.prop(surface, "brush_group")
261
262         if surface_type not in {'DISPLACE', 'WAVE'}:
263             col = flow.column()  # flow the layout otherwise.
264
265         col.prop(surface, "brush_influence_scale", text="Scale Influence")
266         col.prop(surface, "brush_radius_scale", text="Radius")
267
268
269 class PHYSICS_PT_dp_advanced_canvas_paint_dry(PhysicButtonsPanel, Panel):
270     bl_label = "Dry"
271     bl_parent_id = "PHYSICS_PT_dp_advanced_canvas"
272     bl_options = {'DEFAULT_CLOSED'}
273     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
274
275     @classmethod
276     def poll(cls, context):
277         if not PhysicButtonsPanel.poll_dyn_canvas_paint(context):
278             return False
279
280         return (context.engine in cls.COMPAT_ENGINES)
281
282     def draw_header(self, context):
283         canvas = context.dynamic_paint.canvas_settings
284         surface = canvas.canvas_surfaces.active
285         self.layout.prop(surface, "use_drying", text="")
286
287     def draw(self, context):
288         layout = self.layout
289         layout.use_property_split = True
290         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
291
292         canvas = context.dynamic_paint.canvas_settings
293         surface = canvas.canvas_surfaces.active
294
295         flow.active = surface.use_drying
296
297         col = flow.column()
298         col.prop(surface, "dry_speed", text="Time")
299
300         col = flow.column()
301         col.prop(surface, "color_dry_threshold", text="Color")
302         col.prop(surface, "use_dry_log", text="Slow")
303
304
305 class PHYSICS_PT_dp_advanced_canvas_paint_dissolve(PhysicButtonsPanel, Panel):
306     bl_label = "Dissolve"
307     bl_parent_id = "PHYSICS_PT_dp_advanced_canvas"
308     bl_options = {'DEFAULT_CLOSED'}
309     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
310
311     @classmethod
312     def poll(cls, context):
313         if not PhysicButtonsPanel.poll_dyn_canvas(context):
314             return False
315
316         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
317
318         return (surface.surface_type != 'WAVE' and context.engine in cls.COMPAT_ENGINES)
319
320     def draw_header(self, context):
321         canvas = context.dynamic_paint.canvas_settings
322         surface = canvas.canvas_surfaces.active
323         self.layout.prop(surface, "use_dissolve", text="")
324
325     def draw(self, context):
326         layout = self.layout
327         layout.use_property_split = True
328         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
329
330         canvas = context.dynamic_paint.canvas_settings
331         surface = canvas.canvas_surfaces.active
332
333         flow.active = surface.use_dissolve
334
335         col = flow.column()
336         col.prop(surface, "dissolve_speed", text="Time")
337
338         col = flow.column()
339         col.prop(surface, "use_dissolve_log", text="Slow")
340
341
342 class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
343     bl_label = "Output"
344     bl_parent_id = "PHYSICS_PT_dynamic_paint"
345     bl_options = {'DEFAULT_CLOSED'}
346     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
347
348     @classmethod
349     def poll(cls, context):
350         if not PhysicButtonsPanel.poll_dyn_output(context):
351             return False
352
353         return (context.engine in cls.COMPAT_ENGINES)
354
355     def draw(self, context):
356         layout = self.layout
357         layout.use_property_split = True
358
359         canvas = context.dynamic_paint.canvas_settings
360         surface = canvas.canvas_surfaces.active
361         ob = context.object
362
363         surface_type = surface.surface_type
364
365         # vertex format outputs.
366         if surface.surface_format == 'VERTEX':
367             if surface_type == 'PAINT':
368                 # toggle active preview.
369                 layout.prop(surface, "preview_id")
370
371                 # paint-map output.
372                 row = layout.row()
373                 row.prop_search(surface, "output_name_a", ob.data, "vertex_colors", text="Paintmap Layer")
374
375                 icons = 'ZOOMOUT' if surface.output_exists(object=ob, index=0) else 'ZOOMIN'
376                 row.operator("dpaint.output_toggle", icon=icons, text="").output = 'A'
377
378                 # wet-map output.
379                 row = layout.row()
380                 row.prop_search(surface, "output_name_b", ob.data, "vertex_colors", text="Wetmap Layer")
381
382                 icons = 'ZOOMOUT' if surface.output_exists(object=ob, index=1) else 'ZOOMIN'
383                 row.operator("dpaint.output_toggle", icon=icons, text="").output = 'B'
384
385             elif surface_type == 'WEIGHT':
386                 row = layout.row()
387                 row.prop_search(surface, "output_name_a", ob, "vertex_groups", text="Vertex Group")
388
389                 icons = 'ZOOMOUT' if surface.output_exists(object=ob, index=0) else 'ZOOMIN'
390                 row.operator("dpaint.output_toggle", icon=icons, text="").output = 'A'
391
392         # image format outputs.
393         if surface.surface_format == 'IMAGE':
394             # layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT')
395
396             flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
397
398             col = flow.column()
399
400             col.prop_search(surface, "uv_layer", ob.data, "uv_layers", text="UV Map")
401
402             col = flow.column()
403             col.prop(surface, "image_fileformat")
404             col.prop(surface, "use_premultiply", text="Premultiply Alpha")
405
406             if surface_type != 'PAINT':
407                 col = col.column()
408                 col.prop(surface, "output_name_a", text="Filename")
409
410                 if surface_type == 'DISPLACE':
411                     col.prop(surface, "displace_type", text="Displace Type")
412                     col.prop(surface, "depth_clamp")
413
414                 elif surface_type == 'WAVE':
415                     col.prop(surface, "depth_clamp", text="Wave Clamp")
416
417
418 class PHYSICS_PT_dp_canvas_output_paintmaps(PhysicButtonsPanel, Panel):
419     bl_label = "Paintmaps"
420     bl_parent_id = "PHYSICS_PT_dp_canvas_output"
421     bl_options = {'DEFAULT_CLOSED'}
422     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
423
424     @classmethod
425     def poll(cls, context):
426         if not PhysicButtonsPanel.poll_dyn_output_maps(context):
427             return False
428
429         return (context.engine in cls.COMPAT_ENGINES)
430
431     def draw_header(self, context):
432         canvas = context.dynamic_paint.canvas_settings
433         surface = canvas.canvas_surfaces.active
434         self.layout.prop(surface, "use_output_a", text="")
435
436     def draw(self, context):
437         layout = self.layout
438         layout.use_property_split = True
439
440         canvas = context.dynamic_paint.canvas_settings
441         surface = canvas.canvas_surfaces.active
442
443         sub = layout.column()
444         sub.active = surface.use_output_a
445         sub.prop(surface, "output_name_a", text="Name")
446
447
448 class PHYSICS_PT_dp_canvas_output_bake(PhysicButtonsPanel, Panel):
449     bl_label = "Bake"
450     bl_parent_id = "PHYSICS_PT_dp_canvas_output"
451     bl_options = {'DEFAULT_CLOSED'}
452     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
453
454     @classmethod
455     def poll(cls, context):
456         if not PhysicButtonsPanel.poll_dyn_output_maps(context):
457             return False
458
459         return (context.engine in cls.COMPAT_ENGINES)
460
461     def draw(self, context):
462         layout = self.layout
463
464         canvas = context.dynamic_paint.canvas_settings
465         surface = canvas.canvas_surfaces.active
466
467         row = layout.row(align=True)
468         row.alignment = 'RIGHT'
469         row.label(text="Cache Path")
470
471         layout.prop(surface, "image_output_path", text="")
472         layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT')
473
474
475 class PHYSICS_PT_dp_canvas_output_wetmaps(PhysicButtonsPanel, Panel):
476     bl_label = "Wetmaps"
477     bl_parent_id = "PHYSICS_PT_dp_canvas_output"
478     bl_options = {'DEFAULT_CLOSED'}
479     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
480
481     @classmethod
482     def poll(cls, context):
483         if not PhysicButtonsPanel.poll_dyn_output_maps(context):
484             return False
485
486         return (context.engine in cls.COMPAT_ENGINES)
487
488     def draw_header(self, context):
489         canvas = context.dynamic_paint.canvas_settings
490         surface = canvas.canvas_surfaces.active
491         self.layout.prop(surface, "use_output_b", text="")
492
493     def draw(self, context):
494         layout = self.layout
495         layout.use_property_split = True
496
497         canvas = context.dynamic_paint.canvas_settings
498         surface = canvas.canvas_surfaces.active
499
500         sub = layout.column()
501         sub.active = surface.use_output_b
502         sub.prop(surface, "output_name_b", text="Name")
503
504
505 class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
506     bl_label = "Initial Color"
507     bl_parent_id = "PHYSICS_PT_dynamic_paint"
508     bl_options = {'DEFAULT_CLOSED'}
509     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
510
511     @classmethod
512     def poll(cls, context):
513         if not PhysicButtonsPanel.poll_dyn_canvas_paint(context):
514             return False
515
516         return (context.engine in cls.COMPAT_ENGINES)
517
518     def draw(self, context):
519         layout = self.layout
520
521         canvas = context.dynamic_paint.canvas_settings
522         surface = canvas.canvas_surfaces.active
523         ob = context.object
524
525         layout.use_property_split = True
526
527         col = layout.column()
528         col.prop(surface, "init_color_type", text="Type", expand=False)
529
530         if surface.init_color_type != 'NONE':
531             col.separator()
532
533         # dissolve
534         if surface.init_color_type == 'COLOR':
535             layout.prop(surface, "init_color")
536
537         elif surface.init_color_type == 'TEXTURE':
538             col.prop(surface, "init_texture")
539             col.prop_search(surface, "init_layername", ob.data, "uv_layers", text="UV Map")
540
541         elif surface.init_color_type == 'VERTEX_COLOR':
542             col.prop_search(surface, "init_layername", ob.data, "vertex_colors", text="Color Layer")
543
544
545 class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
546     bl_label = "Effects"
547     bl_parent_id = 'PHYSICS_PT_dynamic_paint'
548     bl_options = {'DEFAULT_CLOSED'}
549     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
550
551     @classmethod
552     def poll(cls, context):
553         if not PhysicButtonsPanel.poll_dyn_canvas_paint(context):
554             return False
555
556         return (context.engine in cls.COMPAT_ENGINES)
557
558     def draw(self, context):
559         return  # do nothing.
560
561
562 class PHYSICS_PT_dp_effects_spread(PhysicButtonsPanel, Panel):
563     bl_label = "Spread"
564     bl_parent_id = "PHYSICS_PT_dp_effects"
565     bl_options = {'DEFAULT_CLOSED'}
566     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
567
568     @classmethod
569     def poll(cls, context):
570         if not PhysicButtonsPanel.poll_dyn_paint(context):
571             return False
572
573         return (context.engine in cls.COMPAT_ENGINES)
574
575     def draw_header(self, context):
576         canvas = context.dynamic_paint.canvas_settings
577         surface = canvas.canvas_surfaces.active
578
579         self.layout.prop(surface, "use_spread", text="")
580
581     def draw(self, context):
582         layout = self.layout
583         layout.use_property_split = True
584         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
585
586         canvas = context.dynamic_paint.canvas_settings
587         surface = canvas.canvas_surfaces.active
588         layout.active = surface.use_spread
589
590         col = flow.column()
591         col.prop(surface, "spread_speed", text="Speed")
592
593         col = flow.column()
594         col.prop(surface, "color_spread_speed", text="Color")
595
596
597 class PHYSICS_PT_dp_effects_drip(PhysicButtonsPanel, Panel):
598     bl_label = "Drip"
599     bl_parent_id = "PHYSICS_PT_dp_effects"
600     bl_options = {'DEFAULT_CLOSED'}
601     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
602
603     @classmethod
604     def poll(cls, context):
605         if not PhysicButtonsPanel.poll_dyn_paint(context):
606             return False
607
608         return (context.engine in cls.COMPAT_ENGINES)
609
610     def draw_header(self, context):
611         canvas = context.dynamic_paint.canvas_settings
612         surface = canvas.canvas_surfaces.active
613
614         self.layout.prop(surface, "use_drip", text="")
615
616     def draw(self, context):
617         layout = self.layout
618         layout.use_property_split = True
619         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
620
621         canvas = context.dynamic_paint.canvas_settings
622         surface = canvas.canvas_surfaces.active
623
624         flow.active = surface.use_drip
625
626         col = flow.column()
627         col.prop(surface, "drip_velocity", slider=True)
628
629         col = flow.column()
630         col.prop(surface, "drip_acceleration", slider=True)
631
632
633 class PHYSICS_PT_dp_effects_drip_weights(PhysicButtonsPanel, Panel):
634     bl_label = "Weights"
635     bl_parent_id = "PHYSICS_PT_dp_effects_drip"
636     bl_options = {'DEFAULT_CLOSED'}
637     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
638
639     @classmethod
640     def poll(cls, context):
641         if not PhysicButtonsPanel.poll_dyn_paint(context):
642             return False
643
644         return (context.engine in cls.COMPAT_ENGINES)
645
646     def draw(self, context):
647         layout = self.layout
648
649         canvas = context.dynamic_paint.canvas_settings
650         surface = canvas.canvas_surfaces.active
651
652         layout.active = surface.use_drip
653
654         effector_weights_ui(self, context, surface.effector_weights, 'DYNAMIC_PAINT')
655
656
657 class PHYSICS_PT_dp_effects_shrink(PhysicButtonsPanel, Panel):
658     bl_label = "Shrink"
659     bl_parent_id = "PHYSICS_PT_dp_effects"
660     bl_options = {'DEFAULT_CLOSED'}
661     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
662
663     @classmethod
664     def poll(cls, context):
665         if not PhysicButtonsPanel.poll_dyn_paint(context):
666             return False
667
668         return (context.engine in cls.COMPAT_ENGINES)
669
670     def draw_header(self, context):
671         canvas = context.dynamic_paint.canvas_settings
672         surface = canvas.canvas_surfaces.active
673
674         self.layout.prop(surface, "use_shrink", text="")
675
676     def draw(self, context):
677         layout = self.layout
678         layout.use_property_split = True
679
680         canvas = context.dynamic_paint.canvas_settings
681         surface = canvas.canvas_surfaces.active
682         layout.active = surface.use_shrink
683
684         layout.prop(surface, "shrink_speed", text="Speed")
685
686
687 class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
688     bl_label = "Cache"
689     bl_parent_id = "PHYSICS_PT_dynamic_paint"
690     bl_options = {'DEFAULT_CLOSED'}
691     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
692
693     @classmethod
694     def poll(cls, context):
695         if not PhysicButtonsPanel.poll_dyn_canvas(context):
696             return False
697
698         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
699         return (surface.is_cache_user and (context.engine in cls.COMPAT_ENGINES))
700
701     def draw(self, context):
702         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
703         cache = surface.point_cache
704
705         point_cache_ui(self, context, cache, (cache.is_baked is False), 'DYNAMIC_PAINT')
706
707
708 class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
709     bl_label = "Source"
710     bl_parent_id = "PHYSICS_PT_dynamic_paint"
711     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
712
713     @classmethod
714     def poll(cls, context):
715         if not PhysicButtonsPanel.poll_dyn_canvas_brush(context):
716             return False
717
718         return (context.engine in cls.COMPAT_ENGINES)
719
720     def draw(self, context):
721         layout = self.layout
722         layout.use_property_split = True
723
724         brush = context.dynamic_paint.brush_settings
725         ob = context.object
726
727         layout.prop(brush, "paint_source", text="Paint")
728
729         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
730
731         if brush.paint_source == 'PARTICLE_SYSTEM':
732             col = flow.column()
733
734             col.separator()
735
736             col.prop_search(brush, "particle_system", ob, "particle_systems")
737
738             if brush.particle_system:
739                 col = flow.column()
740
741                 sub = col.column()
742                 sub.active = not brush.use_particle_radius
743                 sub.prop(brush, "solid_radius", text="Effect Solid Radius")
744
745                 col.prop(brush, "use_particle_radius", text="Use Particle's Radius")
746                 col.prop(brush, "smooth_radius", text="Smooth Radius")
747
748         if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}:
749             col = flow.column()
750
751             col.separator()
752
753             col.prop(brush, "paint_distance", text="Distance")
754             col.prop(brush, "proximity_falloff")
755
756             if brush.paint_source == 'VOLUME_DISTANCE':
757                 col.prop(brush, "invert_proximity")
758
759                 col = flow.column()
760                 col.prop(brush, "use_negative_volume")
761
762             if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE'}:
763                 col = flow.column() if brush.paint_source != 'VOLUME_DISTANCE' else col.column()
764                 col.prop(brush, "use_proximity_project")
765
766                 sub = col.column()
767                 sub.active = brush.use_proximity_project
768                 sub.prop(brush, "ray_direction")
769
770
771 class PHYSICS_PT_dp_brush_source_color_ramp(PhysicButtonsPanel, Panel):
772     bl_label = "Falloff Ramp"
773     bl_parent_id = "PHYSICS_PT_dp_brush_source"
774     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
775
776     @classmethod
777     def poll(cls, context):
778         if not PhysicButtonsPanel.poll_dyn_canvas_brush(context):
779             return False
780
781         brush = context.dynamic_paint.brush_settings
782         return ((brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'})
783                 and (brush.proximity_falloff == 'RAMP')
784                 and (context.engine in cls.COMPAT_ENGINES))
785
786     def draw(self, context):
787         layout = self.layout
788         layout.use_property_split = True
789
790         brush = context.dynamic_paint.brush_settings
791         layout.prop(brush, "use_proximity_ramp_alpha", text="Only Use Alpha")
792
793         layout.use_property_split = False
794         layout.template_color_ramp(brush, "paint_ramp", expand=True)
795
796
797 class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel):
798     bl_label = "Velocity"
799     bl_parent_id = "PHYSICS_PT_dynamic_paint"
800     bl_options = {'DEFAULT_CLOSED'}
801     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
802
803     @classmethod
804     def poll(cls, context):
805         if not PhysicButtonsPanel.poll_dyn_canvas_brush(context):
806             return False
807
808         return (context.engine in cls.COMPAT_ENGINES)
809
810     def draw(self, context):
811         layout = self.layout
812         layout.use_property_split = True
813         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
814
815         brush = context.dynamic_paint.brush_settings
816
817         col = flow.column()
818         col.prop(brush, "use_velocity_alpha")
819         col.prop(brush, "use_velocity_color")
820
821         col = flow.column()
822         col.prop(brush, "use_velocity_depth")
823         sub = col.column()
824         sub.active = (brush.use_velocity_alpha or brush.use_velocity_color or brush.use_velocity_depth)
825         sub.prop(brush, "velocity_max")
826
827
828 class PHYSICS_PT_dp_brush_velocity_color_ramp(PhysicButtonsPanel, Panel):
829     bl_label = "Ramp"
830     bl_parent_id = "PHYSICS_PT_dp_brush_velocity"
831     bl_options = {'DEFAULT_CLOSED'}
832     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
833
834     @classmethod
835     def poll(cls, context):
836         if not PhysicButtonsPanel.poll_dyn_canvas_brush(context):
837             return False
838
839         return (context.engine in cls.COMPAT_ENGINES)
840
841     def draw(self, context):
842         layout = self.layout
843
844         brush = context.dynamic_paint.brush_settings
845
846         layout.template_color_ramp(brush, "velocity_ramp", expand=True)
847
848
849 class PHYSICS_PT_dp_brush_velocity_smudge(PhysicButtonsPanel, Panel):
850     bl_label = "Smudge"
851     bl_parent_id = "PHYSICS_PT_dp_brush_velocity"
852     bl_options = {'DEFAULT_CLOSED'}
853     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
854
855     @classmethod
856     def poll(cls, context):
857         if not PhysicButtonsPanel.poll_dyn_canvas_brush(context):
858             return False
859
860         return (context.engine in cls.COMPAT_ENGINES)
861
862     def draw_header(self, context):
863         brush = context.dynamic_paint.brush_settings
864
865         self.layout.prop(brush, "use_smudge", text="")
866
867     def draw(self, context):
868         layout = self.layout
869         layout.use_property_split = True
870
871         brush = context.dynamic_paint.brush_settings
872
873         layout.active = brush.use_smudge
874         layout.prop(brush, "smudge_strength", text="Strength", slider=True)
875
876
877 class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel):
878     bl_label = "Waves"
879     bl_parent_id = "PHYSICS_PT_dynamic_paint"
880     bl_options = {'DEFAULT_CLOSED'}
881     COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
882
883     @classmethod
884     def poll(cls, context):
885         if not PhysicButtonsPanel.poll_dyn_canvas_brush(context):
886             return False
887
888         return (context.engine in cls.COMPAT_ENGINES)
889
890     def draw(self, context):
891         layout = self.layout
892         layout.use_property_split = True
893
894         brush = context.dynamic_paint.brush_settings
895
896         layout.prop(brush, "wave_type", text="Type")
897
898         flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
899
900         if brush.wave_type != 'REFLECT':
901             col = flow.column()
902             col.prop(brush, "wave_factor")
903
904             col = flow.column()
905             col.prop(brush, "wave_clamp")
906
907
908 classes = (
909     PHYSICS_UL_dynapaint_surfaces,
910     PHYSICS_PT_dynamic_paint,
911     PHYSICS_PT_dynamic_paint_settings,
912     PHYSICS_PT_dp_advanced_canvas,
913     PHYSICS_PT_dp_advanced_canvas_paint_dissolve,
914     PHYSICS_PT_dp_advanced_canvas_paint_dry,
915     PHYSICS_PT_dp_cache,
916     PHYSICS_PT_dp_effects,
917     PHYSICS_PT_dp_effects_spread,
918     PHYSICS_PT_dp_effects_drip,
919     PHYSICS_PT_dp_effects_drip_weights,
920     PHYSICS_PT_dp_effects_shrink,
921     PHYSICS_PT_dp_canvas_initial_color,
922     PHYSICS_PT_dp_brush_source,
923     PHYSICS_PT_dp_brush_source_color_ramp,
924     PHYSICS_PT_dp_brush_velocity,
925     PHYSICS_PT_dp_brush_velocity_color_ramp,
926     PHYSICS_PT_dp_brush_velocity_smudge,
927     PHYSICS_PT_dp_brush_wave,
928     PHYSICS_PT_dp_canvas_output,
929     PHYSICS_PT_dp_canvas_output_bake,
930     PHYSICS_PT_dp_canvas_output_paintmaps,
931     PHYSICS_PT_dp_canvas_output_wetmaps,
932 )
933
934
935 if __name__ == "__main__":  # only for live edit.
936     from bpy.utils import register_class
937     for cls in classes:
938         register_class(cls)