#!BPY
"""
Name: 'VertexNormalFromFaceNormal'
Blender: 248
Group: 'Mesh'
Tooltip: 'set vertex normals according to face normals'
"""

# --------------------------------------------------------------------------
# Vertex Normal script by Simon Broggi
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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 *****
# --------------------------------------------------------------------------


from Blender import Scene, Mesh, Window, sys, Mathutils, Draw, BGL
import BPyMessages
import bpy

#toggle button states
xFromFace = 1
yFromFace = 1
zFromFace = 1
restorMode = 0
smoothWhenObjmode = 0


def fn2vn(me, xFromFace, yFromFace, zFromFace):
	# change the vertex-normals of the selected faces to match
	# the face-normal in the selected axis	
	for f in me.faces:
		if f.sel:
			for v in f:
				newNo = Mathutils.Vector(v.no.x, v.no.y, v.no.z)
				if xFromFace:
					newNo.x = f.no.x
				if yFromFace:
					newNo.y = f.no.y
				if zFromFace:
					newNo.z = f.no.z
				v.no = newNo

def saveVNormals(me):
	vNormals = {}
	for v in me.verts:
		vNormals[v.index] = v.no
	return vNormals

def setVNormals(me, vNormals):
	for v in me.verts:
		v.no = vNormals[v.index]
		
def event(evt, val):	# the function to handle input events
	if not val:  # val = 0: it's a key/mbutton release
		if evt in [Draw.LEFTMOUSE, Draw.MIDDLEMOUSE, Draw.RIGHTMOUSE]:
			print("mousebutton released")
			Draw.Redraw(1)
		return
	
	if evt == Draw.ESCKEY:
		Draw.Exit()                 # exit when user presses ESC
		return

def button_event(evt):
	global xFromFace, yFromFace, zFromFace, restorMode, smoothWhenObjmode
	if evt == 1:#x
		xFromFace = 1 - xFromFace
		Draw.Redraw(1)
	if evt == 2:#y
		yFromFace = 1 - yFromFace
		Draw.Redraw(1)
	if evt == 3:#z
		zFromFace = 1 - zFromFace
		Draw.Redraw(1)
	if evt == 4:#go
		go()
	if evt == 5:#restorMode
		restorMode = 1 - restorMode
		Draw.Redraw(1)
	if evt == 6:#smoothWhenObjmode
		smoothWhenObjmode = 1 - smoothWhenObjmode
		Draw.Redraw(1)

def gui():
	global xFromFace, yFromFace, zFromFace, restorMode, smoothWhenObjmode
	Draw.Toggle("X From Face", 1, 10, 70, 100, 20, xFromFace, "set the vertex normals x to the face normals x")
	Draw.Toggle("Y From Face", 2, 10, 40, 100, 20, yFromFace, "set the vertex normals y to the face normals y")
	Draw.Toggle("Z From Face", 3, 10, 10, 100, 20, zFromFace, "set the vertex normals z to the face normals z")
	Draw.PushButton("Go", 4, 130, 10, 100, 50, "set vertex normals of selected faces to face normals")
	Draw.Toggle("edit", 5, 130, 70, 45, 20, restorMode, "gos back to edit mode. Warnign: if you then go back to object mode normally the normals will be smothed!")
	Draw.Toggle("smooth", 6, 185, 70, 45, 20, smoothWhenObjmode, "reset the normals to before running the script. This automatically hapens when you go from edit to object mode")

def go():
	sce = bpy.data.scenes.active
	ob_act = sce.objects.active
	
	if not ob_act or ob_act.type != 'Mesh':
		BPyMessages.Error_NoMeshActive()
		return 
	
	Window.WaitCursor(1)
	me = ob_act.getData(mesh=1) # old NMesh api is default
	#t = sys.time()
	
	# to avoid losing the values of the normals
	# save them before going out of edit mode.
	# (going out of edit mode smooths the normals)
	normals = saveVNormals(me)
	
	# Saves the editmode state and go's out of 
	# editmode if its enabled, we cant make
	# changes to the mesh data while in editmode.
	is_editmode = Window.EditMode()
	if is_editmode: Window.EditMode(0)
	
	if not smoothWhenObjmode:
		setVNormals(me, normals)
	
	# Run the mesh editing function
	fn2vn(me, xFromFace, yFromFace, zFromFace)
	
	# Restore editmode if it was enabled
	if is_editmode and restorMode: Window.EditMode(1)
	
	# Timing the script is a good way to be aware on any speed hits when scripting
	#print 'My normal Script finished in %.2f seconds' % (sys.time()-t)
	Window.WaitCursor(0)
	

if __name__ == '__main__':
	Draw.Register(gui, event, button_event)
