
# ***** 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.
#
# If you have Internet access, you can find the license text at
# http://www.gnu.org/licenses/gpl.txt,
# if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

__bpydoc__ = """\
This plugin fills in another gap in the Blender modelling experience.  It provides a means of
setting up an unlimited amount of "background images", or to be more precise "reference images".
noThese planes can be positioned/scaled/deformed to your liking and will seemingly appear behind your
transparently rendered geometry.  In fact the reference planes are transparent
themselves and drawn on top of the geometry.  This means it is possible to use the planes for
both sides of your geometry (front/back, right/left, top/bottom), whatever way you look at them,
they will always be drawn transparently on top of the geometry.

Documentation
Go to User Preferences->Addons and enable the TranspRef addon in the 3D View section.
A TransRef pulldown will appear in the right pane (pull + icon on right of 3D view).
It will be empty until you select a standard Mesh->Plane with four vertices.
Click the file browser icon in N panel->TranspRef and load up an image, the image will be projected over the scene contents,
carefully filling the space bounded by the selected plane, which you can afterwards translate,
rotate, scale and deform(editmode) to your wishes.  When you selet an image, also a Transparency slider
will appear, put it somewhere low so you can see your geometry behind the reference planes.

NOTE: the reference planes shouldnt occlude object selection, thats why you can only select them
      by clicking the plane edges.

NOTE: you can create as many reference planes as needed.  Reselecting a plane later, enables you to
      access image path and transparency values.

HINT: you can use the reference planes from both sides. 
I recommend to model in orthogonal mode (which is a good idea anyhow) if you want this to work correctly.

BEWARE:  reference state will be saved along with your blend file, but you will have to manually enable
TranspRef once every Blender session and load your file after having done this.
"""

# many thanks go to lobo_nz for hacking in the original load/save code !
bl_info = {
	"name": "TranspRef",
	"author": "Gert De Roost",
	"version": (2, 5, 0),
	"blender": (2, 6, 3),
	"location": "View3D > UI > TranspRef",
	"description": "Adding transparent reference images to VIEW3D.",
	"warning": "",
	"wiki_url": "",
	"tracker_url": "",
	"category": "3D View"}

if "bpy" in locals():
    import imp


import bpy
from bpy_extras import *
from math import sqrt
from mathutils import *
from bgl import *
import os
import time
from bpy.app.handlers import persistent


imagelist = []
planelist = []
transplist = []
startedlist = []
resetlist = []
filenm = {}
state = {}
remembv = {}
position = 0
cbon = 0
oldtransp = 0.2
oldobj = None
ok = 0
start = 1
oldobjname = None
scnfilenm = ""
tm = time.time()
    
bpy.types.Scene.Transp = bpy.props.FloatProperty(
		name = "Transparency", 
		description = "Enter transparency",
        default = 0.2,
        min = 0,
        max = 1)
bpy.types.Scene.Filename = bpy.props.StringProperty(
		name="Image",
		attr="custompath",# this a variable that will set or get from the scene
		description="path to reference image",
		maxlen= 1024,
		subtype='FILE_PATH',
		default= "")



class TranspRefPanel(bpy.types.Panel):
	bl_label = "TranspRef"
	bl_space_type = "VIEW_3D"
	bl_region_type = "UI"
	
	def draw(self, context):
		
		global cbon, regionui, region3d, handle
				
		if not(cbon):
			cbon = 1
			for region in bpy.context.area.regions:
				if region.type == "UI":
					regionui = region
			for region in bpy.context.area.regions:
				if region.type == "WINDOW":
					region3d = region
					handle = region.callback_add(redraw, (), 'POST_VIEW')
					
		scn = context.scene

		if bpy.context.active_object:
			selobj = bpy.context.active_object.name
		else:
			selobj = None
		if selobj in state.keys():
			if state[selobj]:
				self.layout.prop(scn, 'Filename')
			if state[selobj] == 2:
				self.layout.prop(scn, 'Transp')
				
#		region3d.tag_redraw()


def register():
	bpy.utils.register_module(__name__)
	bpy.app.handlers.load_post.append(loaddata)

def unregister():
	bpy.utils.unregister_module(__name__)
	bpy.context.region.callback_remove(handle)


if __name__ == "__main__":
	register()




