#!BPY

"""
Name: 'Render UV Seams'
Blender: 248
Group: 'UV'
Tooltip: 'Render UV Seams'
""" 

__author__ = "Damir Prebeg"
__url__ = ("http://www.blender.org", "http://blenderartists.org/", "http://blendfactory.phpnet.us")
__version__ = "0.520070924"

__bpydoc__ = """\

Description:
	
	- This script renders UV Seems and saves rendered image to selected location.

Usage:
	
	-	First, make sure that there is one UV mapped mesh selected, launch this script from Render menu,
		define size, wire and background color, select image type and hit 'Render' or 'Render & Save' button.
	-	If you hit 'Save UV Image' in File Selector without typing or selecting file, Image will be named as selected object.
	
Issues:
	
	- Currently there's no way to define wire thicknes.
	- Uhm... How to enter Face Select mode with python?!?!

Warning and I'll say again - Warning:
	
	-	Because this script creates new meshes, objects and materials, links and unlinks them from scene,
		changes world and render setings although it saves and restore them after finishes it's job,
		save your blend file before you launch this script.

		You have been warned.

Versions:
	
	- 0.520070924:
		
		Date: 24.09.2007
		Desc: First public, beta release

Contact:
	
	- Bug reports, suggestions, comments and questions send to: blend point factory on gmail point com
	
	
	Damir Prebeg

"""

# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2007 by Damir Prebeg, blend.factory@gmail.com
#
# 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 *****

import Blender
from Blender import *
from Blender.Mathutils import Vector, Euler
from Blender.Scene import Render

evt_null = 0

evt_btnRender = 1
evt_btnSave = 2
evt_btnClose = 3

evt_togBW = 4
evt_togRGB = 5
evt_togRGBA = 6

numSize = Draw.Create(512)
numQuality = Draw.Create(85)
clrPickWire = Draw.Create(0.0, 0.0, 0.0)
clrPickBG = Draw.Create(1.0, 1.0, 1.0)
mnuContent = "Select image type:%t|PNG%x1|JPEG%x2|BMP%x3|TARGA%x4|TARGA RAW%x5|TIFF%x6"
mnuImageTypes = Draw.Create(1)

togAntialias = Draw.Create(1)

togBW = Draw.Create(0)
togRGB = Draw.Create(1)
togRGBA = Draw.Create(0)

imgTypes = ["PNG","JPEG","BMP","TARGA","RAWTGA","TIFF"]
imgExtensions = ["png","jpg","bmp","tga","tga","tif"]

workingMesh = None
editMode = 0

def draw():
	global numSize, numQuality, clrPickWire, clrPickBG, mnuImageTypes, togAntialias, togBW, togRGB, togRGBA
	Draw.Label("Render UV Seems", 24, 220, 150, 20)
	numSize = Draw.Number("Size:", evt_null, 5, 200, 150, 20, numSize.val, 10, 10000, "Set output image size")
	Draw.Label("FG color:", 2, 180, 150, 20)
	clrPickWire = Draw.ColorPicker(evt_null, 5, 160, 70, 20, clrPickWire.val, "Set color of UV mesh")
	Draw.Label("BG color:", 82, 180, 150, 20)
	clrPickBG = Draw.ColorPicker(evt_null, 85, 160, 70, 20, clrPickBG.val, "Set Background color")
	Draw.Label("Image format:", 2, 140, 150, 20)
	mnuImageTypes = Draw.Menu(mnuContent, evt_null, 5, 120, 150, 20, mnuImageTypes.val, "Select Image format")
	if mnuImageTypes.val in [1,4,5,6]:
		togBW = Draw.Toggle("BW", evt_togBW, 5, 100, 50, 16, togBW.val, "Black & White")
		togRGB = Draw.Toggle("RGB", evt_togRGB, 55, 100, 50, 16, togRGB.val, "Color")
		if mnuImageTypes.val == 1:
			togRGBA = Draw.Toggle("RGBA", evt_togRGBA, 105, 100, 50, 16, togRGBA.val, "Color with Alpha")
	elif mnuImageTypes.val == 2:
		numQuality = Draw.Number("Quality:", evt_null, 5, 100, 150, 16, numQuality.val, 10, 100, "Set JPEG quality")
	
	togAntialias = Draw.Toggle("Antialias", evt_null, 5, 80, 150, 16, togAntialias.val, "Antialias")
	
	Draw.Button("Render", evt_btnRender, 5, 55, 150, 20, "Just Preview render, don't save")
	Draw.Button("Render & Save", evt_btnSave, 5, 30, 150, 20, "Render UV Image")
	Draw.Button("Close", evt_btnClose, 5, 5, 150, 20, "Exit script")
	pass

def _Input_Events_Callback(event, Value):
	if event == Draw.QKEY and Value:
		ret = Draw.PupMenu("Quit Render UV Seems?%t|Yes%x1|No%x2")
		if ret == 1:
			Draw.Exit()

