8f2c3085881f7c585a0d1ee9b14c32a92dc24340
[blender.git] / release / scripts / startup / bl_ui / properties_texture.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 from bpy.types import Menu, Panel, UIList
22
23 from bpy.types import (
24     Brush,
25     FreestyleLineStyle,
26     Lamp,
27     Material,
28     Object,
29     ParticleSettings,
30     Texture,
31     World,
32 )
33
34 from rna_prop_ui import PropertyPanel
35
36 from .properties_paint_common import brush_texture_settings
37
38
39 class TEXTURE_MT_specials(Menu):
40     bl_label = "Texture Specials"
41     COMPAT_ENGINES = {'BLENDER_RENDER'}
42
43     def draw(self, context):
44         layout = self.layout
45
46         layout.operator("texture.slot_copy", icon='COPYDOWN')
47         layout.operator("texture.slot_paste", icon='PASTEDOWN')
48
49
50 class TEXTURE_MT_envmap_specials(Menu):
51     bl_label = "Environment Map Specials"
52     COMPAT_ENGINES = {'BLENDER_RENDER'}
53
54     def draw(self, context):
55         layout = self.layout
56
57         layout.operator("texture.envmap_save", icon='IMAGEFILE')
58         layout.operator("texture.envmap_clear", icon='FILE_REFRESH')
59         layout.operator("texture.envmap_clear_all", icon='FILE_REFRESH')
60
61
62 class TEXTURE_UL_texslots(UIList):
63
64     def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
65         # assert(isinstance(item, bpy.types.MaterialTextureSlot)
66         ma = data
67         slot = item
68         tex = slot.texture if slot else None
69         if self.layout_type in {'DEFAULT', 'COMPACT'}:
70             if tex:
71                 layout.prop(tex, "name", text="", emboss=False, icon_value=icon)
72             else:
73                 layout.label(text="", icon_value=icon)
74             if tex and isinstance(item, bpy.types.MaterialTextureSlot):
75                 layout.prop(ma, "use_textures", text="", index=index)
76         elif self.layout_type == 'GRID':
77             layout.alignment = 'CENTER'
78             layout.label(text="", icon_value=icon)
79
80
81 from .properties_material import active_node_mat
82
83
84 def context_tex_datablock(context):
85     idblock = context.material
86     if idblock:
87         return active_node_mat(idblock)
88
89     idblock = context.lamp
90     if idblock:
91         return idblock
92
93     idblock = context.world
94     if idblock:
95         return idblock
96
97     idblock = context.brush
98     if idblock:
99         return idblock
100
101     idblock = context.line_style
102     if idblock:
103         return idblock
104
105     if context.particle_system:
106         idblock = context.particle_system.settings
107
108     return idblock
109
110
111 def id_tex_datablock(bid):
112     if isinstance(bid, Object):
113         if bid.type == 'LAMP':
114             return bid.data
115         return bid.active_material
116
117     return bid
118
119
120 class TextureButtonsPanel:
121     bl_space_type = 'PROPERTIES'
122     bl_region_type = 'WINDOW'
123     bl_context = "texture"
124
125     @classmethod
126     def poll(cls, context):
127         tex = context.texture
128         return tex and (tex.type != 'NONE' or tex.use_nodes) and (context.engine in cls.COMPAT_ENGINES)
129
130
131 class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel):
132     bl_label = ""
133     bl_options = {'HIDE_HEADER'}
134     COMPAT_ENGINES = {'BLENDER_RENDER'}
135
136     @classmethod
137     def poll(cls, context):
138         engine = context.engine
139         # if not (hasattr(context, "texture_slot") or hasattr(context, "texture_node")):
140         #     return False
141         return ((context.material or
142                  context.world or
143                  context.lamp or
144                  context.texture or
145                  context.line_style or
146                  context.particle_system or
147                  isinstance(context.space_data.pin_id, ParticleSettings) or
148                  context.texture_user) and
149                 (engine in cls.COMPAT_ENGINES))
150
151     def draw(self, context):
152         layout = self.layout
153
154         slot = getattr(context, "texture_slot", None)
155         node = getattr(context, "texture_node", None)
156         space = context.space_data
157         tex = context.texture
158         idblock = context_tex_datablock(context)
159         pin_id = space.pin_id
160
161         space.use_limited_texture_context = True
162
163         if space.use_pin_id and not isinstance(pin_id, Texture):
164             idblock = id_tex_datablock(pin_id)
165             pin_id = None
166
167         if not space.use_pin_id:
168             layout.row().prop(space, "texture_context", expand=True)
169             pin_id = None
170
171         if space.texture_context == 'OTHER':
172             if not pin_id:
173                 layout.template_texture_user()
174             user = context.texture_user
175             if user or pin_id:
176                 layout.separator()
177
178                 row = layout.row()
179
180                 if pin_id:
181                     row.template_ID(space, "pin_id")
182                 else:
183                     propname = context.texture_user_property.identifier
184                     row.template_ID(user, propname, new="texture.new")
185
186                 if tex:
187                     split = layout.split(percentage=0.2)
188                     if tex.use_nodes:
189                         if slot:
190                             split.label(text="Output:")
191                             split.prop(slot, "output_node", text="")
192                     else:
193                         split.label(text="Type:")
194                         split.prop(tex, "type", text="")
195             return
196
197         tex_collection = (pin_id is None) and (node is None) and (not isinstance(idblock, Brush))
198
199         if tex_collection:
200             row = layout.row()
201
202             row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots",
203                               idblock, "active_texture_index", rows=2)
204
205             col = row.column(align=True)
206             col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
207             col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
208             col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
209
210         if tex_collection:
211             layout.template_ID(idblock, "active_texture", new="texture.new")
212         elif node:
213             layout.template_ID(node, "texture", new="texture.new")
214         elif idblock:
215             layout.template_ID(idblock, "texture", new="texture.new")
216
217         if pin_id:
218             layout.template_ID(space, "pin_id")
219
220         if tex:
221             split = layout.split(percentage=0.2)
222             if tex.use_nodes:
223                 if slot:
224                     split.label(text="Output:")
225                     split.prop(slot, "output_node", text="")
226             else:
227                 split.label(text="Type:")
228                 split.prop(tex, "type", text="")
229
230
231 class TEXTURE_PT_preview(TextureButtonsPanel, Panel):
232     bl_label = "Preview"
233     COMPAT_ENGINES = {'BLENDER_RENDER'}
234
235     def draw(self, context):
236         layout = self.layout
237
238         tex = context.texture
239         slot = getattr(context, "texture_slot", None)
240         idblock = context_tex_datablock(context)
241
242         if idblock:
243             layout.template_preview(tex, parent=idblock, slot=slot)
244         else:
245             layout.template_preview(tex, slot=slot)
246
247         # Show Alpha Button for Brush Textures, see #29502
248         if context.space_data.texture_context == 'BRUSH':
249             layout.prop(tex, "use_preview_alpha")
250
251
252 class TEXTURE_PT_colors(TextureButtonsPanel, Panel):
253     bl_label = "Colors"
254     bl_options = {'DEFAULT_CLOSED'}
255     COMPAT_ENGINES = {'BLENDER_RENDER'}
256
257     def draw(self, context):
258         layout = self.layout
259
260         tex = context.texture
261
262         layout.prop(tex, "use_color_ramp", text="Ramp")
263         if tex.use_color_ramp:
264             layout.template_color_ramp(tex, "color_ramp", expand=True)
265
266         split = layout.split()
267
268         col = split.column()
269         col.label(text="RGB Multiply:")
270         sub = col.column(align=True)
271         sub.prop(tex, "factor_red", text="R")
272         sub.prop(tex, "factor_green", text="G")
273         sub.prop(tex, "factor_blue", text="B")
274
275         col = split.column()
276         col.label(text="Adjust:")
277         col.prop(tex, "intensity")
278         col.prop(tex, "contrast")
279         col.prop(tex, "saturation")
280
281         col = layout.column()
282         col.prop(tex, "use_clamp", text="Clamp")
283
284 # Texture Slot Panels #
285
286
287 class TextureSlotPanel(TextureButtonsPanel):
288     COMPAT_ENGINES = {'BLENDER_RENDER'}
289
290     @classmethod
291     def poll(cls, context):
292         if not hasattr(context, "texture_slot"):
293             return False
294
295         engine = context.engine
296         return TextureButtonsPanel.poll(cls, context) and (engine in cls.COMPAT_ENGINES)
297
298
299 # Texture Type Panels #
300
301
302 class TextureTypePanel(TextureButtonsPanel):
303
304     @classmethod
305     def poll(cls, context):
306         tex = context.texture
307         engine = context.engine
308         return tex and ((tex.type == cls.tex_type and not tex.use_nodes) and (engine in cls.COMPAT_ENGINES))
309
310
311 class TEXTURE_PT_clouds(TextureTypePanel, Panel):
312     bl_label = "Clouds"
313     tex_type = 'CLOUDS'
314     COMPAT_ENGINES = {'BLENDER_RENDER'}
315
316     def draw(self, context):
317         layout = self.layout
318
319         tex = context.texture
320
321         layout.row().prop(tex, "cloud_type", expand=True)
322         layout.label(text="Noise:")
323         layout.row().prop(tex, "noise_type", text="Type", expand=True)
324         layout.prop(tex, "noise_basis", text="Basis")
325
326         split = layout.split()
327
328         col = split.column()
329         col.prop(tex, "noise_scale", text="Size")
330         col.prop(tex, "noise_depth", text="Depth")
331
332         split.prop(tex, "nabla", text="Nabla")
333
334
335 class TEXTURE_PT_wood(TextureTypePanel, Panel):
336     bl_label = "Wood"
337     tex_type = 'WOOD'
338     COMPAT_ENGINES = {'BLENDER_RENDER'}
339
340     def draw(self, context):
341         layout = self.layout
342
343         tex = context.texture
344
345         layout.row().prop(tex, "noise_basis_2", expand=True)
346         layout.row().prop(tex, "wood_type", expand=True)
347
348         col = layout.column()
349         col.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'}
350         col.label(text="Noise:")
351         col.row().prop(tex, "noise_type", text="Type", expand=True)
352         layout.prop(tex, "noise_basis", text="Basis")
353
354         split = layout.split()
355         split.active = tex.wood_type in {'RINGNOISE', 'BANDNOISE'}
356
357         col = split.column()
358         col.prop(tex, "noise_scale", text="Size")
359         col.prop(tex, "turbulence")
360
361         split.prop(tex, "nabla")
362
363
364 class TEXTURE_PT_marble(TextureTypePanel, Panel):
365     bl_label = "Marble"
366     tex_type = 'MARBLE'
367     COMPAT_ENGINES = {'BLENDER_RENDER'}
368
369     def draw(self, context):
370         layout = self.layout
371
372         tex = context.texture
373
374         layout.row().prop(tex, "marble_type", expand=True)
375         layout.row().prop(tex, "noise_basis_2", expand=True)
376         layout.label(text="Noise:")
377         layout.row().prop(tex, "noise_type", text="Type", expand=True)
378         layout.prop(tex, "noise_basis", text="Basis")
379
380         split = layout.split()
381
382         col = split.column()
383         col.prop(tex, "noise_scale", text="Size")
384         col.prop(tex, "noise_depth", text="Depth")
385
386         col = split.column()
387         col.prop(tex, "turbulence")
388         col.prop(tex, "nabla")
389
390
391 class TEXTURE_PT_magic(TextureTypePanel, Panel):
392     bl_label = "Magic"
393     tex_type = 'MAGIC'
394     COMPAT_ENGINES = {'BLENDER_RENDER'}
395
396     def draw(self, context):
397         layout = self.layout
398
399         tex = context.texture
400
401         row = layout.row()
402         row.prop(tex, "noise_depth", text="Depth")
403         row.prop(tex, "turbulence")
404
405
406 class TEXTURE_PT_blend(TextureTypePanel, Panel):
407     bl_label = "Blend"
408     tex_type = 'BLEND'
409     COMPAT_ENGINES = {'BLENDER_RENDER'}
410
411     def draw(self, context):
412         layout = self.layout
413
414         tex = context.texture
415
416         layout.prop(tex, "progression")
417
418         sub = layout.row()
419
420         sub.active = (tex.progression in {'LINEAR', 'QUADRATIC', 'EASING', 'RADIAL'})
421         sub.prop(tex, "use_flip_axis", expand=True)
422
423
424 class TEXTURE_PT_stucci(TextureTypePanel, Panel):
425     bl_label = "Stucci"
426     tex_type = 'STUCCI'
427     COMPAT_ENGINES = {'BLENDER_RENDER'}
428
429     def draw(self, context):
430         layout = self.layout
431
432         tex = context.texture
433
434         layout.row().prop(tex, "stucci_type", expand=True)
435         layout.label(text="Noise:")
436         layout.row().prop(tex, "noise_type", text="Type", expand=True)
437         layout.prop(tex, "noise_basis", text="Basis")
438
439         row = layout.row()
440         row.prop(tex, "noise_scale", text="Size")
441         row.prop(tex, "turbulence")
442
443
444 class TEXTURE_PT_image(TextureTypePanel, Panel):
445     bl_label = "Image"
446     tex_type = 'IMAGE'
447     COMPAT_ENGINES = {'BLENDER_RENDER'}
448
449     def draw(self, context):
450         layout = self.layout
451
452         tex = context.texture
453
454         layout.template_image(tex, "image", tex.image_user)
455
456
457 def texture_filter_common(tex, layout):
458     layout.label(text="Filter:")
459     layout.prop(tex, "filter_type", text="")
460     if tex.use_mipmap and tex.filter_type in {'AREA', 'EWA', 'FELINE'}:
461         if tex.filter_type == 'FELINE':
462             layout.prop(tex, "filter_lightprobes", text="Light Probes")
463         else:
464             layout.prop(tex, "filter_eccentricity", text="Eccentricity")
465
466     layout.prop(tex, "filter_size")
467     layout.prop(tex, "use_filter_size_min")
468
469
470 class TEXTURE_PT_image_sampling(TextureTypePanel, Panel):
471     bl_label = "Image Sampling"
472     bl_options = {'DEFAULT_CLOSED'}
473     tex_type = 'IMAGE'
474     COMPAT_ENGINES = {'BLENDER_RENDER'}
475
476     def draw(self, context):
477         layout = self.layout
478
479         idblock = context_tex_datablock(context)
480         tex = context.texture
481         slot = getattr(context, "texture_slot", None)
482
483         split = layout.split()
484
485         col = split.column()
486         col.label(text="Alpha:")
487         row = col.row()
488         row.active = bool(tex.image and tex.image.use_alpha)
489         row.prop(tex, "use_alpha", text="Use")
490         col.prop(tex, "use_calculate_alpha", text="Calculate")
491         col.prop(tex, "invert_alpha", text="Invert")
492         col.separator()
493         col.prop(tex, "use_flip_axis", text="Flip X/Y Axis")
494
495         col = split.column()
496
497         # Only for Material based textures, not for Lamp/World...
498         if slot and isinstance(idblock, Material):
499             col.prop(tex, "use_normal_map")
500             row = col.row()
501             row.active = tex.use_normal_map
502             row.prop(slot, "normal_map_space", text="")
503
504             row = col.row()
505             row.active = not tex.use_normal_map
506             row.prop(tex, "use_derivative_map")
507
508         col.prop(tex, "use_mipmap")
509         row = col.row()
510         row.active = tex.use_mipmap
511         row.prop(tex, "use_mipmap_gauss")
512         col.prop(tex, "use_interpolation")
513
514         texture_filter_common(tex, col)
515
516
517 class TEXTURE_PT_image_mapping(TextureTypePanel, Panel):
518     bl_label = "Image Mapping"
519     bl_options = {'DEFAULT_CLOSED'}
520     tex_type = 'IMAGE'
521     COMPAT_ENGINES = {'BLENDER_RENDER'}
522
523     def draw(self, context):
524         layout = self.layout
525
526         tex = context.texture
527
528         layout.prop(tex, "extension")
529
530         split = layout.split()
531
532         if tex.extension == 'REPEAT':
533             col = split.column(align=True)
534             col.label(text="Repeat:")
535             col.prop(tex, "repeat_x", text="X")
536             col.prop(tex, "repeat_y", text="Y")
537
538             col = split.column(align=True)
539             col.label(text="Mirror:")
540             row = col.row(align=True)
541             row.prop(tex, "use_mirror_x", text="X")
542             row.active = (tex.repeat_x > 1)
543             row = col.row(align=True)
544             row.prop(tex, "use_mirror_y", text="Y")
545             row.active = (tex.repeat_y > 1)
546             layout.separator()
547
548         elif tex.extension == 'CHECKER':
549             col = split.column(align=True)
550             row = col.row(align=True)
551             row.prop(tex, "use_checker_even", text="Even")
552             row.prop(tex, "use_checker_odd", text="Odd")
553
554             col = split.column()
555             col.prop(tex, "checker_distance", text="Distance")
556
557             layout.separator()
558
559         split = layout.split()
560
561         col = split.column(align=True)
562         # col.prop(tex, "crop_rectangle")
563         col.label(text="Crop Minimum:")
564         col.prop(tex, "crop_min_x", text="X")
565         col.prop(tex, "crop_min_y", text="Y")
566
567         col = split.column(align=True)
568         col.label(text="Crop Maximum:")
569         col.prop(tex, "crop_max_x", text="X")
570         col.prop(tex, "crop_max_y", text="Y")
571
572
573 class TEXTURE_PT_envmap(TextureTypePanel, Panel):
574     bl_label = "Environment Map"
575     tex_type = 'ENVIRONMENT_MAP'
576     COMPAT_ENGINES = {'BLENDER_RENDER'}
577
578     def draw(self, context):
579         layout = self.layout
580
581         tex = context.texture
582         env = tex.environment_map
583
584         row = layout.row()
585         row.prop(env, "source", expand=True)
586         row.menu("TEXTURE_MT_envmap_specials", icon='DOWNARROW_HLT', text="")
587
588         if env.source == 'IMAGE_FILE':
589             layout.template_ID(tex, "image", open="image.open")
590             layout.template_image(tex, "image", tex.image_user, compact=True)
591         else:
592             layout.prop(env, "mapping")
593             if env.mapping == 'PLANE':
594                 layout.prop(env, "zoom")
595             layout.prop(env, "viewpoint_object")
596
597             split = layout.split()
598
599             col = split.column()
600             col.prop(env, "layers_ignore")
601             col.prop(env, "resolution")
602             col.prop(env, "depth")
603
604             col = split.column(align=True)
605
606             col.label(text="Clipping:")
607             col.prop(env, "clip_start", text="Start")
608             col.prop(env, "clip_end", text="End")
609
610
611 class TEXTURE_PT_envmap_sampling(TextureTypePanel, Panel):
612     bl_label = "Environment Map Sampling"
613     bl_options = {'DEFAULT_CLOSED'}
614     tex_type = 'ENVIRONMENT_MAP'
615     COMPAT_ENGINES = {'BLENDER_RENDER'}
616
617     def draw(self, context):
618         layout = self.layout
619
620         tex = context.texture
621
622         texture_filter_common(tex, layout)
623
624
625 class TEXTURE_PT_musgrave(TextureTypePanel, Panel):
626     bl_label = "Musgrave"
627     tex_type = 'MUSGRAVE'
628     COMPAT_ENGINES = {'BLENDER_RENDER'}
629
630     def draw(self, context):
631         layout = self.layout
632
633         tex = context.texture
634
635         layout.prop(tex, "musgrave_type")
636
637         split = layout.split()
638
639         col = split.column()
640         col.prop(tex, "dimension_max", text="Dimension")
641         col.prop(tex, "lacunarity")
642         col.prop(tex, "octaves")
643
644         musgrave_type = tex.musgrave_type
645         col = split.column()
646         if musgrave_type in {'HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
647             col.prop(tex, "offset")
648         col.prop(tex, "noise_intensity", text="Intensity")
649         if musgrave_type in {'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'}:
650             col.prop(tex, "gain")
651
652         layout.label(text="Noise:")
653
654         layout.prop(tex, "noise_basis", text="Basis")
655
656         row = layout.row()
657         row.prop(tex, "noise_scale", text="Size")
658         row.prop(tex, "nabla")
659
660
661 class TEXTURE_PT_voronoi(TextureTypePanel, Panel):
662     bl_label = "Voronoi"
663     tex_type = 'VORONOI'
664     COMPAT_ENGINES = {'BLENDER_RENDER'}
665
666     def draw(self, context):
667         layout = self.layout
668
669         tex = context.texture
670
671         split = layout.split()
672
673         col = split.column()
674         col.label(text="Distance Metric:")
675         col.prop(tex, "distance_metric", text="")
676         sub = col.column()
677         sub.active = tex.distance_metric == 'MINKOVSKY'
678         sub.prop(tex, "minkovsky_exponent", text="Exponent")
679         col.label(text="Coloring:")
680         col.prop(tex, "color_mode", text="")
681         col.prop(tex, "noise_intensity", text="Intensity")
682
683         col = split.column()
684         sub = col.column(align=True)
685         sub.label(text="Feature Weights:")
686         sub.prop(tex, "weight_1", text="1", slider=True)
687         sub.prop(tex, "weight_2", text="2", slider=True)
688         sub.prop(tex, "weight_3", text="3", slider=True)
689         sub.prop(tex, "weight_4", text="4", slider=True)
690
691         layout.label(text="Noise:")
692         row = layout.row()
693         row.prop(tex, "noise_scale", text="Size")
694         row.prop(tex, "nabla")
695
696
697 class TEXTURE_PT_distortednoise(TextureTypePanel, Panel):
698     bl_label = "Distorted Noise"
699     tex_type = 'DISTORTED_NOISE'
700     COMPAT_ENGINES = {'BLENDER_RENDER'}
701
702     def draw(self, context):
703         layout = self.layout
704
705         tex = context.texture
706
707         layout.prop(tex, "noise_distortion")
708         layout.prop(tex, "noise_basis", text="Basis")
709
710         split = layout.split()
711
712         col = split.column()
713         col.prop(tex, "distortion", text="Distortion")
714         col.prop(tex, "noise_scale", text="Size")
715
716         split.prop(tex, "nabla")
717
718
719 class TEXTURE_PT_voxeldata(TextureButtonsPanel, Panel):
720     bl_label = "Voxel Data"
721     COMPAT_ENGINES = {'BLENDER_RENDER'}
722
723     @classmethod
724     def poll(cls, context):
725         tex = context.texture
726         engine = context.engine
727         return tex and (tex.type == 'VOXEL_DATA' and (engine in cls.COMPAT_ENGINES))
728
729     def draw(self, context):
730         layout = self.layout
731
732         tex = context.texture
733         vd = tex.voxel_data
734
735         layout.prop(vd, "file_format")
736         if vd.file_format in {'BLENDER_VOXEL', 'RAW_8BIT'}:
737             layout.prop(vd, "filepath")
738         if vd.file_format == 'RAW_8BIT':
739             layout.prop(vd, "resolution")
740         elif vd.file_format == 'SMOKE':
741             layout.prop(vd, "domain_object")
742             layout.prop(vd, "smoke_data_type")
743         elif vd.file_format == 'HAIR':
744             layout.prop(vd, "domain_object")
745             layout.prop(vd, "hair_data_type")
746         elif vd.file_format == 'IMAGE_SEQUENCE':
747             layout.template_ID(tex, "image", open="image.open")
748             layout.template_image(tex, "image", tex.image_user, compact=True)
749             # layout.prop(vd, "frame_duration")
750
751         if vd.file_format in {'BLENDER_VOXEL', 'RAW_8BIT'}:
752             layout.prop(vd, "use_still_frame")
753             row = layout.row()
754             row.active = vd.use_still_frame
755             row.prop(vd, "still_frame")
756
757         layout.prop(vd, "interpolation")
758         layout.prop(vd, "extension")
759         layout.prop(vd, "intensity")
760
761
762 class TEXTURE_PT_pointdensity(TextureButtonsPanel, Panel):
763     bl_label = "Point Density"
764     COMPAT_ENGINES = {'BLENDER_RENDER'}
765
766     @classmethod
767     def poll(cls, context):
768         tex = context.texture
769         engine = context.engine
770         return tex and (tex.type == 'POINT_DENSITY' and (engine in cls.COMPAT_ENGINES))
771
772     def draw(self, context):
773         layout = self.layout
774
775         tex = context.texture
776         pd = tex.point_density
777
778         layout.row().prop(pd, "point_source", expand=True)
779
780         split = layout.split()
781
782         col = split.column()
783         if pd.point_source == 'PARTICLE_SYSTEM':
784             col.label(text="Object:")
785             col.prop(pd, "object", text="")
786
787             sub = col.column()
788             sub.enabled = bool(pd.object)
789             if pd.object:
790                 sub.label(text="System:")
791                 sub.prop_search(pd, "particle_system", pd.object, "particle_systems", text="")
792             sub.label(text="Cache:")
793             sub.prop(pd, "particle_cache_space", text="")
794         else:
795             col.label(text="Object:")
796             col.prop(pd, "object", text="")
797             col.label(text="Cache:")
798             col.prop(pd, "vertex_cache_space", text="")
799
800         col.separator()
801
802         col.label(text="Color Source:")
803         if pd.point_source == 'PARTICLE_SYSTEM':
804             col.prop(pd, "particle_color_source", text="")
805             if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_VELOCITY'}:
806                 col.prop(pd, "speed_scale")
807             if pd.particle_color_source in {'PARTICLE_SPEED', 'PARTICLE_AGE'}:
808                 layout.template_color_ramp(pd, "color_ramp", expand=True)
809         else:
810             col.prop(pd, "vertex_color_source", text="")
811             if pd.vertex_color_source == 'VERTEX_COLOR':
812                 if pd.object and pd.object.data:
813                     col.prop_search(pd, "vertex_attribute_name", pd.object.data, "vertex_colors", text="")
814             if pd.vertex_color_source == 'VERTEX_WEIGHT':
815                 if pd.object:
816                     col.prop_search(pd, "vertex_attribute_name", pd.object, "vertex_groups", text="")
817                 layout.template_color_ramp(pd, "color_ramp", expand=True)
818
819         col = split.column()
820         col.label()
821         col.prop(pd, "radius")
822         col.label(text="Falloff:")
823         col.prop(pd, "falloff", text="")
824         if pd.falloff == 'SOFT':
825             col.prop(pd, "falloff_soft")
826         if pd.falloff == 'PARTICLE_VELOCITY':
827             col.prop(pd, "falloff_speed_scale")
828
829         col.prop(pd, "use_falloff_curve")
830
831         if pd.use_falloff_curve:
832             col = layout.column()
833             col.label(text="Falloff Curve")
834             col.template_curve_mapping(pd, "falloff_curve", brush=False)
835
836
837 class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, Panel):
838     bl_label = "Turbulence"
839     COMPAT_ENGINES = {'BLENDER_RENDER'}
840
841     @classmethod
842     def poll(cls, context):
843         tex = context.texture
844         engine = context.engine
845         return tex and (tex.type == 'POINT_DENSITY' and (engine in cls.COMPAT_ENGINES))
846
847     def draw_header(self, context):
848         pd = context.texture.point_density
849
850         self.layout.prop(pd, "use_turbulence", text="")
851
852     def draw(self, context):
853         layout = self.layout
854
855         tex = context.texture
856         pd = tex.point_density
857         layout.active = pd.use_turbulence
858
859         split = layout.split()
860
861         col = split.column()
862         col.label(text="Influence:")
863         col.prop(pd, "turbulence_influence", text="")
864         col.label(text="Noise Basis:")
865         col.prop(pd, "noise_basis", text="")
866
867         col = split.column()
868         col.label()
869         col.prop(pd, "turbulence_scale")
870         col.prop(pd, "turbulence_depth")
871         col.prop(pd, "turbulence_strength")
872
873
874 class TEXTURE_PT_ocean(TextureTypePanel, Panel):
875     bl_label = "Ocean"
876     tex_type = 'OCEAN'
877     COMPAT_ENGINES = {'BLENDER_RENDER'}
878
879     def draw(self, context):
880         layout = self.layout
881
882         tex = context.texture
883         ot = tex.ocean
884
885         col = layout.column()
886         col.prop(ot, "ocean_object")
887         col.prop(ot, "output")
888
889
890 class TEXTURE_PT_mapping(TextureSlotPanel, Panel):
891     bl_label = "Mapping"
892     COMPAT_ENGINES = {'BLENDER_RENDER'}
893
894     @classmethod
895     def poll(cls, context):
896         idblock = context_tex_datablock(context)
897         if isinstance(idblock, Brush) and not context.sculpt_object:
898             return False
899
900         if not getattr(context, "texture_slot", None):
901             return False
902
903         engine = context.engine
904         return (engine in cls.COMPAT_ENGINES)
905
906     def draw(self, context):
907         layout = self.layout
908
909         idblock = context_tex_datablock(context)
910
911         tex = context.texture_slot
912
913         if not isinstance(idblock, Brush):
914             split = layout.split(percentage=0.3)
915             col = split.column()
916             col.label(text="Coordinates:")
917             col = split.column()
918             col.prop(tex, "texture_coords", text="")
919
920             if tex.texture_coords == 'ORCO':
921                 """
922                 ob = context.object
923                 if ob and ob.type == 'MESH':
924                     split = layout.split(percentage=0.3)
925                     split.label(text="Mesh:")
926                     split.prop(ob.data, "texco_mesh", text="")
927                 """
928             elif tex.texture_coords == 'UV':
929                 split = layout.split(percentage=0.3)
930                 split.label(text="Map:")
931                 ob = context.object
932                 if ob and ob.type == 'MESH':
933                     split.prop_search(tex, "uv_layer", ob.data, "uv_layers", text="")
934                 else:
935                     split.prop(tex, "uv_layer", text="")
936
937             elif tex.texture_coords == 'OBJECT':
938                 split = layout.split(percentage=0.3)
939                 split.label(text="Object:")
940                 split.prop(tex, "object", text="")
941
942             elif tex.texture_coords == 'ALONG_STROKE':
943                 split = layout.split(percentage=0.3)
944                 split.label(text="Use Tips:")
945                 split.prop(tex, "use_tips", text="")
946
947         if isinstance(idblock, Brush):
948             if context.sculpt_object or context.image_paint_object:
949                 brush_texture_settings(layout, idblock, context.sculpt_object)
950         else:
951             if isinstance(idblock, FreestyleLineStyle):
952                 split = layout.split(percentage=0.3)
953                 split.label(text="Projection:")
954                 split.prop(tex, "mapping", text="")
955
956                 split = layout.split(percentage=0.3)
957                 split.separator()
958                 row = split.row()
959                 row.prop(tex, "mapping_x", text="")
960                 row.prop(tex, "mapping_y", text="")
961                 row.prop(tex, "mapping_z", text="")
962
963             elif isinstance(idblock, Material):
964                 split = layout.split(percentage=0.3)
965                 split.label(text="Projection:")
966                 split.prop(tex, "mapping", text="")
967
968                 split = layout.split()
969
970                 col = split.column()
971                 if tex.texture_coords in {'ORCO', 'UV'}:
972                     col.prop(tex, "use_from_dupli")
973                     if (idblock.type == 'VOLUME' and tex.texture_coords == 'ORCO'):
974                         col.prop(tex, "use_map_to_bounds")
975                 elif tex.texture_coords == 'OBJECT':
976                     col.prop(tex, "use_from_original")
977                     if (idblock.type == 'VOLUME'):
978                         col.prop(tex, "use_map_to_bounds")
979                 else:
980                     col.label()
981
982                 col = split.column()
983                 row = col.row()
984                 row.prop(tex, "mapping_x", text="")
985                 row.prop(tex, "mapping_y", text="")
986                 row.prop(tex, "mapping_z", text="")
987
988             row = layout.row()
989             row.column().prop(tex, "offset")
990             row.column().prop(tex, "scale")
991
992
993 class TEXTURE_PT_influence(TextureSlotPanel, Panel):
994     bl_label = "Influence"
995     COMPAT_ENGINES = {'BLENDER_RENDER'}
996
997     @classmethod
998     def poll(cls, context):
999         idblock = context_tex_datablock(context)
1000         if isinstance(idblock, Brush):
1001             return False
1002
1003         if not getattr(context, "texture_slot", None):
1004             return False
1005
1006         engine = context.engine
1007         return (engine in cls.COMPAT_ENGINES)
1008
1009     def draw(self, context):
1010
1011         layout = self.layout
1012
1013         idblock = context_tex_datablock(context)
1014
1015         tex = context.texture_slot
1016
1017         def factor_but(layout, toggle, factor, name):
1018             row = layout.row(align=True)
1019             row.prop(tex, toggle, text="")
1020             sub = row.row(align=True)
1021             sub.active = getattr(tex, toggle)
1022             sub.prop(tex, factor, text=name, slider=True)
1023             return sub  # XXX, temp. use_map_normal needs to override.
1024
1025         if isinstance(idblock, Material):
1026             if idblock.type in {'SURFACE', 'WIRE'}:
1027                 split = layout.split()
1028
1029                 col = split.column()
1030                 col.label(text="Diffuse:")
1031                 factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity")
1032                 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1033                 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1034                 factor_but(col, "use_map_translucency", "translucency_factor", "Translucency")
1035
1036                 col.label(text="Specular:")
1037                 factor_but(col, "use_map_specular", "specular_factor", "Intensity")
1038                 factor_but(col, "use_map_color_spec", "specular_color_factor", "Color")
1039                 factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
1040
1041                 col = split.column()
1042                 col.label(text="Shading:")
1043                 factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
1044                 factor_but(col, "use_map_emit", "emit_factor", "Emit")
1045                 factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
1046                 factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
1047
1048                 col.label(text="Geometry:")
1049                 # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
1050                 sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal")
1051                 sub_tmp.active = (tex.use_map_normal or tex.use_map_displacement)
1052                 # END XXX
1053
1054                 factor_but(col, "use_map_warp", "warp_factor", "Warp")
1055                 factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
1056
1057                 #~ sub = col.column()
1058                 #~ sub.active = tex.use_map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror
1059                 #~ sub.prop(tex, "default_value", text="Amount", slider=True)
1060             elif idblock.type == 'HALO':
1061                 layout.label(text="Halo:")
1062
1063                 split = layout.split()
1064
1065                 col = split.column()
1066                 factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1067                 factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1068
1069                 col = split.column()
1070                 factor_but(col, "use_map_raymir", "raymir_factor", "Size")
1071                 factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
1072                 factor_but(col, "use_map_translucency", "translucency_factor", "Add")
1073             elif idblock.type == 'VOLUME':
1074                 layout.label(text="Volume:")
1075
1076                 split = layout.split()
1077
1078                 col = split.column()
1079                 factor_but(col, "use_map_density", "density_factor", "Density")
1080                 factor_but(col, "use_map_emission", "emission_factor", "Emission")
1081                 factor_but(col, "use_map_scatter", "scattering_factor", "Scattering")
1082                 factor_but(col, "use_map_reflect", "reflection_factor", "Reflection")
1083
1084                 col = split.column()
1085                 col.label(text=" ")
1086                 factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color")
1087                 factor_but(col, "use_map_color_transmission", "transmission_color_factor", "Transmission Color")
1088                 factor_but(col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color")
1089
1090                 layout.label(text="Geometry:")
1091
1092                 split = layout.split()
1093
1094                 col = split.column()
1095                 factor_but(col, "use_map_warp", "warp_factor", "Warp")
1096
1097                 col = split.column()
1098                 factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
1099
1100         elif isinstance(idblock, Lamp):
1101             split = layout.split()
1102
1103             col = split.column()
1104             factor_but(col, "use_map_color", "color_factor", "Color")
1105
1106             col = split.column()
1107             factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
1108
1109         elif isinstance(idblock, World):
1110             split = layout.split()
1111
1112             col = split.column()
1113             factor_but(col, "use_map_blend", "blend_factor", "Blend")
1114             factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
1115
1116             col = split.column()
1117             factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
1118             factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
1119         elif isinstance(idblock, ParticleSettings):
1120             split = layout.split()
1121
1122             col = split.column()
1123             col.label(text="General:")
1124             factor_but(col, "use_map_time", "time_factor", "Time")
1125             factor_but(col, "use_map_life", "life_factor", "Lifetime")
1126             factor_but(col, "use_map_density", "density_factor", "Density")
1127             factor_but(col, "use_map_size", "size_factor", "Size")
1128
1129             col = split.column()
1130             col.label(text="Physics:")
1131             factor_but(col, "use_map_velocity", "velocity_factor", "Velocity")
1132             factor_but(col, "use_map_damp", "damp_factor", "Damp")
1133             factor_but(col, "use_map_gravity", "gravity_factor", "Gravity")
1134             factor_but(col, "use_map_field", "field_factor", "Force Fields")
1135
1136             layout.label(text="Hair:")
1137
1138             split = layout.split()
1139
1140             col = split.column()
1141             factor_but(col, "use_map_length", "length_factor", "Length")
1142             factor_but(col, "use_map_clump", "clump_factor", "Clump")
1143             factor_but(col, "use_map_twist", "twist_factor", "Twist")
1144
1145             col = split.column()
1146             factor_but(col, "use_map_kink_amp", "kink_amp_factor", "Kink Amplitude")
1147             factor_but(col, "use_map_kink_freq", "kink_freq_factor", "Kink Frequency")
1148             factor_but(col, "use_map_rough", "rough_factor", "Rough")
1149
1150         elif isinstance(idblock, FreestyleLineStyle):
1151             split = layout.split()
1152
1153             col = split.column()
1154             factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
1155             col = split.column()
1156             factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
1157
1158         layout.separator()
1159
1160         if not isinstance(idblock, ParticleSettings):
1161             split = layout.split()
1162
1163             col = split.column()
1164             col.prop(tex, "blend_type", text="Blend")
1165             col.prop(tex, "use_rgb_to_intensity")
1166             # color is used on gray-scale textures even when use_rgb_to_intensity is disabled.
1167             col.prop(tex, "color", text="")
1168
1169             col = split.column()
1170             col.prop(tex, "invert", text="Negative")
1171             col.prop(tex, "use_stencil")
1172
1173         if isinstance(idblock, Material) or isinstance(idblock, World):
1174             col.prop(tex, "default_value", text="DVar", slider=True)
1175
1176         if isinstance(idblock, Material):
1177             layout.label(text="Bump Mapping:")
1178
1179             # only show bump settings if activated but not for normal-map images
1180             row = layout.row()
1181
1182             sub = row.row()
1183             sub.active = (
1184                 (tex.use_map_normal or tex.use_map_warp) and
1185                 not (tex.texture.type == 'IMAGE' and
1186                      (tex.texture.use_normal_map or tex.texture.use_derivative_map))
1187             )
1188             sub.prop(tex, "bump_method", text="Method")
1189
1190             # the space setting is supported for: derivative-maps + bump-maps
1191             # (DEFAULT,BEST_QUALITY), not for normal-maps
1192             sub = row.row()
1193             sub.active = (
1194                 (tex.use_map_normal or tex.use_map_warp) and
1195                 not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) and
1196                 ((tex.bump_method in {'BUMP_LOW_QUALITY', 'BUMP_MEDIUM_QUALITY', 'BUMP_BEST_QUALITY'}) or
1197                  (tex.texture.type == 'IMAGE' and tex.texture.use_derivative_map))
1198             )
1199             sub.prop(tex, "bump_objectspace", text="Space")
1200
1201
1202 class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, Panel):
1203     COMPAT_ENGINES = {'BLENDER_RENDER'}
1204     _context_path = "texture"
1205     _property_type = Texture
1206
1207
1208 classes = (
1209     TEXTURE_MT_specials,
1210     TEXTURE_MT_envmap_specials,
1211     TEXTURE_UL_texslots,
1212     TEXTURE_PT_context_texture,
1213     TEXTURE_PT_preview,
1214     TEXTURE_PT_colors,
1215     TEXTURE_PT_clouds,
1216     TEXTURE_PT_wood,
1217     TEXTURE_PT_marble,
1218     TEXTURE_PT_magic,
1219     TEXTURE_PT_blend,
1220     TEXTURE_PT_stucci,
1221     TEXTURE_PT_image,
1222     TEXTURE_PT_image_sampling,
1223     TEXTURE_PT_image_mapping,
1224     TEXTURE_PT_envmap,
1225     TEXTURE_PT_envmap_sampling,
1226     TEXTURE_PT_musgrave,
1227     TEXTURE_PT_voronoi,
1228     TEXTURE_PT_distortednoise,
1229     TEXTURE_PT_voxeldata,
1230     TEXTURE_PT_pointdensity,
1231     TEXTURE_PT_pointdensity_turbulence,
1232     TEXTURE_PT_ocean,
1233     TEXTURE_PT_mapping,
1234     TEXTURE_PT_influence,
1235     TEXTURE_PT_custom_props,
1236 )
1237
1238 if __name__ == "__main__":  # only for live edit.
1239     from bpy.utils import register_class
1240     for cls in classes:
1241         register_class(cls)