#####################################################
#                                                   
#   Python Script Version 1.5 to setup an           
#   Off-Axis Stereo Camera in Blender 2.49          
#                                                   
#   to run this script press:  Alt + P              
#                                                   
#   Author: Sebastian Schneider                     
#   Web: http://www.noeol.de/s3d (incl. Tutorial)   
#                                                   
#   Save/Load Patch by Matteo De Simone             
#   Web: http://matteo.desimone.name                
#                                                   
#   Update: April 2010                              
#                                                   
#####################################################



import Blender
from Blender import *
from Blender.Draw import *
from Blender.BGL import *
from Blender.Scene import Render
from Blender.Mesh import Primitives
import types
import math



#
# GUI
#
def gui():


	#
	# backgrounds
	#
	glClearColor(0.5, 0.5, 0.5, 0.0)
	glClear(GL_COLOR_BUFFER_BIT)
	
	glColor3f(0.65, 0.65, 0.65)	# medium grey 
	glRectf(5, 5, 448, 590)		# gui background

	glColor3f(0.75, 0.75, 0.75)	# light grey
	glRectf(5, 23, 448, 559)	# content background

	glColor3f(0.85, 0.85, 0.85)	# white (almost)	
	glRectf(196, 312, 436, 293)	# focal distance result bg
	glRectf(196, 282, 436, 263)	# cam separation in blender units result bg	
	glRectf(196, 252, 436, 233)	# parallax at near plane bg
	glRectf(196, 222, 436, 203)	# parallax at far plane bg
	glRectf(196, 192, 436, 173)	# result l+r fov bg
	glRectf(196, 162, 436, 143)	# result extended render width bg

	glColor3f(0.96, 0.96, 0.96)	# white (almost)
	glRectf(196, 125, 252, 106)	# left image crop X1
	glRectf(196, 103, 252, 84)	# left image crop X2	
	glRectf(255, 125, 311, 106)	# left image crop Y1
	glRectf(255, 103, 311, 84)	# left image crop Y2
	glRectf(321, 125, 377, 106)	# right image crop X1
	glRectf(321, 103, 377, 84)	# right image crop X2
	glRectf(380, 125, 436, 106)	# right image crop Y1
	glRectf(380, 103, 436, 84)	# right image crop Y2


	#
	# script title
	#
	glColor3f(1, 1, 1)	
	glRasterPos2d(15, 569)
	Text("BStereoOffAxisCamera v.1.5")


	#
	# load/save button
	#
	Button("Load",1,313,565,60,19, "Load settings from file (in same directory as this .blend file)")
	Button("Save",2,381,565,60,19, "Save settings to file (in same directory as this .blend file)")

	
	#
	# input fields
	#
	DATA_DICT['CAM_SEPARATION']   = Number("Camera Separation: " ,  3, 15, 520, 423, 20, DATA_DICT['CAM_SEPARATION'].val, 1, 10000, "Distance between camera lenses', a higher value increases the stereo effect (Hyperstereoscopy)")
	DATA_DICT['MAX_DEVIATION']    = Number("Deviation Rule: 1/"  ,  4, 15, 490, 423, 20, DATA_DICT['MAX_DEVIATION'].val, 1, 100, "Simple stereoscopic rule (Camera Separation should be 1/30 of the distance to the projection plane with zero parallax)")
	DATA_DICT['FINAL_FOV']        = Number("Final Camera FoV: "  ,  5, 15, 460, 423, 20, DATA_DICT['FINAL_FOV'].val, 7.32, 172.85, "Intended horizontal camera aperture in degree")
	DATA_DICT['FINAL_WIDTH']      = Number("Final Render Width: ",  6, 15, 430, 423, 20, DATA_DICT['FINAL_WIDTH'].val, 1, 10000, "Final stereo image width in pixel")
	DATA_DICT['NEAR_PLANE_DIST']  = Number("Near Plane Distance: ", 7, 15, 400, 208, 20, DATA_DICT['NEAR_PLANE_DIST'].val, 0.01, 1000.00, "Distance from camera to near plane. Place this plane right before your first object seen by the camera. (Default: camera.clipStart is always too close)")
	DATA_DICT['FAR_PLANE_DIST']   = Number("Far Plane Distance: " , 8,230, 400, 208, 20, DATA_DICT['FAR_PLANE_DIST'].val, 0.01, 1000.00, "Distance from camera to far plane. Place this plane right behind your last object seen by the camera. (Default: camera.clipEnd)")
	DATA_DICT['USE_THIS_FO_DIST'] = Toggle("use this:"          ,   9, 15, 370,  60, 20, DATA_DICT['USE_THIS_FO_DIST'].val, "Toggle this on, to set your own distance between camera and projection plane with zero parallax (Deviation rule will be disabled)")
	DATA_DICT['OWN_FOCAL_DIST']   = Number("Focal Distance: "   ,  10, 75, 370, 363, 20, DATA_DICT['OWN_FOCAL_DIST'].val, 0.01, 1000.00, "Distance from camera to the projection plane (or 'stereo window') with zero parallax")

	
	#
	# calculate button
	#
	Button("Calculate",11,196,330,239,20,"Only calculate the stereo parameter")

	
	#
	# focal distance (zero prallax) 
	#
	glColor3f(0, 0, 0)	
	glRasterPos2d(15, 299)	
	Text(DATA_DICT['FOCAL_DISTANCE'].val)
	
	
	#
	# show zero parallax plane button to visualize the stereo window
	#
	DATA_DICT['ZERO_PLANE'] = Toggle("show it", 12, 375, 294, 60, 18, DATA_DICT['ZERO_PLANE'].val, "Shows the 'stereo window' as a plane (after press 'Set Stereo Camera')")	

	
	#
	# camera separation
	#
	glRasterPos2d(77, 269)	
	Text(DATA_DICT['CAM_SEPAR_BU'].val)


	#
	# show the left and right camera to visualize the stereo base
	#
	DATA_DICT['SHOW_BASE'] = Toggle("show it", 13, 375, 264, 60, 18, DATA_DICT['SHOW_BASE'].val, "Shows the left and right camera to visualize the stereo base (after press 'Set Stereo Camera')")

	
	#
	# parallax at near plane 
	#
	glRasterPos2d(58, 239)	
	Text(DATA_DICT['NEAR_PLANE_PARALLAX'].val)
	
	
	#
	# show the near plane
	#
	DATA_DICT['NEAR_PLANE'] = Toggle("show it", 14, 375, 234, 60, 18, DATA_DICT['NEAR_PLANE'].val, "Shows the Near Plane (after press 'Set Stereo Camera')")	

	
	#
	# parallax at far plane
	#
	glRasterPos2d(66, 209)	
	Text(DATA_DICT['FAR_PLANE_PARALLAX'].val)


	#
	# show the far plane
	#
	DATA_DICT['FAR_PLANE'] = Toggle("show it", 14, 375, 204, 60, 18, DATA_DICT['FAR_PLANE'].val, "Shows the Far Plane (after press 'Set Stereo Camera')")

	
	#
	# left and right camera FoV
	#
	glRasterPos2d(87, 179)	
	Text(DATA_DICT['CAM_FOV'].val)


	#
	# extended render width
	#
	glRasterPos2d(53, 149)	
	Text(DATA_DICT['EXTEND_WIDTH'].val)
	
	
	#
	# image crop-node parameters
	#
	glRasterPos2d(15, 102)	
	Text("Image Crop-Node Parameters =")
	
	
	#
	# left
	#
	glRasterPos2d(245, 129)	
	Text("Left",'small')	
	
	
	#
	# right
	#	
	glRasterPos2d(364, 129)	
	Text("Right",'small')


	#
	# left image crop-node X1
	#
	glRasterPos2d(198, 112)	
	Text(DATA_DICT['CROP_LEFT_X1'].val)	


	#
	# left image crop-node X2
	#
	glRasterPos2d(198, 90)	
	Text(DATA_DICT['CROP_LEFT_X2'].val)
	
	
	#
	# left image crop-node Y1
	#
	glRasterPos2d(257, 112)	
	Text(DATA_DICT['CROP_LEFT_Y1'].val)	


	#
	# left image crop-node Y2
	#
	glRasterPos2d(257, 90)	
	Text(DATA_DICT['CROP_LEFT_Y2'].val)


	#
	# right image crop-node X1
	#
	glRasterPos2d(323, 112)	
	Text(DATA_DICT['CROP_RIGHT_X1'].val)	


	#
	# right image crop-node X2
	#
	glRasterPos2d(323, 90)	
	Text(DATA_DICT['CROP_RIGHT_X2'].val)
	
	
	#
	# right image crop-node Y1
	#
	glRasterPos2d(382, 112)	
	Text(DATA_DICT['CROP_RIGHT_Y1'].val)	


	#
	# right image crop-node Y2
	#
	glRasterPos2d(382, 90)	
	Text(DATA_DICT['CROP_RIGHT_Y2'].val)


	#
	# link objects
	#
	DATA_DICT['LINK_OBJECTS'] = Toggle("link objects", 16, 102, 42, 80, 20, DATA_DICT['LINK_OBJECTS'].val, "Links all objects to a (new) left and right camera scene")
	
	
	#
	# set stereo camera
	#
	Button("Set Stereo Camera",17,196,40,239,24, "Calculate and set the stereo parameter for the active camera in this scene (a Track-To Constraint will be deleted)")
	
	
	#
	# error text
	#
	glColor3f(0.791, 0.023, 0.023)
	glRasterPos2d(151, 28)	
	Text(DATA_DICT['WRONG_CAM_INFO'].val,'small')
	
	
	#
	# weblink
	#
	glColor3f(1, 1, 1)
	glRasterPos2d(15, 11)	
	Text("(c) 2010 www.noeol.de/s3d")
	
	
	#
	# quit
	#
	glRasterPos2d(351, 11)	
	Text("Press Q to exit")		


