##################################################
#
#	Toe-in Stereo Camera for Blender 2.49b
#
#	Author: Sebastian Schneider                     
#	Web: http://www.noeol.de/s3d
#
#	Date: Sept. 2010
#
#	FREE TO USE
#
##################################################



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



# vars
DATA_DICT = {
	'CAM_SEPARATION': Create(0.65),
	'OWN_FOCAL_DIST': Create(10.0)
		}	
		


# 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, 300, 200)		# gui background
	glColor3f(0.75, 0.75, 0.75)	# light grey
	glRectf(5, 23, 300, 170)	# content background
	glColor3f(1, 1, 1)	
	glRasterPos2d(15, 180)
	Text("'Toein' Stereo Camera") # title
	
	# input fields
	DATA_DICT['CAM_SEPARATION']   = Number("Camera Separation: " ,  1, 15, 130, 275, 20, DATA_DICT['CAM_SEPARATION'].val, 0.01, 1000.0, "Distance between camera lenses', a higher value increases the stereo effect (Hyperstereoscopy)")
	DATA_DICT['OWN_FOCAL_DIST']   = Number("Focal Distance: "   ,  2, 15, 90, 275, 20, DATA_DICT['OWN_FOCAL_DIST'].val, 0.01, 1000.0, "Distance from camera to the projection plane (or 'stereo window') with zero parallax")
	# event button
	Button("Set Stereo Camera",3,15,40,275,24, "Adds a Toein Stereo Camera to the active camera in this scene (a Track-To Constraint will be deleted)")
	Button("Exit",4,254,175,36,18, "Quit the script")



# setting function
def set_toein_stereo_camera():
	
	stereo_base = DATA_DICT['CAM_SEPARATION'].val
	focal_distance = DATA_DICT['OWN_FOCAL_DIST'].val
	
	# get the scene
	scn = Scene.GetCurrent()
	
	# get the active camera object and data
	active_cam = scn.objects.camera
	active_cam_data = active_cam.getData()
	
	# save the active camera data
	old_active_cam_loc = active_cam.loc
	old_active_cam_rotX = active_cam.RotX
	old_active_cam_rotY = active_cam.RotY
	old_active_cam_rotZ = active_cam.RotZ
	old_active_cam_size = active_cam.size
	
	# delete a camera track-to constraint, to avoid camera-view-vector disorientation
	CamConstraints = active_cam.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	
	focalDistExists = 0
	for ob in scn.objects:
		if(ob.name == "Left_"+active_cam.name):
			leftCamExists = 1
		if(ob.name == "Right_"+active_cam.name):
			rightCamExists = 1
		if(ob.name == "Stereo_Window_"+active_cam.name):
			focalDistExists = 1		
	
	# add a new left camera object
	if(leftCamExists==0):
		c = Camera.New("persp")
		left_cam = Object.New("Camera", "Left_"+active_cam.name)
		left_cam.link(c)
		scn.objects.link(left_cam)
	else:
		left_cam = Blender.Object.Get("Left_"+active_cam.name)
	left_cam_data = left_cam.getData()
	left_cam_data.angle = active_cam_data.angle
	
	# add a new right camera object
	if(rightCamExists==0):
		c = Camera.New("persp")
		right_cam = Object.New("Camera", "Right_"+active_cam.name)
		right_cam.link(c)
		scn.objects.link(right_cam)
	else:
		right_cam = Blender.Object.Get("Right_"+active_cam.name)
	right_cam_data = right_cam.getData()
	right_cam_data.angle = active_cam_data.angle
	
	# add a plane to show the zero parallax at focal distance, this will be also the target for the left and right 'toein' cameras
	if(focalDistExists == 0):
		focal_dist_prim = Primitives.Plane(4.0)
		focal_dist_plane = Object.New("Mesh", "Stereo_Window_"+active_cam.name)
		focal_dist_plane.link(focal_dist_prim)
		scn.objects.link(focal_dist_plane)
	else:
		focal_dist_plane = Blender.Object.Get("Stereo_Window_"+active_cam.name)
	
	# set the 'real size' of the stereo window (focal distance plane)
	alpha = math.radians(active_cam_data.angle/2)
	beta  = math.radians(90-(active_cam_data.angle/2))
	sw_x = ((math.sin(alpha) * focal_distance) / math.sin(beta))
	sw_y = (scn.getRenderingContext().imageSizeY() * sw_x) / scn.getRenderingContext().imageSizeX()
	focal_dist_plane.SizeX = (sw_x)/2
	focal_dist_plane.SizeY = (sw_y)/2
	# do not render this plane
	focal_dist_plane.restrictRender = True
			
	# place the left and right cameras and their target (focal distance plane or 'stereo window')
	# 1. translate the active camera to the blender 3d orign
	active_cam.loc = (0,0,0)
	active_cam.rot = (0,0,0)
	active_cam.size = (1,1,1)
	# 2. stereobase translate and target rotation of the left and right camera 
	toein_angle = math.atan2((stereo_base/2), focal_distance) # <--- this is the simple trigonometric calculation for your camera rotation
	left_cam.loc = (-(stereo_base/2),0,0)
	left_cam.rot = (0,-toein_angle,0)
	left_cam.size = (1,1,1)
	right_cam.loc = ((stereo_base/2),0,0)
	right_cam.rot = (0,toein_angle,0)
	right_cam.size = (1,1,1)
	# 3. place the stereo window (toein camera target)
	focal_dist_plane.loc = (0,0,-focal_distance)
	# 4. parent the left and right cam to the active camera (= center camera)
	scn.update(1)
	active_cam.makeParent([left_cam, right_cam, focal_dist_plane],0,0)
	# 5. reset the active camera location	
	active_cam.loc = old_active_cam_loc
	active_cam.RotX = old_active_cam_rotX
	active_cam.RotY = old_active_cam_rotY
	active_cam.RotZ = old_active_cam_rotZ
	active_cam.size = old_active_cam_size
	
	# redraw the 3d window
	Window.RedrawAll()
	
	Redraw()
	

	
# button event		
def bevent(evt):
	if(evt == 3):
		set_toein_stereo_camera()
		set_toein_stereo_camera()
	if(evt == 4):
		Exit()
	# draw it			
	Redraw()	



# exit event
def event(evt, val):
	if(evt == QKEY and not val):
		Exit()


		
# register
Register(gui, event, bevent)