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