#
# GUI end
#



###############################
#                             
# Off-Axis stereo calculation 
#                             
###############################
def stereo_calculation():
	
	
	global delta, fo, stereobase, sizeY, fov2 # global vars for set_stereo_camera() 
	
	
	#
	# focal distance (zero parallax)	
	#
	if(DATA_DICT['USE_THIS_FO_DIST'].val == 1):
		# use user focal distance:
		fo = DATA_DICT['OWN_FOCAL_DIST'].val
	else:
		# 1/30 rule:
		fo = (float(DATA_DICT['CAM_SEPARATION'].val)/1000)*DATA_DICT['MAX_DEVIATION'].val
	
	
	#
	# write the focal distance in blender units
	#
	DATA_DICT['FOCAL_DISTANCE'].val = "Focal Distance (zero parallax) = "+str(round(fo,2))+" B.U."
	
	
	#
	# write camera separation 'stereobase' in blender units
	#
	stereobase = float(DATA_DICT['CAM_SEPARATION'].val)/1000
	DATA_DICT['CAM_SEPAR_BU'].val = "Camera Separation = "+str(stereobase)+" B.U."
	
		
	#	
	# calculate delta in pixel at the zero parallax plane
	#
	delta = ( DATA_DICT['FINAL_WIDTH'].val * (float(DATA_DICT['CAM_SEPARATION'].val)/1000) ) / ( 2 * fo * math.tan(math.radians(DATA_DICT['FINAL_FOV'].val / 2)) )
	delta = int(round(delta)) 
	
	
	#
	# calculate FoV' in degree for the left and right camera
	#	
	fov2 = math.degrees(2*math.atan( (DATA_DICT['FINAL_WIDTH'].val+delta) * (math.tan(math.radians(DATA_DICT['FINAL_FOV'].val / 2))) / DATA_DICT['FINAL_WIDTH'].val ))
	
	
	#
	# write the results (delta and FoV')
	#
	DATA_DICT['CAM_FOV'].val = "L+R Camera FoV = "+str(round(fov2,3))+" Degree"
	DATA_DICT['EXTEND_WIDTH'].val = "Extended Render Width = "+str(delta+DATA_DICT['FINAL_WIDTH'].val)+" Pixel"
	
	
	#
	# write the crop-node parameters
	#
	scn = Scene.GetCurrent()
	renderContext = scn.getRenderingContext()
	sizeY = renderContext.imageSizeY()	
	DATA_DICT['CROP_LEFT_X1'].val = "X1: "+str(delta)
	DATA_DICT['CROP_LEFT_X2'].val = "X2: "+str((DATA_DICT['FINAL_WIDTH'].val+delta)-1)
	DATA_DICT['CROP_LEFT_Y1'].val = "Y1: 0"
	DATA_DICT['CROP_LEFT_Y2'].val = "Y2: "+str((sizeY)-1)
	DATA_DICT['CROP_RIGHT_X1'].val = "X1: 0"
	DATA_DICT['CROP_RIGHT_X2'].val = "X2: "+str((DATA_DICT['FINAL_WIDTH'].val)-1)
	DATA_DICT['CROP_RIGHT_Y1'].val = "Y1: 0"
	DATA_DICT['CROP_RIGHT_Y2'].val = "Y2: "+str((sizeY)-1)	
	

	#
	# near plane pixel parallax calculation
	#
	near_delta = ( DATA_DICT['FINAL_WIDTH'].val * (float(DATA_DICT['CAM_SEPARATION'].val)/1000) ) / ( 2 * DATA_DICT['NEAR_PLANE_DIST'].val * math.tan(math.radians(DATA_DICT['FINAL_FOV'].val / 2)) )
	near_delta = abs( int(round(near_delta))-delta )
	
	
	#
	# far plane pixel parallax calculation
	#
	far_delta = ( DATA_DICT['FINAL_WIDTH'].val * (float(DATA_DICT['CAM_SEPARATION'].val)/1000) ) / ( 2 * DATA_DICT['FAR_PLANE_DIST'].val * math.tan(math.radians(DATA_DICT['FINAL_FOV'].val / 2)) )
	far_delta = abs( int(round(far_delta))-delta )
	
	
	#
	# theta calculation
	#
	viewer_dist = 20.0 # inch
	ppi = 96.0 # monitor pixel per inch
	near_theta = round( math.degrees(2*math.atan( float(near_delta/ppi) / float(2*viewer_dist) ) ) , 2 )
	far_theta  = round( math.degrees(2*math.atan( float(far_delta/ppi) / float(2*viewer_dist) ) ) , 2 ) 
	
	
	#
	#  is theta ok or too high?
	#
	if(near_theta < 1.0):
		near_theta_status = "nice"
	else:
		near_theta_status = "hard to fuse"
			
	if(far_theta < 1.0):
		far_theta_status = "nice"
	else:
		far_theta_status = "hard to fuse"		
	
	
	#
	# write the results (parallax at near/far plane in pixel and theta)
	#
	DATA_DICT['NEAR_PLANE_PARALLAX'].val = "Parallax at Near Plane = "+str(near_delta)+" Pixel ("+str(near_theta)+"="+near_theta_status+")"
	DATA_DICT['FAR_PLANE_PARALLAX'].val = "Parallax at Far Plane = "+str(far_delta)+" Pixel ("+str(far_theta)+"="+far_theta_status+")"
	

	#
	# redraw the gui and show the results
	#
	Redraw()


