#!BPY

#""" 
#Name: 'TEXFACE Utilities'
#Blender: 248
#Group: 'UV'
#Tooltip: 'convert TEXFACE to materials and back and more'
#"""

# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2008 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://www.cowtoolsmedia.co.uk/')
__version__ = '1'
__bpydoc__ = """
TEXFACE images are quick to assign
This script converts them to materials so that they can be refined.

To use simply select the objects that you want converted, run this script and choose 
you option

texface-->material adds materials to the mesh with the image set to the first tex channel

material-->texface takes the images assigned in the first texture channel of the materials and 
assigns them to the UV faces (so they are visible in the gl viewport and UV editor)

Unlink materials removes the links for all materials on the mesh

set active UV layer makes the chosen set of UVs the active one for all meshes in the selection.
The list is from all objects, if the chosen UV layer is not present on some of the meshes in the 
selection then it is created and activated.
"new" will allow the user to create a new set of UVS for all the meshes in the selection.

"""




import bpy
import Blender
from Blender import *
from bpy import*


		
#-------------------------------------------------


def matToMeshIndex(me, mat):				# string, string
	
	#checks mesh "me" to see if material "mat" is attached. if not attached, then add it
	#returns which index the material is attached to.
	
	nme=NMesh.GetRaw(me) 
	#search through mesh materials
	materials=nme.materials

	index=-1
	i=0
	for m in materials:					
			if m.name == mat:
					print "material is attached to mesh"
					index=i
			i+=1
	#check that the material was found	
	if index<0 and i<15: 
			#the material wasn't found and there's still space for more materials on this mesh
			print "material not attached to mesh"
			print "Adding it now"
			mesh = Mesh.Get(me)
			material = Material.Get(mat)
			mesh.materials += [material]
			index=i
			
	if i >= 15:
			print"Warning: too many Materials: 16 maximum per mesh!"
	print "index =", index
	print
	return index
		
		
	
		
				
#-------------------------------------------------
def stripExtension(myString):
		lastFour = myString [-4:] 
		lastFour = lastFour.lower()	
		if lastFour == ".jpg" or lastFour == ".png" or lastFour == ".tga" or lastFour == ".exr":
				myString = myString [:-4] 

		if len(myString) > 20:
				myString	= myString[:20]
		return myString
	
	
#-------------------------------------------------
def matFromIndex(meshname, index):
		#get the material object from a mesh and index
		
		nme=NMesh.GetRaw(meshname) 
		#search through mesh materials
		materials=nme.materials
		if materials == []:
			print "No material on this index"
			mat = []
			return mat
		else:
			mat = materials[index]
			return mat
	
#-------------------------------------------------
def TEXFACEToMat():  
		#converts texface images from active uv slot to materials 
		#acts on all visible selected objects.
		
		editmode = Window.EditMode() 				# are we in editmode?
		if editmode:
				Window.EditMode(0) 							#leave edit mode before getting mesh
				
				
		scn = 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
						me = ob.getData(mesh=1)	
						
						print "---------------------------------------------------"
						print " Processing Object",me.name
						print "---------------------------------------------------"
						
						#build a list of images
						imglist =[]			#we'll store all the TEXFACE images used here
						matindex =[]		#we'll store materials indices here
						for f in me.faces:
								TEXFACE = 1
								try:
										img = f.image								
										imName = img.name	
								except:
										#the face has no TEXFACE image assigned
										print " no image on face"
										TEXFACE = 0
								
								if TEXFACE == 1:	
										#Face has image: 
										found = 0
										i =0
										for im in imglist:
											if imName == im:
												#this image has been processed already
												found = 1
												#set the mesh index to our material
												f.mat = matindex[i]
												continue
											i += 1	
																								
										if found ==0:
											# image is not on the list yet.
											print "adding", imName, "to image list"
											imglist.append(imName)
												
											#check for material and add material to the list
											matname = me.name[:10] + "_" + imName							
											matname = stripExtension(matname)	
					
											try:												
													mat = Material.Get(matname)
													print "Found material ",mat.name
											except:
													#the material does not exist- lets create it
													mat = Material.New(matname)	
													print "created material", mat.name
														
											#check that our image is attached to the material
											imagetoTex(img.name, mat.name, 0)
											setUVname(mat.name, me.activeUVLayer, 0)

															
											#now we have a material with the correct name convention
																	
											#lets see if its attached to the mesh and at what index		
											index = matToMeshIndex(me.name, mat.name)
											
											#set the mesh index to our material
											f.mat = index
											
											#store the index for other faces with this image
											matindex.append(index)


		if editmode: 
				Window.EditMode(1)			#restore editmode to be nice.

			
#-------------------------------------------------
def matToTEXFACE(): 
		editmode = Window.EditMode() 				# are we in editmode?
		if editmode:
				Window.EditMode(0) 							#leave edit mode before getting mesh
				
				
		#for each material in a mesh finds the first  texture channel image and assigns it as TEXFACE
		#acts on all visible selected objects.
		#could be extended to take multiple uvs into account
		scn = 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
						me = ob.getData(mesh=1)	
						
						print "---------------------------------------------------"
						print " Processing Object",me.name
						print "---------------------------------------------------"
										
						for f in me.faces:
								#get the mesh index
								index = f.mat
								#find which material this is
								mat = matFromIndex(me.name, index)
								
								if mat != []:
										print mat
										#loop through the Textures in that material
									
										mtextures = mat.getTextures()
										try:
												tex = mtextures[0].tex
												if tex.type == Texture.Types.IMAGE:
														img = tex.image						
														f.image = img
										except:
												print" no image found"
		if editmode: 
				Window.EditMode(1)			#restore editmode to be nice.


