Cycles: svn merge -r39457:39669 https://svn.blender.org/svnroot/bf-blender/trunk...
[blender.git] / intern / cycles / blender / addon / ui.py
1 #
2 # Copyright 2011, Blender Foundation.
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 #
18
19 import bpy
20
21 from cycles import enums
22 from cycles import engine
23
24 class CyclesButtonsPanel():
25         bl_space_type = "PROPERTIES"
26         bl_region_type = "WINDOW"
27         bl_context = "render"
28         
29         @classmethod
30         def poll(cls, context):
31                 rd = context.scene.render
32                 return rd.engine == 'CYCLES'
33
34 class CyclesRender_PT_integrator(CyclesButtonsPanel, bpy.types.Panel):
35         bl_label = "Integrator"
36
37         def draw(self, context):
38                 layout = self.layout
39
40                 scene = context.scene
41                 cycles = scene.cycles
42
43                 split = layout.split()
44
45                 col = split.column()
46                 col.prop(cycles, "passes")
47                 col.prop(cycles, "no_caustics")
48
49                 col = split.column()
50                 col = col.column(align=True)
51                 col.prop(cycles, "max_bounces")
52                 col.prop(cycles, "min_bounces")
53
54                 #row = col.row()
55                 #row.prop(cycles, "blur_caustics")
56                 #row.active = not cycles.no_caustics
57
58 class CyclesRender_PT_film(CyclesButtonsPanel, bpy.types.Panel):
59         bl_label = "Film"
60
61         def draw(self, context):
62                 layout = self.layout
63
64                 scene = context.scene
65                 cycles = scene.cycles
66
67                 split = layout.split()
68
69                 split.prop(cycles, "exposure")
70                 split.prop(cycles, "response_curve", text="")
71
72 class CyclesRender_PT_debug(CyclesButtonsPanel, bpy.types.Panel):
73         bl_label = "Debug"
74         bl_options = {'DEFAULT_CLOSED'}
75
76         def draw(self, context):
77                 layout = self.layout
78
79                 scene = context.scene
80                 cycles = scene.cycles
81
82                 split = layout.split()
83
84                 col = split.column()
85
86                 sub = col.column(align=True)
87                 sub.prop(cycles, "debug_bvh_type", text="")
88                 sub.prop(cycles, "debug_use_spatial_splits")
89
90                 sub = col.column(align=True)
91                 sub.prop(cycles, "debug_tile_size")
92                 sub.prop(cycles, "debug_min_size")
93
94                 col = split.column(align=True)
95                 col.prop(cycles, "debug_cancel_timeout")
96                 col.prop(cycles, "debug_reset_timeout")
97                 col.prop(cycles, "debug_text_timeout")
98
99 class Cycles_PT_post_processing(CyclesButtonsPanel, bpy.types.Panel):
100         bl_label = "Post Processing"
101         bl_options = {'DEFAULT_CLOSED'}
102
103         def draw(self, context):
104                 layout = self.layout
105
106                 rd = context.scene.render
107
108                 split = layout.split()
109
110                 col = split.column()
111                 col.prop(rd, "use_compositing")
112                 col.prop(rd, "use_sequencer")
113
114                 col = split.column()
115                 col.prop(rd, "dither_intensity", text="Dither", slider=True)
116
117 class Cycles_PT_camera(CyclesButtonsPanel, bpy.types.Panel):
118         bl_label = "Cycles"
119         bl_context = "data"
120
121         @classmethod
122         def poll(cls, context):
123                 return context.camera
124
125         def draw(self, context):
126                 layout = self.layout
127
128                 camera = context.camera
129                 cycles = camera.cycles
130
131                 layout.prop(cycles, "lens_radius")
132
133 class Cycles_PT_context_material(CyclesButtonsPanel, bpy.types.Panel):
134         bl_label = "Surface"
135         bl_context = "material"
136         bl_options = {'HIDE_HEADER'}
137
138         @classmethod
139         def poll(cls, context):
140                 return (context.material or context.object) and CyclesButtonsPanel.poll(context)
141
142         def draw(self, context):
143                 layout = self.layout
144
145                 mat = context.material
146                 ob = context.object
147                 slot = context.material_slot
148                 space = context.space_data
149
150                 if ob:
151                         row = layout.row()
152
153                         row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
154
155                         col = row.column(align=True)
156                         col.operator("object.material_slot_add", icon='ZOOMIN', text="")
157                         col.operator("object.material_slot_remove", icon='ZOOMOUT', text="")
158
159                         col.menu("MATERIAL_MT_specials", icon='DOWNARROW_HLT', text="")
160
161                         if ob.mode == 'EDIT':
162                                 row = layout.row(align=True)
163                                 row.operator("object.material_slot_assign", text="Assign")
164                                 row.operator("object.material_slot_select", text="Select")
165                                 row.operator("object.material_slot_deselect", text="Deselect")
166
167                 split = layout.split(percentage=0.65)
168
169                 if ob:
170                         split.template_ID(ob, "active_material", new="material.new")
171                         row = split.row()
172
173                         if slot:
174                                 row.prop(slot, "link", text="")
175                         else:
176                                 row.label()
177                 elif mat:
178                         split.template_ID(space, "pin_id")
179                         split.separator()
180
181 class Cycles_PT_mesh_displacement(CyclesButtonsPanel, bpy.types.Panel):
182         bl_label = "Displacement"
183         bl_context = "data"
184
185         @classmethod
186         def poll(cls, context):
187                 return context.mesh or context.curve or context.meta_ball
188
189         def draw(self, context):
190                 layout = self.layout
191
192                 mesh = context.mesh
193                 curve = context.curve
194                 mball = context.meta_ball
195
196                 if mesh:
197                         cycles = mesh.cycles
198                 elif curve:
199                         cycles = curve.cycles
200                 elif mball:
201                         cycles = mball.cycles
202
203                 layout.prop(cycles, "displacement_method", text="Method")
204                 layout.prop(cycles, "use_subdivision");
205                 layout.prop(cycles, "dicing_rate");
206
207 def find_node(material, nodetype):
208         if material and material.node_tree:
209                 ntree = material.node_tree
210
211                 for node in ntree.nodes:
212                         if type(node) is not bpy.types.NodeGroup and node.type == nodetype:
213                                 return node
214         
215         return None
216
217 def find_node_input(node, name):
218         for input in node.inputs:
219                 if input.name == name:
220                         return input
221         
222         return None
223
224 def panel_node_draw(layout, id, output_type, input_name):
225         if not id.node_tree:
226                 layout.prop(id, "use_nodes")
227                 return
228
229         ntree = id.node_tree
230
231         node = find_node(id, output_type)
232         if not node:
233                 layout.label(text="No output node.")
234         else:
235                 input = find_node_input(node, input_name)
236                 layout.template_node_view(ntree, node, input);
237
238 class CyclesLamp_PT_lamp(CyclesButtonsPanel, bpy.types.Panel):
239         bl_label = "Surface"
240         bl_context = "data"
241
242         @classmethod
243         def poll(cls, context):
244                 return context.lamp and CyclesButtonsPanel.poll(context)
245
246         def draw(self, context):
247                 layout = self.layout
248
249                 mat = context.lamp
250                 panel_node_draw(layout, mat, 'OUTPUT_LAMP', 'Surface')
251
252 class CyclesWorld_PT_surface(CyclesButtonsPanel, bpy.types.Panel):
253         bl_label = "Surface"
254         bl_context = "world"
255
256         @classmethod
257         def poll(cls, context):
258                 return context.world and CyclesButtonsPanel.poll(context)
259
260         def draw(self, context):
261                 layout = self.layout
262
263                 mat = context.world
264                 panel_node_draw(layout, mat, 'OUTPUT_WORLD', 'Surface')
265
266 class CyclesWorld_PT_volume(CyclesButtonsPanel, bpy.types.Panel):
267         bl_label = "Volume"
268         bl_context = "world"
269
270         @classmethod
271         def poll(cls, context):
272                 return context.world and CyclesButtonsPanel.poll(context)
273
274         def draw(self, context):
275                 layout = self.layout
276                 layout.active = False
277
278                 mat = context.world
279                 panel_node_draw(layout, mat, 'OUTPUT_WORLD', 'Volume')
280
281 class CyclesMaterial_PT_surface(CyclesButtonsPanel, bpy.types.Panel):
282         bl_label = "Surface"
283         bl_context = "material"
284
285         @classmethod
286         def poll(cls, context):
287                 return context.material and CyclesButtonsPanel.poll(context)
288
289         def draw(self, context):
290                 layout = self.layout
291
292                 mat = context.material
293                 panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface')
294
295 class CyclesMaterial_PT_volume(CyclesButtonsPanel, bpy.types.Panel):
296         bl_label = "Volume"
297         bl_context = "material"
298
299         @classmethod
300         def poll(cls, context):
301                 return context.material and CyclesButtonsPanel.poll(context)
302
303         def draw(self, context):
304                 layout = self.layout
305                 layout.active = False
306
307                 mat = context.material
308                 panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume')
309
310 class CyclesMaterial_PT_displacement(CyclesButtonsPanel, bpy.types.Panel):
311         bl_label = "Displacement"
312         bl_context = "material"
313
314         @classmethod
315         def poll(cls, context):
316                 return context.material and CyclesButtonsPanel.poll(context)
317
318         def draw(self, context):
319                 layout = self.layout
320
321                 mat = context.material
322                 panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement')
323
324 class CyclesMaterial_PT_settings(CyclesButtonsPanel, bpy.types.Panel):
325         bl_label = "Settings"
326         bl_context = "material"
327         bl_options = {'DEFAULT_CLOSED'}
328
329         @classmethod
330         def poll(cls, context):
331                 # return context.material and CyclesButtonsPanel.poll(context)
332                 return False
333
334         def draw(self, context):
335                 layout = self.layout
336
337                 mat = context.material
338         
339                 row = layout.row()
340                 row.label(text="Light Group:")
341                 row.prop(mat, "light_group", text="")
342
343 class CyclesTexture_PT_context(CyclesButtonsPanel, bpy.types.Panel):
344         bl_label = ""
345         bl_context = "texture"
346         bl_options = {'HIDE_HEADER'}
347         COMPAT_ENGINES = {'CYCLES'}
348
349         def draw(self, context):
350                 layout = self.layout
351
352                 tex = context.texture
353                 space = context.space_data
354                 pin_id = space.pin_id
355                 use_pin_id = space.use_pin_id;
356                 user = context.texture_user
357                 node = context.texture_node
358
359                 if not use_pin_id or not isinstance(pin_id, bpy.types.Texture):
360                         pin_id = None
361
362                 if not pin_id:
363                         layout.template_texture_user()
364
365                 if user:
366                         layout.separator()
367
368                         split = layout.split(percentage=0.65)
369                         col = split.column()
370
371                         if pin_id:
372                                 col.template_ID(space, "pin_id")
373                         elif user:
374                                 col.template_ID(user, "texture", new="texture.new")
375                         
376                         if tex:
377                                 row = split.row()
378                                 row.prop(tex, "use_nodes", icon="NODETREE", text="")
379                                 row.label()
380
381                                 if not tex.use_nodes:
382                                         split = layout.split(percentage=0.2)
383                                         split.label(text="Type:")
384                                         split.prop(tex, "type", text="")
385
386 class CyclesTexture_PT_nodes(CyclesButtonsPanel, bpy.types.Panel):
387         bl_label = "Nodes"
388         bl_context = "texture"
389
390         @classmethod
391         def poll(cls, context):
392                 tex = context.texture
393                 return (tex and tex.use_nodes) and CyclesButtonsPanel.poll(context)
394
395         def draw(self, context):
396                 layout = self.layout
397
398                 tex = context.texture
399                 panel_node_draw(layout, tex, 'OUTPUT_TEXTURE', 'Color')
400
401 class CyclesTexture_PT_node(CyclesButtonsPanel, bpy.types.Panel):
402         bl_label = "Node"
403         bl_context = "texture"
404
405         @classmethod
406         def poll(cls, context):
407                 node = context.texture_node
408                 return node and CyclesButtonsPanel.poll(context)
409
410         def draw(self, context):
411                 layout = self.layout
412
413                 node = context.texture_node
414                 ntree = node.id_data
415                 layout.template_node_view(ntree, node, None)
416
417 class CyclesTexture_PT_mapping(CyclesButtonsPanel, bpy.types.Panel):
418         bl_label = "Mapping"
419         bl_context = "texture"
420
421         @classmethod
422         def poll(cls, context):
423                 tex = context.texture
424                 node = context.texture_node
425                 return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
426
427         def draw(self, context):
428                 layout = self.layout
429                 layout.label("Texture coordinate mapping goes here.");
430                 layout.label("Translate, rotate, scale, projection, XYZ.")
431
432 class CyclesTexture_PT_color(CyclesButtonsPanel, bpy.types.Panel):
433         bl_label = "Color"
434         bl_context = "texture"
435
436         @classmethod
437         def poll(cls, context):
438                 tex = context.texture
439                 node = context.texture_node
440                 return (node or (tex and tex.use_nodes)) and CyclesButtonsPanel.poll(context)
441
442         def draw(self, context):
443                 layout = self.layout
444                 layout.label("Color modification options go here.");
445                 layout.label("Ramp, brightness, contrast, saturation.")
446         
447 def draw_device(self, context):
448         scene = context.scene
449         layout = self.layout
450
451         if scene.render.engine == "CYCLES":
452                 cycles = scene.cycles
453
454                 if 'cuda' in engine.available_devices():
455                         layout.prop(cycles, "device")
456                 if cycles.device == 'CPU' and engine.with_osl():
457                         layout.prop(cycles, "shading_system")
458
459 def get_panels():
460         return [
461                 bpy.types.RENDER_PT_render,
462                 bpy.types.RENDER_PT_output,
463                 bpy.types.RENDER_PT_encoding,
464                 bpy.types.RENDER_PT_dimensions,
465                 bpy.types.RENDER_PT_stamp,
466                 bpy.types.WORLD_PT_context_world,
467                 bpy.types.DATA_PT_context_mesh,
468                 bpy.types.DATA_PT_context_camera,
469                 bpy.types.DATA_PT_context_lamp,
470                 bpy.types.DATA_PT_texture_space,
471                 bpy.types.DATA_PT_curve_texture_space,
472                 bpy.types.DATA_PT_mball_texture_space,
473                 bpy.types.DATA_PT_vertex_groups,
474                 bpy.types.DATA_PT_shape_keys,
475                 bpy.types.DATA_PT_uv_texture,
476                 bpy.types.DATA_PT_vertex_colors,
477                 bpy.types.DATA_PT_camera,
478                 bpy.types.DATA_PT_camera_display,
479                 bpy.types.DATA_PT_custom_props_mesh,
480                 bpy.types.DATA_PT_custom_props_camera,
481                 bpy.types.DATA_PT_custom_props_lamp,
482                 bpy.types.TEXTURE_PT_clouds,
483                 bpy.types.TEXTURE_PT_wood,
484                 bpy.types.TEXTURE_PT_marble,
485                 bpy.types.TEXTURE_PT_magic,
486                 bpy.types.TEXTURE_PT_blend,
487                 bpy.types.TEXTURE_PT_stucci,
488                 bpy.types.TEXTURE_PT_image,
489                 bpy.types.TEXTURE_PT_image_sampling,
490                 bpy.types.TEXTURE_PT_image_mapping,
491                 bpy.types.TEXTURE_PT_musgrave,
492                 bpy.types.TEXTURE_PT_voronoi,
493                 bpy.types.TEXTURE_PT_distortednoise,
494                 bpy.types.TEXTURE_PT_voxeldata,
495                 bpy.types.TEXTURE_PT_pointdensity,
496                 bpy.types.TEXTURE_PT_pointdensity_turbulence]
497
498 def register():
499         bpy.types.RENDER_PT_render.append(draw_device)
500
501         for panel in get_panels():
502                 panel.COMPAT_ENGINES.add('CYCLES')
503         
504 def unregister():
505         bpy.types.RENDER_PT_render.remove(draw_device)
506
507         for panel in get_panels():
508                 panel.COMPAT_ENGINES.remove('CYCLES')
509