DPAINT_OT_output_toggle operator was using an index option for what was really a...
[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 Panel
23
24 from .properties_physics_common import (
25     point_cache_ui,
26     effector_weights_ui,
27     )
28
29
30 class PhysicButtonsPanel():
31     bl_space_type = 'PROPERTIES'
32     bl_region_type = 'WINDOW'
33     bl_context = "physics"
34
35     @classmethod
36     def poll(cls, context):
37         ob = context.object
38         rd = context.scene.render
39         return (ob and ob.type == 'MESH') and (not rd.use_game_engine) and context.dynamic_paint
40
41
42 class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
43     bl_label = "Dynamic Paint"
44
45     def draw(self, context):
46         layout = self.layout
47
48         md = context.dynamic_paint
49         ob = context.object
50
51         layout.prop(md, "ui_type", expand=True)
52
53         if md.ui_type == 'CANVAS':
54             canvas = md.canvas_settings
55
56             if canvas is None:
57                 layout.operator("dpaint.type_toggle", text="Add Canvas").type = 'CANVAS'
58             else:
59                 layout.operator("dpaint.type_toggle", text="Remove Canvas", icon='X').type = 'CANVAS'
60
61                 surface = canvas.canvas_surfaces.active
62
63                 row = layout.row()
64                 row.template_list(canvas, "canvas_surfaces", canvas.canvas_surfaces, "active_index", rows=2)
65
66                 col = row.column(align=True)
67                 col.operator("dpaint.surface_slot_add", icon='ZOOMIN', text="")
68                 col.operator("dpaint.surface_slot_remove", icon='ZOOMOUT', text="")
69
70                 if surface:
71                     layout.prop(surface, "name")
72                     layout.prop(surface, "surface_format")
73
74                     col = layout.column()
75                     if surface.surface_format != 'VERTEX':
76                         col.label(text="Quality:")
77                         col.prop(surface, "image_resolution")
78                     col.prop(surface, "use_antialiasing")
79
80                     col = layout.column()
81                     col.label(text="Frames:")
82                     split = col.split()
83
84                     col = split.column(align=True)
85                     col.prop(surface, "frame_start", text="Start")
86                     col.prop(surface, "frame_end", text="End")
87
88                     split.prop(surface, "frame_substeps")
89
90         elif md.ui_type == 'BRUSH':
91             brush = md.brush_settings
92             engine = context.scene.render.engine
93
94             if brush is None:
95                 layout.operator("dpaint.type_toggle", text="Add Brush").type = 'BRUSH'
96             else:
97                 layout.operator("dpaint.type_toggle", text="Remove Brush", icon='X').type = 'BRUSH'
98
99                 split = layout.split()
100
101                 col = split.column()
102                 col.prop(brush, "absolute_alpha")
103                 col.prop(brush, "paint_erase")
104                 col.prop(brush, "paint_wetness", text="Wetness")
105
106                 col = split.column()
107                 if engine == 'BLENDER_RENDER':
108                     sub = col.column()
109                     sub.active = (brush.paint_source != 'PARTICLE_SYSTEM')
110                     sub.prop(brush, "use_material")
111                 if brush.use_material and brush.paint_source != 'PARTICLE_SYSTEM' and engine == 'BLENDER_RENDER':
112                     col.prop(brush, "material", text="")
113                     col.prop(brush, "paint_alpha", text="Alpha Factor")
114                 else:
115                     col.prop(brush, "paint_color", text="")
116                     col.prop(brush, "paint_alpha", text="Alpha")
117
118
119 class PHYSICS_PT_dp_advanced_canvas(PhysicButtonsPanel, Panel):
120     bl_label = "Dynamic Paint Advanced"
121
122     @classmethod
123     def poll(cls, context):
124         md = context.dynamic_paint
125         return md and md.ui_type == 'CANVAS' and md.canvas_settings and md.canvas_settings.canvas_surfaces.active
126
127     def draw(self, context):
128         layout = self.layout
129
130         canvas = context.dynamic_paint.canvas_settings
131         surface = canvas.canvas_surfaces.active
132         ob = context.object
133
134         surface_type = surface.surface_type
135
136         layout.prop(surface, "surface_type")
137         layout.separator()
138
139         # dissolve
140         if surface_type == 'PAINT':
141             split = layout.split(percentage=0.35)
142             split.label(text="Wetmap drying:")
143
144             col = split.column()
145             split = col.split(percentage=0.7)
146             split.prop(surface, "dry_speed", text="Time")
147             split.prop(surface, "use_dry_log", text="Slow")
148
149         if surface_type != 'WAVE':
150             split = layout.split(percentage=0.35)
151             col = split.column()
152             if surface_type == 'WEIGHT':
153                 col.prop(surface, "use_dissolve", text="Fade:")
154             else:
155                 col.prop(surface, "use_dissolve", text="Dissolve:")
156             col = split.column()
157             col.active = surface.use_dissolve
158             split = col.split(percentage=0.7)
159             split.prop(surface, "dissolve_speed", text="Time")
160             split.prop(surface, "use_dissolve_log", text="Slow")
161
162         # per type settings
163         if surface_type == 'DISPLACE':
164             layout.prop(surface, "use_incremental_displace")
165             if surface.surface_format == 'VERTEX':
166                 row = layout.row()
167                 row.prop(surface, "depth_clamp")
168                 row.prop(surface, "displace_factor")
169
170         elif surface_type == 'WAVE':
171             layout.prop(surface, "wave_open_borders")
172
173             split = layout.split()
174
175             col = split.column(align=True)
176             col.prop(surface, "wave_timescale")
177             col.prop(surface, "wave_speed")
178
179             col = split.column(align=True)
180             col.prop(surface, "wave_damping")
181             col.prop(surface, "wave_spring")
182
183         layout.separator()
184         layout.prop(surface, "brush_group", text="Brush Group")
185
186
187 class PHYSICS_PT_dp_canvas_output(PhysicButtonsPanel, Panel):
188     bl_label = "Dynamic Paint Output"
189     bl_options = {'DEFAULT_CLOSED'}
190
191     @classmethod
192     def poll(cls, context):
193         md = context.dynamic_paint
194         if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
195             return 0
196         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
197         return surface and not (surface.surface_format == 'VERTEX' and (surface.surface_type in {'DISPLACE', 'WAVE'}))
198
199     def draw(self, context):
200         layout = self.layout
201
202         canvas = context.dynamic_paint.canvas_settings
203         surface = canvas.canvas_surfaces.active
204         ob = context.object
205
206         surface_type = surface.surface_type
207
208         # vertex format outputs
209         if surface.surface_format == 'VERTEX':
210             if surface_type == 'PAINT':
211                  # toggle active preview
212                 layout.prop(surface, "preview_id")
213
214                 # paintmap output
215                 row = layout.row()
216                 row.prop_search(surface, "output_name_a", ob.data, "vertex_colors", text="Paintmap layer: ")
217                 if surface.output_exists(object=ob, index=0):
218                     ic = 'ZOOMOUT'
219                 else:
220                     ic = 'ZOOMIN'
221
222                 row.operator("dpaint.output_toggle", icon=ic, text="").output = 'A'
223
224                 # wetmap output
225                 row = layout.row()
226                 row.prop_search(surface, "output_name_b", ob.data, "vertex_colors", text="Wetmap layer: ")
227                 if surface.output_exists(object=ob, index=1):
228                     ic = 'ZOOMOUT'
229                 else:
230                     ic = 'ZOOMIN'
231
232                 row.operator("dpaint.output_toggle", icon=ic, text="").output = 'B'
233
234             elif surface_type == 'WEIGHT':
235                 row = layout.row()
236                 row.prop_search(surface, "output_name_a", ob, "vertex_groups", text="Vertex Group: ")
237                 if surface.output_exists(object=ob, index=0):
238                     ic = 'ZOOMOUT'
239                 else:
240                     ic = 'ZOOMIN'
241
242                 row.operator("dpaint.output_toggle", icon=ic, text="").output = 'A'
243
244         # image format outputs
245         if surface.surface_format == 'IMAGE':
246             layout.operator("dpaint.bake", text="Bake Image Sequence", icon='MOD_DYNAMICPAINT')
247             layout.prop_search(surface, "uv_layer", ob.data, "uv_textures", text="UV layer:")
248             layout.separator()
249
250             layout.prop(surface, "image_output_path", text="")
251             row = layout.row()
252             row.prop(surface, "image_fileformat", text="")
253             row.prop(surface, "premultiply", text="Premultiply alpha")
254
255             if surface_type == 'PAINT':
256                 split = layout.split(percentage=0.4)
257                 split.prop(surface, "use_output_a", text="Paintmaps:")
258                 sub = split.row()
259                 sub.active = surface.use_output_a
260                 sub.prop(surface, "output_name_a", text="")
261
262                 split = layout.split(percentage=0.4)
263                 split.prop(surface, "do_output_b", text="Wetmaps:")
264                 sub = split.row()
265                 sub.active = surface.do_output_b
266                 sub.prop(surface, "output_name_b", text="")
267             else:
268                 col = layout.column()
269                 col.prop(surface, "output_name_a", text="Filename: ")
270                 if surface_type == 'DISPLACE':
271                     col.prop(surface, "displace_type", text="Displace Type")
272                     col.prop(surface, "depth_clamp")
273                 elif surface_type == 'WAVE':
274                     col.prop(surface, "depth_clamp", text="Wave Clamp")
275
276
277 class PHYSICS_PT_dp_canvas_initial_color(PhysicButtonsPanel, Panel):
278     bl_label = "Dynamic Paint Initial Color"
279     bl_options = {'DEFAULT_CLOSED'}
280
281     @classmethod
282     def poll(cls, context):
283         md = context.dynamic_paint
284         if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
285             return 0
286         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
287         return (surface and surface.surface_type == 'PAINT')
288
289     def draw(self, context):
290         layout = self.layout
291
292         canvas = context.dynamic_paint.canvas_settings
293         surface = canvas.canvas_surfaces.active
294         ob = context.object
295
296         layout.prop(surface, "init_color_type", expand=False)
297         layout.separator()
298
299         # dissolve
300         if surface.init_color_type == 'COLOR':
301             layout.prop(surface, "init_color")
302
303         elif surface.init_color_type == 'TEXTURE':
304             layout.prop(surface, "init_texture")
305             layout.prop_search(surface, "init_layername", ob.data, "uv_textures", text="UV Layer:")
306
307         elif surface.init_color_type == 'VERTEX_COLOR':
308             layout.prop_search(surface, "init_layername", ob.data, "vertex_colors", text="Color Layer: ")
309
310
311 class PHYSICS_PT_dp_effects(PhysicButtonsPanel, Panel):
312     bl_label = "Dynamic Paint Effects"
313     bl_options = {'DEFAULT_CLOSED'}
314
315     @classmethod
316     def poll(cls, context):
317         md = context.dynamic_paint
318         if not (md and md.ui_type == 'CANVAS' and md.canvas_settings):
319             return False
320         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
321         return (surface and surface.surface_type == 'PAINT')
322
323     def draw(self, context):
324         layout = self.layout
325
326         canvas = context.dynamic_paint.canvas_settings
327         surface = canvas.canvas_surfaces.active
328
329         layout.prop(surface, "effect_ui", expand=True)
330
331         if surface.effect_ui == 'SPREAD':
332             layout.prop(surface, "use_spread")
333
334             row = layout.row()
335             row.active = surface.use_spread
336             row.prop(surface, "spread_speed")
337             row.prop(surface, "color_spread_speed")
338
339         elif surface.effect_ui == 'DRIP':
340             layout.prop(surface, "use_drip")
341
342             col = layout.column()
343             col.active = surface.use_drip
344             effector_weights_ui(self, context, surface.effector_weights)
345
346             layout.label(text="Surface Movement:")
347             row = layout.row()
348             row.prop(surface, "drip_velocity", slider=True)
349             row.prop(surface, "drip_acceleration", slider=True)
350
351         elif surface.effect_ui == 'SHRINK':
352             layout.prop(surface, "use_shrink")
353
354             row = layout.row()
355             row.active = surface.use_shrink
356             row.prop(surface, "shrink_speed")
357
358
359 class PHYSICS_PT_dp_cache(PhysicButtonsPanel, Panel):
360     bl_label = "Dynamic Paint Cache"
361     bl_options = {'DEFAULT_CLOSED'}
362
363     @classmethod
364     def poll(cls, context):
365         md = context.dynamic_paint
366         return (md and
367                 md.ui_type == 'CANVAS' and
368                 md.canvas_settings and
369                 md.canvas_settings.canvas_surfaces.active and
370                 md.canvas_settings.canvas_surfaces.active.uses_cache)
371
372     def draw(self, context):
373         layout = self.layout
374
375         surface = context.dynamic_paint.canvas_settings.canvas_surfaces.active
376         cache = surface.point_cache
377
378         point_cache_ui(self, context, cache, (cache.is_baked is False), 'DYNAMIC_PAINT')
379
380
381 class PHYSICS_PT_dp_brush_source(PhysicButtonsPanel, Panel):
382     bl_label = "Dynamic Paint Source"
383
384     @classmethod
385     def poll(cls, context):
386         md = context.dynamic_paint
387         return md and md.ui_type == 'BRUSH' and md.brush_settings
388
389     def draw(self, context):
390         layout = self.layout
391
392         brush = context.dynamic_paint.brush_settings
393         ob = context.object
394
395         split = layout.split()
396         col = split.column()
397         col.prop(brush, "paint_source")
398
399         if brush.paint_source == 'PARTICLE_SYSTEM':
400             col.prop_search(brush, "particle_system", ob, "particle_systems", text="")
401             if brush.particle_system:
402                 col.label(text="Particle effect:")
403                 sub = col.column()
404                 sub.active = not brush.use_particle_radius
405                 sub.prop(brush, "solid_radius", text="Solid Radius")
406                 col.prop(brush, "use_particle_radius", text="Use Particle's Radius")
407                 col.prop(brush, "smooth_radius", text="Smooth radius")
408
409         if brush.paint_source in {'DISTANCE', 'VOLUME_DISTANCE', 'POINT'}:
410             col.prop(brush, "paint_distance", text="Paint Distance")
411             split = layout.row().split(percentage=0.4)
412             sub = split.column()
413             if brush.paint_source == 'DISTANCE':
414                 sub.prop(brush, "proximity_project")
415             elif brush.paint_source == 'VOLUME_DISTANCE':
416                 sub.prop(brush, "proximity_inverse")
417                 sub.prop(brush, "negate_volume")
418
419             sub = split.column()
420             if brush.paint_source == 'DISTANCE':
421                 column = sub.column()
422                 column.active = brush.proximity_project
423                 column.prop(brush, "ray_direction")
424             sub.prop(brush, "proximity_falloff")
425             if brush.proximity_falloff == 'RAMP':
426                 col = layout.row().column()
427                 col.separator()
428                 col.prop(brush, "proximity_ramp_alpha", text="Only Use Alpha")
429                 col.template_color_ramp(brush, "paint_ramp", expand=True)
430
431
432 class PHYSICS_PT_dp_brush_velocity(PhysicButtonsPanel, Panel):
433     bl_label = "Dynamic Paint Velocity"
434     bl_options = {'DEFAULT_CLOSED'}
435
436     @classmethod
437     def poll(cls, context):
438         md = context.dynamic_paint
439         return md and md.ui_type == 'BRUSH' and md.brush_settings
440
441     def draw(self, context):
442         layout = self.layout
443
444         brush = context.dynamic_paint.brush_settings
445         ob = context.object
446
447         split = layout.split()
448
449         col = split.column()
450         col.prop(brush, "velocity_alpha")
451         col.prop(brush, "velocity_color")
452
453         split.prop(brush, "velocity_depth")
454
455         col = layout.column()
456         col.active = (brush.velocity_alpha or brush.velocity_color or brush.velocity_depth)
457         col.prop(brush, "velocity_max")
458         col.template_color_ramp(brush, "velocity_ramp", expand=True)
459         layout.separator()
460
461         row = layout.row()
462         row.prop(brush, "use_smudge")
463         sub = row.row()
464         sub.active = brush.use_smudge
465         sub.prop(brush, "smudge_strength")
466
467
468 class PHYSICS_PT_dp_brush_wave(PhysicButtonsPanel, Panel):
469     bl_label = "Dynamic Paint Waves"
470     bl_options = {'DEFAULT_CLOSED'}
471
472     @classmethod
473     def poll(cls, context):
474         md = context.dynamic_paint
475         return md and md.ui_type == 'BRUSH' and md.brush_settings
476
477     def draw(self, context):
478         layout = self.layout
479
480         brush = context.dynamic_paint.brush_settings
481         ob = context.object
482
483         layout.prop(brush, "wave_type")
484         if brush.wave_type != 'REFLECT':
485             row = layout.row()
486             row.prop(brush, "wave_factor")
487             row.prop(brush, "wave_clamp")
488
489
490 def register():
491     bpy.utils.register_module(__name__)
492
493
494 def unregister():
495     bpy.utils.register_module(__name__)
496
497 if __name__ == "__main__":
498     register()