#!BPY

""" Registration info for Blender menus: <- these words are ignored
Name: 'Make_Human_fake_sss'
Blender: 248
Group: 'Materials'
Tip: 'Use vertex paint color to make a superficial subsurface scattering effect'
"""

__author__ = "MakeHuman team"
__url__ = ("blender", "elysiun",
"Script's homepage, http://www.dedalo-3d.com",
"Communicate problems and errors, info@makehuman.org")
__version__ = "1.0 09/2005"

__bpydoc__ = """\
This script use the Blender vertex shader to simulate a superficial scattering effect.
It's under GPL license.

"""
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Script copyright (C) MakeHuman Team 
#
# 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 math import *
from Blender.Draw import *
from Blender.BGL import *
from Blender import Scene
from Blender import Window


import time

power= Create(1.0)
diffusion = Create(1.0)
colors1= [Create(150), Create(150), Create(150)]
		

	
#Some vector-matrix functions
#############################

# returns Vector Length
def vlen(u):
    return sqrt(u[0]**2 + u[1]**2 + u[2]**2)
def vdot(u, v):
    return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]
# returns a vector u-v
def vsub(u, v):
    return [u[0]-v[0], u[1]-v[1], u[2]-v[2]]
# returns a vector u+v
def vadd(u, v):
    return [u[0]+v[0], u[1]+v[1], u[2]+v[2]]

# returns a vector u*scalar
def vmul(u, s):
    return [u[0]*s, u[1]*s, u[2]*s]
# returns a vector normalized
def vunit(u):
    return vmul(u, 1/vlen(u))

def multmatvec4x3(m, v):
	r = [0.0, 0.0, 0.0]
	r[0] = v[0]*m[0][0] + v[1]*m[1][0] + v[2]*m[2][0] + m[3][0]
	r[1] = v[0]*m[0][1] + v[1]*m[1][1] + v[2]*m[2][1] + m[3][1]
	r[2] = v[0]*m[0][2] + v[1]*m[1][2] + v[2]*m[2][2] + m[3][2]
	return r

def mulmatvec3x3(m, v):
	r = [0.0, 0.0, 0.0]
	r[0] = v[0]*m[0][0] + v[1]*m[1][0] + v[2]*m[2][0]
	r[1] = v[0]*m[0][1] + v[1]*m[1][1] + v[2]*m[2][1]
	r[2] = v[0]*m[0][2] + v[1]*m[1][2] + v[2]*m[2][2]
	return r


#Main functions
#############################

def quickSSS(rampColor, power=1, diffusion = 2, intensity = 1):
	vLights = {}
	vNormls = {}
	vCoords = {}		
	
	
	try:		
		objToIlluminate = Object.GetSelected()[0]
	except:
		print "No obj selected for Ill"
		PupMenu("Error%t|No object selected")
		return					
	
	if objToIlluminate.getType() == "Mesh":			
		mesh = objToIlluminate.getData()
		m = objToIlluminate.getMatrix()
		faces = mesh.faces
		mesh.hasVertexColours(1)
		for f in faces:
			for i in f.col:
				i.r = 0
				i.g = 0
				i.b = 0								
				
	else:
		print "No obj selected for Ill"
		PupMenu("Error%t|No object selected")
		return	
		
	#If we have multiple lights, this is optimized to make the
	#matrix multiplication only one time
	for v in mesh.verts:			
			vNormls[str(v)] = mulmatvec3x3(m, v.no) #local to global (no translation)
			vCoords[str(v)] = multmatvec4x3(m, v.co) #local to global (tranlation too)
			
	objects = Object.Get()		
	for obj in objects:
		if 'Lamp' in obj.getName() or obj.getType() == "Lamp":
			sourceLight = obj
					
			lightCoo = sourceLight.getLocation()
					
			print "NAME",sourceLight.getName(), "COOR",lightCoo
			for v in mesh.verts:
				
				vCoo = vCoords[str(v)]
				vNor = vNormls[str(v)]
										
				lightVector = vunit(vsub(lightCoo,vCoo))
				vertVector = vNor #The norm is already normalized
		
				dotProd = vdot(lightVector,vertVector)
				
				vColR = 0
				vColG = 0
				vColB = 0			
							
				rampFactor = (e**(-1*((diffusion*dotProd)**2)))/(6-power)		
				
					
				if vLights.has_key(str(v)):
					#to take account to already calc light
					vColR = int(vLights[str(v)].r + int(rampColor[0]*rampFactor))
					vColG = int(vLights[str(v)].g + int(rampColor[1]*rampFactor))
					vColB = int(vLights[str(v)].b + int(rampColor[2]*rampFactor))				
				else:
					#if this is the first light
					vColR = int(rampColor[0]*rampFactor)
					vColG = int(rampColor[1]*rampFactor)
					vColB = int(rampColor[2]*rampFactor)
														
							
				if vColR > 255: vColR = 255
				if vColG > 255: vColG = 255
				if vColB > 255: vColB = 255			
				
					
				color = NMesh.Col(vColR,vColG,vColB,255)
				vLights[str(v)] = color
			
	for f in faces:							
		if len(f.col)==0: 
			f.col = []				
			for v in f.v:
				f.col.append(NMesh.Col(0,0,0,0))				
		for v in f.v:
			vIndx = f.v.index(v)
			if vLights.has_key(str(v)):
				f.col[vIndx].r += vLights[str(v)].r
				f.col[vIndx].g += vLights[str(v)].g
				f.col[vIndx].b += vLights[str(v)].b									
	mesh.update()


			
