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