#
# stereo_calculation() end
#


	
###################################
#                                 
# Configure the stereo camera rig 
#                                 
###################################
def set_stereo_camera():
	
	
	#
	# get the current scene
	#
	scn = Scene.GetCurrent()
	
	
	#
	# get the current camera
	#
	curCam = scn.objects.camera
	curCamData = curCam.getData()
	
	
	#
	# check the current(active) camera, should not be a left or right camera
	#
	if(curCam.name[:4]=="Left" or curCam.name[:5]=="Right"):

		#
		# show a info
		#
		DATA_DICT['WRONG_CAM_INFO'].val = "Your active camera is already a Left- or Right Stereo Camera."

	else:

		#
		# do the settings
		#
		
		
		DATA_DICT['WRONG_CAM_INFO'].val = " " # clear the error string

		
		#
		# save the cameraData
		#
		oldCamLocation = curCam.loc
		oldCamRotationX = curCam.RotX
		oldCamRotationY = curCam.RotY
		oldCamRotationZ = curCam.RotZ
		oldCamSize = curCam.size
		
		
		#
		# delete a camera track-to constraint, to avoid camera-view-vector disorientation
		#
		CamConstraints = curCam.constraints
		CamConstLen = CamConstraints.__len__()
		if(CamConstLen > 0):
			for	CamConst in CamConstraints:
				if(CamConst.type == Constraint.Type.TRACKTO):
					curCam.constraints.remove(CamConst)
		
		
		#
		# check for a left/right camera, a near/zero/far parallax empty/plane 
		#
		leftCamExists = 0
		rightCamExists = 0
		zeroEmptyExists = 0
		zeroPlaneExists = 0
		camEmptyExists = 0
		nearPlaneExists = 0
		farPlaneExists = 0
		for ob in scn.objects:
			if(ob.name == "Left"+curCam.name):
				leftCamExists = 1
			if(ob.name == "Right"+curCam.name):
				rightCamExists = 1
			if(ob.name == curCam.name+"ZeroParallax"):
				zeroEmptyExists = 1
			if(ob.name == curCam.name+"ZeroPlane"):
				zeroPlaneExists = 1
			if(ob.name == curCam.name+"StereoCenter"):
				camEmptyExists = 1	
			if(ob.name == curCam.name+"NearPlane"):
				nearPlaneExists = 1
			if(ob.name == curCam.name+"FarPlane"):
				farPlaneExists = 1			
			
			
		#	
		# add a new left camera (or not)
		#
		if(leftCamExists==0):
			c = Camera.New("persp")
			leftCam = Object.New("Camera", "Left"+curCam.name)
			leftCam.link(c)
			scn.objects.link(leftCam)
			leftCamData = leftCam.getData()
		else:
			leftCam = Blender.Object.Get("Left"+curCam.name)
			leftCamData = leftCam.getData()
		
		
		#
		# add a new right camera (or not)
		#
		if(rightCamExists==0):
			c = Camera.New("persp")
			rightCam = Object.New("Camera", "Right"+curCam.name)
			rightCam.link(c)
			scn.objects.link(rightCam)
			rightCamData = rightCam.getData()
		else:
			rightCam = Blender.Object.Get("Right"+curCam.name)
			rightCamData = rightCam.getData()
	
	
		#
		# add an empty to show the zero parallax distance (or not)
		#
		if(zeroEmptyExists==0):
			zeroEmpty = Object.New("Empty", curCam.name+"ZeroParallax")
			scn.objects.link(zeroEmpty)
		else:
			zeroEmpty = Blender.Object.Get(curCam.name+"ZeroParallax")
		
		
		#	
		# add a plane to show the stereo window at zero parallax
		#
		if(zeroPlaneExists==0):
			zeroPlane_prim = Primitives.Plane(4.0)
			zeroPlane = Object.New("Mesh", curCam.name+"ZeroPlane")
			zeroPlane.link(zeroPlane_prim)
			scn.objects.link(zeroPlane)
		else:
			zeroPlane = Blender.Object.Get(curCam.name+"ZeroPlane")
		
		
		#
		# set the 'real size' of the stereo window at zero parallax
		#
		alpha = math.radians(DATA_DICT['FINAL_FOV'].val/2)
		beta  = math.radians(90-(DATA_DICT['FINAL_FOV'].val/2))
		sw_x = ((math.sin(alpha)*fo) / math.sin(beta))
		sw_y = (sizeY * sw_x) / DATA_DICT['FINAL_WIDTH'].val
		zeroPlane.SizeX = (sw_x)/2
		zeroPlane.SizeY = (sw_y)/2	
		
		
		#	
		# add a near plane
		#
		if(nearPlaneExists==0):
			nearPlane_prim = Primitives.Plane(4.0)
			nearPlane = Object.New("Mesh", curCam.name+"NearPlane")
			nearPlane.link(nearPlane_prim)
			scn.objects.link(nearPlane)
		else:
			nearPlane = Blender.Object.Get(curCam.name+"NearPlane")
		
		
		#
		# set the 'real size' of the near plane
		#
		alpha = math.radians(DATA_DICT['FINAL_FOV'].val/2)
		beta  = math.radians(90-(DATA_DICT['FINAL_FOV'].val/2))
		sw_x = ((math.sin(alpha) * DATA_DICT['NEAR_PLANE_DIST'].val) / math.sin(beta))
		sw_y = (sizeY * sw_x) / DATA_DICT['FINAL_WIDTH'].val
		nearPlane.SizeX = (sw_x)/2
		nearPlane.SizeY = (sw_y)/2
		
		
		#	
		# add a far plane
		#
		if(farPlaneExists==0):
			farPlane_prim = Primitives.Plane(4.0)
			farPlane = Object.New("Mesh", curCam.name+"FarPlane")
			farPlane.link(nearPlane_prim)
			scn.objects.link(farPlane)
		else:
			farPlane = Blender.Object.Get(curCam.name+"FarPlane")
		
		
		#
		# set the 'real size' of the far plane
		#
		alpha = math.radians(DATA_DICT['FINAL_FOV'].val/2)
		beta  = math.radians(90-(DATA_DICT['FINAL_FOV'].val/2))
		sw_x = ((math.sin(alpha) * DATA_DICT['FAR_PLANE_DIST'].val) / math.sin(beta))
		sw_y = (sizeY * sw_x) / DATA_DICT['FINAL_WIDTH'].val
		farPlane.SizeX = (sw_x)/2
		farPlane.SizeY = (sw_y)/2
				
		
		#
		# add an empty for the current (activ) camera, IPO [Bugfix]
		#
		if(camEmptyExists==0):
			camEmpty = Object.New("Empty", curCam.name+"StereoCenter")
			scn.objects.link(camEmpty)
		else:
			camEmpty = Blender.Object.Get(curCam.name+"StereoCenter")


		#
		# before linking all objects, make the zero/near/far parallax plane and the camera empty invisible
		#
		zeroPlane.layers = []
		nearPlane.layers = []
		farPlane.layers = []
		camEmpty.layers = []


		#
		# translate/rotate/scale all stereo-objects at the scene orign
		#
		camEmpty.loc = (0,0,0)
		camEmpty.rot = (0,0,0)
		camEmpty.size = (1,1,1)		
		
		curCam.loc = (0,0,0)
		curCam.rot = (0,0,0)
		curCam.size = (1,1,1)

		leftCam.loc = (-(stereobase/2),0,0)
		leftCam.rot = (0,0,0)
		leftCam.size = (1,1,1)
		
		rightCam.loc = ((stereobase/2),0,0)
		rightCam.rot = (0,0,0)
		rightCam.size = (1,1,1)
		
		zeroEmpty.loc = (0,0,-(round(fo,3)))
		zeroEmpty.rot = (0,0,0)
		zeroEmpty.size = (1,1,1)
	
		zeroPlane.loc = (0,0,-(round(fo,3)))
		zeroPlane.rot = (0,0,0)	
	
		nearPlane.loc = (0,0,-(DATA_DICT['NEAR_PLANE_DIST'].val))
		nearPlane.rot = (0,0,0)	
		
		farPlane.loc = (0,0,-(DATA_DICT['FAR_PLANE_DIST'].val))
		farPlane.rot = (0,0,0)	
		
	
		#
		# set the new FoV for the center,left and right camera
		#
		curCamData.angle = DATA_DICT['FINAL_FOV'].val
		leftCamData.angle = fov2
		rightCamData.angle = fov2
	
	
		#
		# check for a active camera with IPO [Bugfix]
		#
		curCamIpo = curCam.getIpo()
		if(curCamIpo != None):
			#
			# curCam has an IPO:		
			#
			scn.update(1)	
			
			#
			# parenting all stereo objects to the center camera empty
			#			
			camEmpty.makeParent([leftCam, rightCam, zeroEmpty, zeroPlane, nearPlane, farPlane], 0, 0)
			
			camEmpty.loc = oldCamLocation
			camEmpty.RotX = oldCamRotationX
			camEmpty.RotY = oldCamRotationY
			camEmpty.RotZ = oldCamRotationZ
			camEmpty.size = oldCamSize
				
			curCam.makeParent([camEmpty], 0, 0)
		else:
			#
			# curCam has no IPO:
			#
			scn.update(1)
			
			#
			# parenting all stereo objects to the center camera empty
			#
			curCam.makeParent([leftCam, rightCam, zeroEmpty, zeroPlane, camEmpty, nearPlane, farPlane], 0, 0)
				
			# reset original Loc/Rot/Size
			curCam.loc = oldCamLocation
			curCam.RotX = oldCamRotationX
			curCam.RotY = oldCamRotationY
			curCam.RotZ = oldCamRotationZ
			curCam.size = oldCamSize
		
		
		#
		# set new extended render width
		#
		context = scn.getRenderingContext() 
		context.imageSizeX(delta+DATA_DICT['FINAL_WIDTH'].val)


		#
		# create the left/right Blender Scene and link all objects into it 
		#
		if(DATA_DICT['LINK_OBJECTS'].val == 1):
			#
			# add or get left and right scene		
			#
			try:
				scnRight = Scene.Get('Right_Stereo_Cam')
			except:
				scnRight = scn.copy(0)
				scnRight.setName('Right_Stereo_Cam')
		
			try:
				scnLeft = Scene.Get('Left_Stereo_Cam')
			except:
				scnLeft = scn.copy(0)
				scnLeft.setName('Left_Stereo_Cam')

			#
			# link all objects into it
			#
			for obj in scn.objects:
				try:
					scnRight.link(obj)
					scnLeft.link(obj)
				except:
					print 'object already in scene'		
		
			#
			# set the active camera in the left/right scenes			
			#
			for obj in scnRight.objects:
				if(obj.name=="Right"+curCam.name):
					scnRight.objects.camera = obj
			
			for obj in scnLeft.objects:		
				if(obj.name=="Left"+curCam.name):
					scnLeft.objects.camera = obj
					

		#
		# show the zero parallax plane in the curCam layers or not
		#
		if(DATA_DICT['ZERO_PLANE'].val==1):
			zeroPlane.layers = curCam.layers
		else:
			zeroPlane.layers = [] #invisible
			
			
		#
		# show the near plane in the curCam layers or not
		#
		if(DATA_DICT['NEAR_PLANE'].val==1):
			nearPlane.layers = curCam.layers
		else:
			nearPlane.layers = [] #invisible
			
			
		#
		# show the far plane in the curCam layers or not
		#
		if(DATA_DICT['FAR_PLANE'].val==1):
			farPlane.layers = curCam.layers
		else:
			farPlane.layers = [] #invisible
			
		
		#
		# hide/unhide the left and right camera in the main scene
		#
		if(DATA_DICT['SHOW_BASE'].val==0):
			leftCam.layers = []
			rightCam.layers = []
			camEmpty.layers = []
		else:
			leftCam.layers = curCam.layers
			rightCam.layers = curCam.layers
			camEmpty.layers = curCam.layers
			

	#
	# redraw the 3d window too
	#
	Window.RedrawAll() 


	#
	# draw the gui
	#
	Redraw()