def saveplane(new, newplane, newtransp, newpath):
	global save_planelist, save_transplist, save_pathlist

	if bpy.data.texts.get("savedrefplanes") != None:
		txt = bpy.data.texts["savedrefplanes"]
		if new != 2:
			save_planelist = []
			save_transplist = []
			save_pathlist = []
			#load the saved data
			evallist = txt.lines
			eval0 = evallist[0].body
			eval1 = evallist[1].body
			eval2 = evallist[2].body
			eval0 = eval0.encode('unicode_escape')
			eval1 = eval1.encode('unicode_escape')
			eval2 = eval2.encode('unicode_escape')
			save_planelist = eval(eval0)
			save_transplist = eval(eval1)
			save_pathlist = eval(eval2)
		txt.clear()
	else:
		save_planelist = []
		save_transplist = []
		save_pathlist = []
		#create new text
		txt = bpy.data.texts.new("savedrefplanes")

	#append new plane info
	if new == 1:
		save_planelist.insert(0, newplane)
		save_transplist.insert(0, newtransp)
		save_pathlist.insert(0, newpath)
	elif new == 0:
		save_planelist[position] = newplane
		save_transplist[position] = newtransp
		save_pathlist[position] = newpath
    
	#write save_planelist to text object
	txt.write("[")
	for i in range(len(save_planelist)):
		if i != 0:
			txt.write(", ")
		txt.write("'"+save_planelist[i]+"'")
	txt.write("]\n")
    
	#write save_transplist to text object
	txt.write("[")
	for i in range(len(save_transplist)):
		if i != 0:
			txt.write(", ")
		txt.write(str(save_transplist[i]))
	txt.write("]\n")
    
	#write save_pathlist to text object
	txt.write("[")
	for i in range(len(save_pathlist)):
		if i != 0:
			txt.write(", ")
		txt.write("'"+save_pathlist[i]+"'")
	txt.write("]\n")
	

def loadimage(new, filename):
	global imagelist, transplist, planelist
	
	scn = bpy.context.scene
	
	obj = bpy.context.active_object
	bpy.ops.image.open(filepath = filename)
	image = bpy.data.images[os.path.basename(filename)]
	image.gl_load(GL_NEAREST, GL_NEAREST)
	
	if new:
		imagelist.append(image.name)
		obj.draw_type = "BOUNDS"
		transplist.insert(0, 0.2)
	else:
		imagelist[position] = image.name

	saveplane(new, obj.name, scn.Transp, filename)

	



def drawreference(image, vectors, transparency):
	"""
	Draws Reference-imageplanes
	
	image = the image to draw
	vectors = global vector-coordinates of 4 plane corners
	viewport = viewport of current area
	matrix = perspectivematrix of current area
	transparency = transparency of the image from 0.0 to 1.0
	
	"""
	if not(image.bindcode):
		image.gl_load()
	glBindTexture(GL_TEXTURE_2D, image.bindcode)
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)	
	glEnable(GL_TEXTURE_2D)
	glColor4f(1, 1, 1, transparency)
	glDisable(GL_DEPTH_TEST)
	glEnable(GL_BLEND)
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
	glBegin(GL_QUADS)
	glTexCoord2f(0.0, 0.0)
	x, y, z = vectors[3]
	glVertex3f(x, y, z)
	glTexCoord2f(0.0, 1.0)
	x, y, z = vectors[2]
	glVertex3f(x, y, z)
	glTexCoord2f(1.0, 1.0)
	x, y, z = vectors[1]
	glVertex3f(x, y, z)
	glTexCoord2f(1.0, 0.0)
	x, y, z = vectors[0]
	glVertex3f(x, y, z)
	glEnd()
	glBindTexture(GL_TEXTURE_2D, 0)
	glDisable(GL_BLEND)
	glEnable(GL_DEPTH_TEST)
	glDisable(GL_TEXTURE_2D)


def getplanevectors(plane):

	global vectorlist

	mesh = plane.data
	if plane.mode == "EDIT" and plane == bpy.context.active_object:
		bpy.ops.object.editmode_toggle()
		bpy.ops.object.editmode_toggle()
	for vertidx in mesh.polygons[0].vertices:
		vec = Vector(mesh.vertices[vertidx].co[:])
		vec = vec.copy()
		vec.rotate(plane.matrix_world)
		vec.rotate(plane.matrix_world)
		vec = vec * plane.matrix_world + plane.matrix_world.to_translation()
		vectorlist.append(vec)
		


