#!BPY
"""
Name: 'Assign Materials to Faces'
Blender: 248
Group: 'Materials'
Tooltip: 'a script to assign a material directly to selected faces.'
"""

# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2009 Michael Williamson
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

__author__ = 'Michael Williamson'
__url__ = ('http://wiki.blender.org/index.php/Extensions:Py/Scripts/Manual/Materials/Assign_Materials')
__version__ = '1'

__bpydoc__ = """\
(run from the "edit mode": mesh/scripts/Assign Materials menu

This offers a popup list with all the materials in the blend file

 (and a "new" slot to create a new material)... 
 
 click "OK" and your face selection will now use this material! (it's that simple)
 """
 
from Blender import Scene, Mesh, Window, sys, Draw, Material
import BPyMessages
import bpy


def cleanMatSlots():
	
	scn = bpy.data.scenes.active
	for ob in scn.objects.context:
		if not ob.lib and ob.type == 'Mesh':	# object isn't from a library and is a mesh
	
		
			#get number of materials on mesh
			
			me = ob.getData(mesh=1) 
			mats = me.materials 
			
			#check the faces on the mesh to build a list of used materials
			usedMatIndex =[]		#we'll store used materials indices here
			faceMats =[]			#a list of material names corrosponding to face names
				
			for f in me.faces:
				#get the material index for this face...
				faceindex = f.mat
				
				#indices will be lost: Store face mat use by name
				currentfacemat = mats[faceindex].name
				faceMats.append(currentfacemat)
				
				
				#check if index is already listed as used or not
				found = 0
				for m in usedMatIndex:
					if m == faceindex:
						found = 1
						#break
					
				if found == 0:
					#add this index to the list
					
					usedMatIndex.append(faceindex)
						 
			#re-assign the used mats to the mesh and leave out the unused
			ml = []
			mnames = []
			for u in usedMatIndex:
				ml.append( mats[u] )
				#we'll need a list of names to get the face indices...
				mnames.append(mats[u].name)
				
			me.materials = ml
			me.update() 
			
			#restore face indices:
			i = 0
			for f in me.faces:
				matindex = mnames.index(faceMats[i])
				f.mat = matindex
				i += 1
			

	return 1

def getAllMaterials():
	matlist =[]
	for mat in bpy.data.materials:  
		print mat.name
		matlist.append(mat.name)
	return matlist


def ui():
	#create a menu for the user to pick materials from
	
	#get the existing materials
	matlist = getAllMaterials()
	
	Puplist = "Assign Material:%t"
	for mat in matlist:
		Puplist+= "|"+ mat 
	
	#add an "add new" option at the end of the list
	Puplist += "|New"
	
	
	
	#Ok, make the menu
	chan = Draw.PupMenu(Puplist)

	
	if chan != -1:			#something was chosen process it
		try:
			material = matlist[chan-1]		
			print"chosen Material  is", material

			return material
		except:
			#the user has picked "New" so post a text entry to enter a name

			
			#create the new material
			matname = str(createNewMaterial_ui())
			

			mat = Material.New(matname)
	
			#blender could rename if not unique so get the unique blender name
			material = mat.name
			print"chosen NEW Material  is", material   
			return material
def createNewMaterial_ui():
	text = Draw.Create("NewMaterial" )

	block = []
   
	block.append(("Name: ", text, 0, 300, "the name of the material that will be created"))


	retval = Draw.PupBlock("Create New Material", block)

 	name = str(text)[1:-1]
	return name	
		
			
def main():
	
	sce = bpy.data.scenes.active
	ob_act = sce.objects.active
	me = ob_act.getData(mesh=1) 
			 
	if not ob_act or ob_act.type != 'Mesh':
		BPyMessages.Error_NoMeshActive()
		return 
	
	# in editmode?
	is_editmode = Window.EditMode()
	if is_editmode: Window.EditMode(0)
	
	Window.WaitCursor(1)
	me = ob_act.getData(mesh=1) # old NMesh api is default
	t = sys.time()
	

	
	#post ui and get a material name.
	doit = str(ui())
	print "doit", doit
	
	#check if material is on mesh already 
	materials = me.materials
	found = 0
	
	for m in materials:
		if m.name == doit:
			found = 1
	
		
	mat = Material.Get(doit)	
	#attach if it isn't on there
	if found == 0:
		materials.append(mat)
		me.materials = materials
		me.update()
		
	
	index = 0
	#get index for this material
	index  = materials.index(mat)
	print "index", index
	
	#assign to selected faces
	for f in me.faces:
		if is_editmode == True:
			if f.sel:
				f.mat = index
		else:
			f.mat = index
		
	#clean up un-used materials
	
	cleanMatSlots()
	
	
	# Restore editmode if it was enabled
	if is_editmode: Window.EditMode(1)
	
	# Timing the script is a good way to be aware on any speed hits when scripting
	print 'Script finished in %.2f seconds' % (sys.time()-t)
	Window.WaitCursor(0)
	


	
# This lets you can import the script without running it
if __name__ == '__main__':
	main()
9345