#
# set_stereo_camera() end
#



#
# define the name of this Blender file
#
def get_data_file_name():
	blender_file_name = Blender.Get('filename')
	if blender_file_name == "":
		blender_file_name = "unknown"	

	scn = Scene.GetCurrent()
	camera_name = scn.objects.camera.getName()

	return blender_file_name+"."+camera_name+".txt"


#
# Load input data
#
def load_data():
	
	file_name = get_data_file_name()
	
	print "Loading "+file_name+"..."
	
	try:
		file = open(file_name,'r')
	except:
		print "No such file or directory"
		return 0
	
	for line in file.readlines():
		(k,v) = line.split("\t")
		
		data_type = type(DATA_DICT[k].val)
		value = v
		
		if  data_type == types.StringType:
			value = v
		elif data_type == types.IntType:
			value = int(v)
		elif data_type == types.FloatType:
			value = float(v)
		elif data_type == types.LongType:
			value = long(v)
		elif data_type == types.NoneType:
			value = None
		else:
			print "k is a "+ str(data_type)
			
		DATA_DICT[k].val = value
		
		#print k +"=" +str(value)
	
	file.close()

	print "Done!"



#
# Save input data
#		
def save_data():
	
	file_name = get_data_file_name()
	print "Saving "+file_name+"..."
	
	try:
		file = open(file_name,'w+')
	except:
		print "file error, no data saved"
		return 0
	
	for k,v in DATA_DICT.items():
		file.write(k+"\t")		
		if type(v.val) != types.StringType:
			file.write(str(v.val))
		file.write("\n")
		
	
	file.close()

	print "data saved"