def redraw():
	global imagelist, transplist, planelist, vectorlist
	global position
	global filenm, state, oldobj, oldtransp
	global scnfilenm, remembv
	
	if bpy.context.area.type != "VIEW_3D":
		return
		
	scn = bpy.context.scene
	if bpy.context.active_object:
		selobj = bpy.context.active_object.name
	else:
		selobj = None
	if checkplane(selobj):
		if not(selobj in planelist):
			planelist.append(selobj)
			position = 0
			state[selobj] = 1
			scn.Filename == ""
			scnfilenm = ""
			filenm[selobj] = ""
			scn.Transp = 0.2
			transplist.append(scn.Transp)
			oldtransp = scn.Transp
	else:
		if not(selobj in planelist):
			state[selobj] = 0
		
	for plane in planelist:
		obj = bpy.data.objects.get(plane)
		if not(obj):
			posn = planelist.index(plane)
			planelist.pop(posn)
			imagelist.pop(posn)
			transplist.pop(posn)
			filenm[plane] = ""
			state[plane] = 0
			remembv[plane] = {}
	
	
	if selobj != oldobj:
		if selobj in planelist:
			scn.Filename = filenm[selobj]
			scn.Transp = transplist[planelist.index(selobj)]
	
	if selobj != None:	
		if checkplane(selobj):
			if state[selobj] == 1:
				if scn.Filename != "":
					try:
						filenm[selobj] = scn.Filename
						state[selobj] = 2
						loadimage(1, filenm[selobj])
					except:
						print ("Problem with image file...")
			if state[selobj] == 2:
				position = planelist.index(selobj)
				if scn.Filename == "":
					state[selobj] = 1
				elif (scn.Filename != filenm[selobj]) and (selobj == oldobj):
					filenm[selobj] = scn.Filename
					loadimage(0, filenm[selobj])
		oldobj = selobj

		if scn.Transp != oldtransp:
			transplist[position] = scn.Transp
			saveplane(0, selobj, scn.Transp, scn.Filename)
			oldtransp = scn.Transp

		regionui.tag_redraw()
		
		
	for planename in planelist:
		if state[planename] == 2:
			plane = bpy.data.objects.get(planename)
			plane.draw_type = 'BOUNDS'
			if plane.data:
				vectorlist = []
				getplanevectors(plane)		
		
			for area in bpy.context.screen.areas:
				for sp in area.spaces:
					if sp.type == "VIEW_3D":
						posn = planelist.index(planename)
						imagename = imagelist[posn]
						image = bpy.data.images.get(imagename)
						if not(image):
							saveplane(2, "", 0, "")
							filename = save_pathlist[len(imagelist) - posn - 1]
							bpy.ops.image.open(filepath = filename)
							image = bpy.data.images[os.path.basename(filename)]
							image.name = imagename
						drawreference(image, vectorlist, transplist[posn])



def checkplane(objname):
	
	# Test if selection is exactly one non-subdivided plane.
	obj = bpy.data.objects.get(objname)
	if obj == None:
		return 0
	if obj.type != "MESH":
		return 0
	mesh = obj.data
	if not(mesh):
		return 0
	if len(mesh.polygons) == 0:
		return 0
	if (len(mesh.polygons) > 1) or (len(mesh.polygons[0].vertices) != 4):
		return 0
	return 1
    

@persistent
def loaddata(dummy):
	
	global imagelist, planelist, transplist, filenm, state

	scene = bpy.context.scene
	scene.Filename = ""
	
	if bpy.data.texts.get("savedrefplanes"):
		txt = bpy.data.texts["savedrefplanes"]
		#load the saved data
		evallist = txt.lines
		eval0 = evallist[0].body
		eval1 = evallist[1].body
		eval2 = evallist[2].body
		eval0 = eval0.encode('unicode_escape')
		eval1 = eval1.encode('unicode_escape')
		eval2 = eval2.encode('unicode_escape')
		save_planelist = eval(eval0)
		save_transplist = eval(eval1)
		save_pathlist = eval(eval2)
	else:
		filenm = {}
		state = {}
		return
	
	imagelist = []
	planelist = []
	transplist = []
	
	for i in range(len(save_planelist)):
		obj = save_planelist[i]
		planelist.append(obj)
		state[obj] = 2
	for i in range(len(save_transplist)):
		transplist.append(save_transplist[i])
	for i in range(len(save_pathlist)):
		bpy.ops.image.open(filepath = save_pathlist[i])
		imagename = os.path.basename(save_pathlist[i])
		image = bpy.data.images[imagename]
		image.gl_load(GL_NEAREST, GL_NEAREST)
		imagelist.append(imagename)
		filenm[planelist[i]] = save_pathlist[i]
		