def saveParameters(fileName):
		global colors1,power,diffusion
		dataFile = open(fileName,"w")
		dataFile.write(str(colors1[0].val)+"\n")
		dataFile.write(str(colors1[1].val)+"\n")
		dataFile.write(str(colors1[2].val)+"\n")		
		dataFile.write(str(power.val)+"\n")
		dataFile.write(str(diffusion.val)+"\n")
		dataFile.close()
	
		
def loadParameters(fileName):
		global colors1,power,diffusion
		dataFile = open(fileName,"r")
		dataSSS = dataFile.readlines()
		dataFile.close()
		colors1[0].val=int(dataSSS[0])
		colors1[1].val=int(dataSSS[1])
		colors1[2].val=int(dataSSS[2])		
		power.val=float(dataSSS[3])
		diffusion.val=float(dataSSS[4])
		Redraw()				
		

def draw():
	global colors1,power,diffusion

	glClearColor(0.5, 0.5, 0.5, 0.0)
	glClear(GL_COLOR_BUFFER_BIT)

	glColor3f(float(colors1[0].val)/255,float(colors1[1].val)/255,float(colors1[2].val)/255)	
	glRectf(180,160,210,105)	
		
	glColor3f(1, 1, 1)
	glRasterPos2i(10, 167)
	Text("Scatter color",'small' )

	colors1[0]= Slider("Sc R: ", 2, 10, 145, 160, 18, colors1[0].val, 0, 255, 1)
	colors1[1]= Slider("Sc G: ", 2, 10, 125, 160, 18, colors1[1].val, 0, 255, 1)
	colors1[2]= Slider("Sc B: ", 2, 10, 105, 160, 18, colors1[2].val, 0, 255, 1)
	

	glColor3f(1, 1, 1)
	
	Button("Exit", 1, 10, 30, 40, 19)
	Button("Save", 4, 50, 30, 60, 19)
	Button("Load", 5, 110, 30, 60, 19)
	Button("START", 3, 10, 10, 160, 20)
	
	tooltip1 = "Increase or decrease scattering visibility"
	tooltip2 = "Increase or decrease the scattering penetration"
	
	power= Number("Power: ", 2, 10, 50, 160, 20, power.val, 1, 5,tooltip1)
	diffusion= Number("Scattering: ", 2, 10, 70, 160, 20, diffusion.val, 0.1, 5,tooltip2)
		
	glColor3f(1, 1, 1)
	glRasterPos2i(10, 220)
	Text("MH SuperficialSSS MHSSSS 1.0" )
	glColor3f(0, 1, 0)
	glRasterPos2i(10, 200)
	Text("Remember to use the -Vcol light- " )
	glColor3f(0, 1, 0)
	glRasterPos2i(10, 185)
	Text("in material setting!" )
	
	
def event(evt, val):	
	if (evt== QKEY and not val): Exit()

def bevent(evt):
	global colors1,colors2,power,diffusion
	if   (evt== 1): Exit()
	elif (evt== 2): pass
	elif (evt== 3):
		a = time.time()
		Window.WaitCursor(1)
		quickSSS([int(colors1[0].val),\
						int(colors1[1].val),\
						int(colors1[2].val)],\
						power.val,	5.0-diffusion.val)
		
		
		Window.WaitCursor(0)
		print "Time: ",time.time() -a
	elif (evt== 4):
		Window.FileSelector (saveParameters, "Save sss parameters")
	elif (evt== 5):
		Window.FileSelector (loadParameters, "Load sss parameters")

		
		
		
Register(draw, event, bevent)