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