#
# exit event handler 
#
def event(evt, val):
	if(evt == QKEY and not val):
		Exit()



#
# button event handler
#		
def bevent(evt):
	if(evt == 11):
		stereo_calculation()
	elif(evt == 17):
		stereo_calculation()
		set_stereo_camera()
		set_stereo_camera()
	elif (evt==1):
		if load_data() != 0:
			stereo_calculation()
	elif (evt==2):
		name = "Write file ?%t|No %x0|Yes %x1"
		result = Blender.Draw.PupMenu(name)
		if result==1:
			save_data()	

	# draw it			
	Redraw()		

		

#
# get some initial values for this script
#	

scn = Scene.GetCurrent()
renderContext = scn.getRenderingContext()
initRenderWidth = renderContext.imageSizeX() # render width in pixel

curCam = scn.objects.camera
curCamData = curCam.getData()
initCamFov = curCamData.angle # camera Field of View
initClipStart = curCamData.getClipStart() # camera clip start
initClipEnd = curCamData.getClipEnd() # camera clip end


#
# store all parameters in DATA_DICT
#
DATA_DICT = {
	'CAM_SEPARATION': Create(65),
	'MAX_DEVIATION': Create(30),
	'FINAL_FOV': Create(initCamFov),
	'FINAL_WIDTH': Create(initRenderWidth),
	'FOCAL_DISTANCE': Create("Focal Distance (zero parallax) = "),
	'CAM_SEPAR_BU': Create("Camera Separation = "),
	'CAM_FOV': Create("L+R Camera FoV = "),
	'EXTEND_WIDTH': Create("Extended Render Width = "),
	'CROP_LEFT_X1': Create(""),
	'CROP_LEFT_X2': Create(""),
	'CROP_LEFT_Y1': Create(""),
	'CROP_LEFT_Y2': Create(""),
	'CROP_RIGHT_X1': Create(""),
	'CROP_RIGHT_X2': Create(""),
	'CROP_RIGHT_Y1': Create(""),
	'CROP_RIGHT_Y2': Create(""),
	'WRONG_CAM_INFO': Create(""),
	'USE_THIS_FO_DIST': Create(0),
	'OWN_FOCAL_DIST': Create(0.0),
	'NEAR_PLANE_DIST': Create(initClipStart),
	'FAR_PLANE_DIST': Create(initClipEnd),
	'LINK_OBJECTS': Create(1),
	'ZERO_PLANE': Create(0),
	'SHOW_BASE': Create(0),
	'NEAR_PLANE': Create(0),
	'FAR_PLANE': Create(0),
	'NEAR_PLANE_PARALLAX': Create("Parallax at Near Plane = "),
	'FAR_PLANE_PARALLAX': Create("Parallax at Far Plane = ")
		}



#
# register all
#		
Register(gui, event, bevent)