2 "name": "Texture Paint Layer Manager",
3 "author": "Michael Wiliamson",
6 "location": "Texture Paint > Properties > Texture Paint Layers Panels",
7 "description": "Adds a layer manager for image based texture slots in paint and quick add layer tools",
9 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
10 "Scripts/3D_interaction/Texture_paint_layers",
16 from bpy
.props
import*
18 from bpy_extras
.io_utils
import ImportHelper
21 #-------------------------------------------
23 def load_a_brush(context
, filepath
):
24 if os
.path
.isdir(filepath
):
30 fn
= bpy
.path
.display_name_from_filepath(filepath
)
31 #create image and load...
32 img
= bpy
.data
.images
.load(filepath
)
33 img
.use_fake_user
=True
36 tex
= bpy
.data
.textures
.new(name
=fn
, type='IMAGE')
37 tex
.use_fake_user
=True
38 #tex.use_calculate_alpha = True
40 #link the img to the texture
44 print(f
,'is not image?')
51 class load_single_brush(bpy
.types
.Operator
, ImportHelper
):
52 """Load an image as a brush texture"""
53 bl_idname
= "texture.load_single_brush"
54 bl_label
= "Load Image as Brush"
58 def poll(cls
, context
):
59 return context
.active_object
!= None
61 def execute(self
, context
):
62 return load_a_brush(context
, self
.filepath
)
64 #-------------------------------------------
66 def loadbrushes(context
, filepath
):
67 if os
.path
.isdir(filepath
):
71 #is a file, find parent directory
72 li
= filepath
.split(os
.sep
)
73 directory
= filepath
.rstrip(li
[-1])
76 files
= os
.listdir(directory
)
80 #create image and load...
81 img
= bpy
.data
.images
.load(filepath
= directory
+os
.sep
+ f
)
82 img
.use_fake_user
=True
85 tex
= bpy
.data
.textures
.new(name
=fn
, type='IMAGE')
86 tex
.use_fake_user
=True
87 #tex.use_calculate_alpha = True
89 #link the img to the texture
93 print(f
,'is not image?')
100 class ImportBrushes(bpy
.types
.Operator
, ImportHelper
):
101 """Load a directory of images as brush textures"""
102 bl_idname
= "texture.load_brushes"
103 bl_label
= "Load brushes directory"
107 def poll(cls
, context
):
108 return context
.active_object
!= None
110 def execute(self
, context
):
111 return loadbrushes(context
, self
.filepath
)
113 #-------------------------------------------------------------------
115 class OBJECT_PT_LoadBrushes(bpy
.types
.Panel
):
116 bl_label
= "Load Brush images"
117 bl_space_type
= "VIEW_3D"
118 bl_region_type
= "TOOLS"
119 #bl_context = "texturepaint"
122 def poll(cls
, context
):
123 return (context
.sculpt_object
or context
.image_paint_object
)
125 def draw(self
, context
):
128 layout
.operator('texture.load_brushes')
129 layout
.operator('texture.load_single_brush')
132 #======================================================================
138 class OBJECT_PT_Texture_paint_layers(bpy
.types
.Panel
):
139 bl_label
= "Texture Paint Layers"
140 bl_space_type
= "VIEW_3D"
141 bl_region_type
= "UI"
142 #bl_context = "texturepaint"
145 def poll(cls
, context
):
146 return (context
.image_paint_object
)
148 def draw(self
, context
):
151 ob
= bpy
.context
.image_paint_object
153 mat
= ob
.active_material
156 row
.label(' Add a Material first!', icon
= 'ERROR')
159 row
.template_list("UI_UL_list", "texture_paint_layers", ob
, "material_slots", ob
,
160 "active_material_index", rows
=2 )
162 #list Paintable textures
163 #TODO add filter for channel type
165 for t
in mat
.texture_slots
:
168 if t
.texture
.type =='IMAGE':
169 row
= layout
.row(align
= True)
170 if t
.texture
== mat
.active_texture
:
174 row
.operator('object.set_active_paint_layer',
175 text
= "", icon
= ai
).tex_index
=i
176 row
.prop(t
.texture
,'name', text
= "")
181 ic
= 'RESTRICT_VIEW_OFF'
183 ic
= 'RESTRICT_VIEW_ON'
184 row
.prop(t
,'use', text
= "",icon
= ic
)
193 ts
= mat
.texture_slots
[mat
.active_texture_index
]
201 col
= layout
.column(align
=True)
202 col
.label('Active Properties:', icon
= 'BRUSH_DATA')
204 #use if rather than elif... can be mapped to multiple things
205 if ts
.use_map_diffuse
:
206 col
.prop(ts
,'diffuse_factor', slider
= True)
207 if ts
.use_map_color_diffuse
:
208 col
.prop(ts
,'diffuse_color_factor', slider
= True)
210 col
.prop(ts
,'alpha_factor', slider
= True)
211 if ts
.use_map_translucency
:
212 col
.prop(ts
,'translucency_factor', slider
= True)
213 if ts
.use_map_specular
:
214 col
.prop(ts
,'specular_factor', slider
= True)
215 if ts
.use_map_color_spec
:
216 col
.prop(ts
,'specular_color_factor', slider
= True)
217 if ts
.use_map_hardness
:
218 col
.prop(ts
,'hardness_factor', slider
= True)
220 if ts
.use_map_normal
:
221 col
.prop(ts
,'normal_factor', slider
= True)
223 col
.prop(ts
,'warp_factor', slider
= True)
224 if ts
.use_map_displacement
:
225 col
.prop(ts
,'displacement_factor', slider
= True)
227 if ts
.use_map_ambient
:
228 col
.prop(ts
,'ambient_factor', slider
= True)
230 col
.prop(ts
,'emit_factor', slider
= True)
231 if ts
.use_map_mirror
:
232 col
.prop(ts
,'mirror_factor', slider
= True)
233 if ts
.use_map_raymir
:
234 col
.prop(ts
,'raymir_factor', slider
= True)
237 col
.prop(ts
,'blend_type',text
='')
241 row
.label('No paint layers in material', icon
= 'ERROR')
247 # row.label('WIP: Use the X to delete!:')
249 # row.template_ID(mat, "active_texture", new="texture.new")
252 class OBJECT_PT_Texture_paint_add(bpy
.types
.Panel
):
253 bl_label
= "Add Paint Layers"
254 bl_space_type
= "VIEW_3D"
255 bl_region_type
= "UI"
256 #bl_context = "texturepaint"
259 def poll(cls
, context
):
260 return (context
.image_paint_object
)
262 def draw(self
, context
):
265 ob
= bpy
.context
.image_paint_object
267 mat
= ob
.active_material
270 col
= layout
.column(align
=True)
272 col
.operator('object.add_paint_layer',
273 text
= "Add Color").ttype
= 'COLOR'
274 col
.operator('object.add_paint_layer',
275 text
= "Add Bump").ttype
= 'NORMAL'
277 col
= layout
.column(align
=True)
278 col
.operator('object.add_paint_layer',
279 text
= "Add Specular").ttype
= 'SPECULAR'
280 col
.operator('object.add_paint_layer',
281 text
= "Add Spec Col").ttype
= 'SPEC_COL'
282 col
.operator('object.add_paint_layer',
283 text
= "Add Hardness").ttype
= 'HARDNESS'
285 col
= layout
.column(align
=True)
286 col
.operator('object.add_paint_layer',
287 text
= "Add Alpha").ttype
= 'ALPHA'
288 col
.operator('object.add_paint_layer',
289 text
= "Add Translucency").ttype
= 'TRANSLUCENCY'
291 # col = layout.column(align =True)
292 # col.operator('object.add_paint_layer',
293 # text = "Add Mirror").ttype = 'MIRROR'
294 # col.operator('object.add_paint_layer',
295 # text = "Add Ray Mirror").ttype = 'RAY_MIRROR'
297 col
= layout
.column(align
=True)
298 col
.operator('object.add_paint_layer',
299 text
= "Add Emit").ttype
= 'EMIT'
300 col
.operator('object.add_paint_layer',
301 text
= "Add Diffuse").ttype
= 'DIFFUSE'
302 col
.operator('object.add_paint_layer',
303 text
= "Add Ambient").ttype
= 'AMBIENT'
306 layout
.label(' Add a Material first!', icon
= 'ERROR')
310 def main(context
,tn
):
311 #tn is the index of the texture in the active material
312 ob
= context
.active_object
314 mat
= ob
.active_material
315 mat
.active_texture_index
= tn
316 ts
= mat
.texture_slots
[tn
]
318 #make sure it's visible
322 if not me
.uv_textures
:
323 bpy
.ops
.mesh
.uv_texture_add()
325 # texture Slot uses UVs?
326 if ts
.texture_coords
== 'UV':
328 uvtex
= me
.uv_textures
[ts
.uv_layer
]
331 uvtex
= me
.uv_textures
.active
332 me
.uv_textures
.active
= uvtex
334 ts
.texture_coords
='UV'
335 uvtex
= me
.uv_textures
.active
338 uvtex
= uvtex
.data
.values()
341 #get image from texture slot
342 img
= ts
.texture
.image
345 m_id
= ob
.active_material_index
348 for f
in me
.polygons
:
349 if f
.material_index
== m_id
:
350 uvtex
[f
.index
].image
= img
355 for f
in me
.polygons
:
356 if f
.material_index
== m_id
:
357 uvtex
[f
.index
].image
= None
367 class set_active_paint_layer(bpy
.types
.Operator
):
369 bl_idname
= "object.set_active_paint_layer"
370 bl_label
= "set_active_paint_layer"
371 tex_index
= IntProperty(name
= 'tex_index',
372 description
= "", default
= 0)
375 def poll(cls
, context
):
376 return context
.active_object
!= None
378 def execute(self
, context
):
385 def add_image_kludge(iname
= 'grey', iwidth
= 256, iheight
= 256,
386 icolor
= (0.5,0.5,0.5,1.0), nfloat
= False):
387 #evil kludge to get index of new image created using bpy.ops
388 #store current images
390 for i
in bpy
.data
.images
:
396 bpy
.ops
.image
.new(name
=iname
,width
=iwidth
,height
=iheight
,
397 color
= icolor
, float = nfloat
)
399 #find its creation index
401 for i
in bpy
.data
.images
:
403 return(bpy
.data
.images
[it
])
408 def add_paint(context
, size
=2048, typ
= 'NORMAL'):
410 ob
= bpy
.context
.object
411 mat
= ob
.active_material
412 ts
= mat
.texture_slots
.add()
416 color
=(0.5,0.5,0.5,1.0)
421 color
= (1.0,1.0,1.0,0.0)
425 color
= (1.0,1.0,1.0,0.0)
427 color
=(0.0,0.0,0.0,1.0)
428 iname
= typ
.capitalize()
430 # bn = bpy.context.blend_data.filepath.split(bpy.utils._os.sep)[-1]
431 # bn = bn.replace('.blend', '')
434 iname
= bn
+'_' + iname
436 tex
= bpy
.data
.textures
.new(name
= iname
, type = 'IMAGE')
438 img
= add_image_kludge(iname
= typ
,
439 iwidth
= size
,iheight
= size
, icolor
= color
, nfloat
= ifloat
)
443 ts
.use_map_color_diffuse
=True
446 elif typ
== 'NORMAL':
447 ts
.use_map_normal
= True
448 ts
.use_map_color_diffuse
=False
449 ts
.normal_factor
= -1
450 ts
.bump_method
='BUMP_MEDIUM_QUALITY'
451 ts
.bump_objectspace
='BUMP_OBJECTSPACE'
453 elif typ
== 'SPECULAR':
454 ts
.use_map_specular
= True
455 ts
.use_map_color_diffuse
=False
456 ts
.use_rgb_to_intensity
= True
457 #ts.blend_type = 'MULTIPLY'
460 ts
.use_map_emit
= True
461 ts
.use_map_color_diffuse
=False
462 ts
.use_rgb_to_intensity
= True
465 mat
.use_transparency
= True
466 ts
.use_map_alpha
= True
467 ts
.use_map_color_diffuse
=False
468 ts
.use_rgb_to_intensity
= True
469 ts
.blend_type
= 'MULTIPLY'
471 elif typ
== 'SPEC_COL':
472 ts
.use_map_color_spec
= True
473 ts
.use_map_color_diffuse
=False
474 ts
.use_rgb_to_intensity
= True
476 elif typ
== 'HARDNESS':
477 ts
.use_map_hardness
= True
478 ts
.use_map_color_diffuse
=False
479 ts
.use_rgb_to_intensity
= True
481 elif typ
== 'DIFFUSE':
482 ts
.use_map_diffuse
= True
483 ts
.use_map_color_diffuse
=False
484 ts
.use_rgb_to_intensity
= True
486 elif typ
== 'TRANSLUCENCY':
487 ts
.use_map_translucency
= True
488 ts
.use_map_color_diffuse
=False
489 ts
.use_rgb_to_intensity
= True
491 elif typ
== 'AMBIENT':
492 ts
.use_map_ambient
= True
493 ts
.use_map_color_diffuse
=False
494 ts
.use_rgb_to_intensity
= True
496 elif typ
== 'MIRROR':
497 ts
.use_map_mirror
= True
498 ts
.use_map_color_diffuse
=False
499 ts
.use_rgb_to_intensity
= True
501 elif typ
== 'RAY_MIRROR':
502 mat
.raytrace_mirror
.use
= True
503 ts
.use_map_ray_mirror
= True
504 ts
.use_map_color_diffuse
=False
505 ts
.use_rgb_to_intensity
= True
507 #set new texture slot to active
510 for t
in mat
.texture_slots
:
517 mat
.active_texture_index
= ts_index
519 #set the texfaces using this material.
520 main(context
,ts_index
)
526 class add_paint_layer(bpy
.types
.Operator
):
528 bl_idname
= "object.add_paint_layer"
529 bl_label
= "Add Paint Layer"
530 ttype
= StringProperty(name
='ttype',default
='NORMAL')
533 def poll(cls
, context
):
534 return context
.active_object
!= None
536 def execute(self
, context
):
538 add_paint(context
,typ
= ttype
)
544 #----------------------------------------------
545 def save_painted(ts
):
546 #generated images don't have a path
547 #so don't get saved with "save_dirty"
548 #ts is a texture slot object.
550 sep
= bpy
.utils
._os
.sep
552 if ts
.texture
.type =='IMAGE':
554 if i
.source
=='GENERATED':
557 if i
.file_format
=='PNG':
559 elif i
.file_format
=='TARGA':
562 bpy
.context
.scene
.render
.image_settings
.color_mode
= 'RGBA'
563 fp
= bpy
.path
.abspath('//textures' + sep
+ name
)
567 if bpy
.context
.user_preferences
.filepaths
.use_relative_paths
:
568 # can't always find the relative path (between drive letters on windows)
570 i
.filepath
= bpy
.path
.relpath(fp
)
577 print("something wrong with", fp
)
578 #THAT'S THE GENERATED FILES saved, pathed and reloaded
579 #now save other painted textures
580 bpy
.ops
.image
.save_dirty()
584 def save_active_paint():
585 #for materials in current object
586 ob
= bpy
.context
.object
587 for m
in ob
.material_slots
:
588 for ts
in m
.material
.texture_slots
:
592 def save_all_paint():
594 for m
in bpy
.data
.materials
:
595 for ts
in m
.texture_slots
:
600 class save_all_generated(bpy
.types
.Operator
):
601 """Saves painted layers to disc"""
602 bl_idname
= "paint.save_all_generated"
604 bl_label
= "SAVE PAINT LAYERS"
608 def poll(cls
, context
):
609 return context
.active_object
!= None
611 def execute(self
, context
):
612 return save_active_paint()
617 #-----------------------------------
618 class OBJECT_PT_SavePainted(bpy
.types
.Panel
):
619 bl_label
= "Save All Painted"
620 bl_space_type
= "VIEW_3D"
621 bl_region_type
= "UI"
622 #bl_context = "texturepaint"
625 def poll(cls
, context
):
626 return (context
.image_paint_object
)
628 def draw(self
, context
):
629 self
.layout
.operator('paint.save_all_generated')
632 bpy
.utils
.register_module(__name__
)
635 bpy
.utils
.unregister_module(__name__
)
637 if __name__
== "__main__":