def event(event, value):
	_Input_Events_Callback(event, value)

def b_Event(event):
	
	global togBW, togRGB, togRGBA
	
	if event == 1:
		render_uvImage(False)
	elif event == 2:
		render_uvImage(True)
	elif event == 3:
		Draw.Exit()
	elif event == 4:
		togBW.val = 1
		togRGB.val = 0
		togRGBA.val = 0
	elif event == 5:
		togRGB.val = 1
		togBW.val = 0
		togRGBA.val = 0
	elif event == 6:
		togRGBA.val = 1
		togBW.val = 0
		togRGB.val = 0
	Draw.Redraw()

	
def do_render_uvImage(save, filename, filepath):
	
	global workingMesh, numSize, numQuality, clrPickWire, clrPickBG, mnuImageTypes, togAntialias, togBW, togRGB, togRGBA
	
	uvVerts = []
	uvFaces = []
	uvDict = {}
	
	#Collect UVs and create faces
	for face in map(list,(face.uv for face in workingMesh.faces if face.sel)):
		uvFace = []
		for uv in face:
			uvVec = Vector(uv[0],uv[1],0)
			uvStr = "%f,%f,%f" % (uvVec[0],uvVec[1],uvVec[2])
			if not uvDict.has_key(uvStr):
				uvVerts.append(uvVec)
				uvDict[uvStr] = len(uvVerts)-1
				uvFace.append(uvDict[uvStr])
			else:
				uvFace.append(uvDict[uvStr])
		uvFaces.append(uvFace)
	
	if not uvVerts:
		Draw.PupMenu("Select faces or UV islands first!%t|Ok")
		return
	
	#Create or get existing RenderUVMesh
	uvMeshOb = None
	try:
		try:
			#Try to get existing RenderUVMesh ob and data
			uvMeshOb = Object.Get("RenderUVMesh")
			uvMesh = uvMeshOb.getData(mesh=1)
			uvMesh.verts.delete(uvMesh.verts)
		except:
			#Try to get only RenderUVMesh mesh
			uvMesh = Mesh.Get("RenderUVMesh")
			uvMesh.verts.delete(uvMesh.verts)
	except:
		#If there's no RenderUVMesh, create a new one
		uvMesh = Blender.Mesh.New("RenderUVMesh")	
	
	#Add verts and faces
	uvMesh.verts.extend(uvVerts)
	uvMesh.faces.extend(uvFaces)	
	
	#Create or get existing RenderUVMat
	try:
		#Get existing RenderUVMat
		uvMat = Material.Get('RenderUVMat')
	except:
		#If there's no RenderUVMat, create a new one
		uvMat = Material.New('RenderUVMat')
	
	#Adjust RenderUVMat and add it to RenderUVMesh
	if togBW.val:
		uvMat.rgbCol = [0.0,0.0,0.0]
	else:
		uvMat.rgbCol = clrPickWire.val
	uvMat.mode = Material.Modes.SHADELESS | Material.Modes.WIRE
	uvMesh.materials=[uvMat]
	
	#Create or get camera
	uvCamOb = None
	try:
		#Get existing RenderUVCamera
		try:
			uvCamOb = Object.Get('RenderUVCamera')
			uvCam = uvCamOb.getData()
		except:
			uvCam = Camera.Get('RenderUVCamera')
	except:
		#If there's no RenderUVCamera, create a new one
		uvCam = Camera.New('ortho', "RenderUVCamera")
	
	uvCam.type = 'ortho'
	uvCam.scale = 1.0	
	
	#Get current scene and world
	scn = Scene.GetCurrent()
	wld = World.GetCurrent()
	
	NewWorld = False
	if not wld:
		wld = World.New("RenderUVWorld")
		wld.setCurrent()
		NewWorld = True			
	
	#If RenderUVMesh and RenderUVCamera already exists, there's no need to add them again
	
	if not uvMeshOb:
		uvMeshOb = scn.objects.new(uvMesh,"RenderUVMesh")
	else:
		#Just to ensure that RenderUVMesh is actually linked to the scene
		try:
			scn.objects.link(uvMeshOb)
		except:
			pass
	if not uvCamOb:
		uvCamOb = scn.objects.new(uvCam,"RenderUVCamera")
	else:
		#Just to ensure that RenderUVCamera is actually linked to the scene
		try:
			scn.objects.link(uvCamOb)
		except:
			pass
	
	#Store current selection
	selObjects = [ob for ob in scn.objects.selected]
	
	#Deselect all objects
	scn.objects.selected = []
	
	#Move objects to current layer
	uvMeshOb.layers = scn.layers
	uvCamOb.layers = scn.layers
	
	#Move camera and mesh outside current view	
	uvMeshOb.setLocation(1000,1000,0)
	uvCamOb.setLocation(1000.5,1000.5,0.1)
	
	#Reset RenderUVCamera rotation
	uvCamOb.setEuler(0,0,0)
	
	#Set RenderUVCamera as active camera
	currActiveCam = scn.objects.camera
	scn.objects.camera = uvCamOb
	
	#Backup world setings
	
	if not NewWorld:
		WldMode = wld.getMode()
		WldHor = wld.getHor()
	
	#Set world setings
	
	wld.setMode(0)
	if togBW.val:
		wld.setHor([1.0,1.0,1.0])
	else:
		wld.setHor(map(float,clrPickBG.val))
	
	#Get rendering context
	context = scn.getRenderingContext()
	
	#Backup rendering context options
	ImageType = context.imageType
	SizeX = context.sizeX
	SizeY = context.sizeY
	SFrame = context.sFrame
	EFrame = context.eFrame
	Renderer = context.renderer
	Quality = context.quality()
	ImagePlanes = context.imagePlanes
	DisplayMode = context.displayMode
	RenderPath = context.getRenderPath()
	Oversampling = context.oversampling
	OSALevel = context.OSALevel
	
	#Set new render options
	context.imageType = eval("Render."+imgTypes[mnuImageTypes.val-1]) #var
	context.sizeX = numSize.val
	context.sizeY = numSize.val
	context.sFrame = context.currentFrame()
	context.eFrame = context.currentFrame()
	context.renderer = 0
	context.quality(numQuality.val)
	if togBW.val and mnuImageTypes.val in [1,4,5,6]:
		context.imagePlanes = 8
	elif togRGB.val and mnuImageTypes.val in [1,2,3,4,5,6]:
		context.imagePlanes = 24
	elif togRGBA.val and mnuImageTypes.val == 1:
		context.imagePlanes = 32
	else:
		context.imagePlanes = 24 #Default depth
	context.displayMode = 1
	context.setRenderPath(filepath)
	context.oversampling = togAntialias.val
	context.OSALevel = 8 #
	
	#Render UVImage
	
	context.render()
	if save:
		context.saveRenderedImage(filename, 1)
	
	#Restore world setings
	
	if not NewWorld:
		wld.setMode(WldMode)
		wld.setHor(WldHor)
	
	#Restore rendering context options
	context.imageType = ImageType
	context.sizeX = SizeX
	context.sizeY = SizeY
	context.sFrame = SFrame
	context.eFrame = EFrame
	context.renderer = Renderer
	context.quality(Quality)
	context.imagePlanes = ImagePlanes
	context.displayMode = DisplayMode
	context.setRenderPath(RenderPath)
	context.oversampling = Oversampling
	context.OSALevel = OSALevel
	
	#Restore active camera	
	scn.objects.camera = currActiveCam
	
	#Remove RenderUVMesh and RenderUVCam form scene
	scn.objects.unlink(uvMeshOb)
	scn.objects.unlink(uvCamOb)
	
	#Restore selection
	scn.objects.selected = selObjects