#-------------------------------------------------
def removeMaterials():
		scn = 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
 
						me = ob.getData(mesh=1)	
						nme=NMesh.GetRaw(me.name)
						mats = nme.materials 
						i=0
						for m in mats:
								del nme.materials[i]
								i += 1
								nme.update()
						print mats
						
#-------------------------------------------------					
			
def add_GetUV(me, UVName): 			#mesh object, string
	
		# Checks mesh object "me" for a set of UVs called "UVName".
		# If it exists set it to active, if it doesn't exist create it and set to active.
		me.faceUV =True
		UVLayers = me.getUVLayerNames()

		#Check to see if there's already a set of UVs called UVName
		found = 0
		for UVL in UVLayers:
				if UVL == UVName:
						found = 1
						me.activeUVLayer = UVName
						me.renderUVLayer = UVName
						print "found"
		if (found == 0):	
		 		me.addUVLayer(UVName)
				me.activeUVLayer = UVName
				me.renderUVLayer = UVName
	
#-------------------------------------------------	
def imagetoTex(imgName, matName,chanNumber):		#string, string, integer
		#assigns an image to a material in the channel
		img = Image.Get(imgName)
		mat = Material.Get(matName)
		imgName = stripExtension(imgName)
		
		try:
				#see if the texture already exists
				Tex = Texture.Get(imgName)
		except:
				#if it doesn't then create it
				Tex = Texture.New(imgName)	
		Tex.setType("Image")		
		Tex.image = img

		mat.setTexture(chanNumber, Tex, Texture.TexCo["UV"],Texture.MapTo["COL"])		

		
#-------------------------------------------------


def TexfaceImageCreate(width, height, mapName, me):				#int, int, string, mesh object
		#adds an image of specified width and height called "object_suffix", or gets the image if it exists		
		#apply the image as TEXFACE
		 
		me.faceUV = True               # adds UV coords and textures if we don't have them.
		                
		       
			  #Make an image named after the mesh
		try:
				img = Image.Get(mapName)
				print "got image", mapName

		except:
 				img = bpy.data.images.new(mapName,width,height)
				print "creating image",mapName
								
		for f in me.faces:
				f.image = img
				

#-------------------------------------------------			
def setActiveUV(UVName):
		#set the active uvs to "UVName"
		
		editmode = Window.EditMode() 				# are we in editmode?
		if editmode:
				Window.EditMode(0) 							#leave edit mode before getting mesh
				
				
		scn = Scene.GetCurrent()
		for ob in scn.objects.context:
				if not ob.lib and ob.type == 'Mesh':    # object isn't from a library and is a mesh
						me = ob.getData(mesh=1)
						add_GetUV(me, UVName)

		if editmode: 
				Window.EditMode(1)			#restore editmode to be nice.
				
				
#-------------------------------------------------			
			
def setUVname(matname, uvName, i):			
	#the material name, name of the uv set and the index of the texture channel to set
	#test code here
	
	try:
		mat = Material.Get(matname)
		print "got", mat
		mtextures = mat.getTextures()
		mtex=mtextures[i]
		mtex.uvlayer = uvName
	except:
		print "couldn't get material"

	return
				
				
#-------------------------------------------------			
	
def getallUVlayers():

	editmode = Window.EditMode() 				# are we in editmode?
	if editmode:
			Window.EditMode(0) 							#leave edit mode before getting mesh
			
			
	#for each material in a mesh finds the first  texture channel image and assigns it as TEXFACE
	#acts on all visible selected objects.
	#could be extended to take multiple uvs into account
	scn = data.scenes.active
	
	
	#create a list to store uvlayer names in
	layers =[]
	
	for ob in scn.objects.context:
			if not ob.lib and ob.type == 'Mesh':    # object isn't from a library and is a mesh
					me = ob.getData(mesh=1)	
					
					UVLayers = me.getUVLayerNames()
					
					#check to see if the layers are on our list
					for UVL in UVLayers:
						found = 0
						for l in layers:
							if l == UVL:
								found = 1
								
						if found == 0:			#this layer isn't on the list yet!
							layers.append(UVL)
	
						
	return	layers
#-------------------------------------------------			
						
def main():
		options = "Choose:%t|Texface-->Material|Material-->Texface|Detach All Materials|SetActive UV layer"
		result = Blender.Draw.PupMenu(options)


		if result == -1:
			print "Nothing Chosen"
			return 0
		
		if result == 1:
			print "Converting TEXFACE images to materials"
			TEXFACEToMat()
			return 1
		
		elif result == 2:
			print "Reading First Texture channel of materials and applying as TEXFACE"
			matToTEXFACE()
			return 1

		elif result ==3:
			print "removing all materials from selected meshes"
			removeMaterials()
			return 1
		
		elif result ==4:
			#create a menu for the user to pick UV chans from
			
			#get the existing UV channels
			UVlayers = getallUVlayers()
			
			Puplist = "Channel:%t"
			for UV in UVlayers:
				Puplist+= "|"+ UV 
			
			#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:
					UVName = UVlayers[chan-1]			
					print"chosen chan is", UVName
					setActiveUV(UVName)
					
				except:
					#the user has picked "New" so post a text entry to enter a name
					UVName = Draw.PupStrInput("Name :", "UVNew")
					print"chosen chan is", UVName
					setActiveUV(UVName)

			return 1

	

		
		
		
		
	
done = main()
if done == 1:
	print "done"
	Draw.PupMenu("Done%t|OK") 
else:
	print"Nothing Done"
	
	
#This lets you import this script without running it
#if__name__=="__main__":
#		main()