def get_mesh():
	try:
		mesh = Blender.Object.GetSelected()[0].getData(mesh=1)
		if type(mesh) != Blender.Types.MeshType:
			Draw.PupMenu("Select a valid mesh object!%t|Ok")
			return False
		if not mesh.faceUV:
			Draw.PupMenu("Selected mesh doesn't have UV data!%t|Ok")
			return False
	except:
		Draw.PupMenu("Select a valid mesh object!%t|Ok")
		return False
	
	return mesh

def render_uvImage(save):
	global workingMesh, editMode
	editMode = Window.EditMode()
	Window.EditMode(0)
	workingMesh = get_mesh()
	if workingMesh:
		if save:
			Window.FileSelector(save_uvImage, 'Save UV Image', ".\\")
		else:
			Window.WaitCursor(1)
			do_render_uvImage(False, "", "")
			Window.WaitCursor(0)
	if editMode:
		Window.EditMode(1)
	Window.RedrawAll()

def save_uvImage(path):
	global mnuImageTypes, imgExtensions
		
	pathElements = path.split("\\")
	
	if pathElements[-1]:
		fileext = pathElements[-1].split(".")[-1].lower()
		if fileext in imgExtensions:
			mnuImageTypes.val = imgExtensions.index(fileext)+1
		filename = pathElements[-1].split(".")[0] + "." + imgExtensions[mnuImageTypes.val-1]
		filepath = ""
		for element in pathElements[0:-1]:
			filepath+=(element+"\\")
	else:
		filename = Object.GetSelected()[0].name + "." + imgExtensions[mnuImageTypes.val-1]
		filepath = ""
		for element in pathElements[0:-1]:
			filepath+=(element+"\\")
	
	if Blender.sys.exists(filepath+filename):
		overwrite = Draw.PupMenu("File with name "+filename+" already exists!%t|Overwrite%x1|Cancel%x0")
		if not overwrite:
			return
	
	Window.WaitCursor(1)
	do_render_uvImage(True, filename, filepath)
	Window.WaitCursor(0)

Draw.Register(draw, event, b_Event)