#!BPY

"""
Name: 'Pipmak Panoramas'
Blender: 248
Group: 'Wizards'
Tooltip: 'Render panoramas for each camera!'
"""

####TODO: calculate FOV for pipmak correctly!

#############################################################
#                                                           #
# Used to be:Blender Go Cubic                !              #
#                                                           #
# (C) February 2005 Stefano <S68> Selleri                   #
# Released under the Blender Artistic Licence (BAL)         #
# See www.blender.org                                       #
#                                                           #
# Adapted by macouno for full functionality                 #
#                                                           #
#############################################################
# History                                                   #
# V: 0.0.0 - 13-11-04 - Macouno published his clever tut    #
#                       on Panoramas, but I'm too lazy to   #
#                       set cameras by hand!                #
#    0.0.2 - 13-11-04 - A GUI!                              #
#    0.0.3 - 27-02-05 - Made the renderer reset all changes #
#                       it renames the files after render   #
#    0.0.4 - 04-03-05 - Included cylindrical render         #
#                       And made it get correct path data   #
#    0.0.5 - 05-03-05 - New UI functionalities, partial     #
#                       cubic renderings, Multiple pano     #
#                       settings.                           #
#    0.0.6 - 28-04-05 - ObjectMode                          #
#    0.0.7 - 14-05-05 - Limits to Object Mode, bugs         #
#    0.0.8 - 19-03-07 - Ported to 2.43 API                  #
#############################################################

import Blender
from Blender import *
import bpy
import os
import re
import math

#############################################################
# GLOBALS                                                   #
#############################################################
VERSION         ='0.0.7'

EVENTHASH = {
    'NOEVENT': 1,
    'REDRAW': 2,
    'EXIT': 3,
    'DO_CUB': 4,
    'EXPORT_CAMS':5,
    'BATCH_CUB':6,
    'CUB_ALL': 201,
    'CUB_NONE': 202,
    }


#############################################################
# Populate the menu                                         #
#############################################################

## Get scene data
cur = Scene.getCurrent()

## Get the current image render context
cntx = cur.getRenderingContext()

## Get the current frame
fra = cntx.currentFrame()

## Get the current file directory
base = Blender.Get('filename')
filename = base
dirx = Blender.sys.dirname(filename)

## Get the render path
pth1 = cntx.getRenderPath()

try:
    rel = re.search(r'\/\/',pth1).start()
except:
    rel = -1

if rel != -1:
    pthx = pth1[2:]    
    pthx = Blender.sys.join(dirx,pthx)
else:
    pthx = pth1

DATAHASH = {
    'SIZE': Draw.Create(500),
    'SIZEXC': Draw.Create(25),
    'SIZEXT': Draw.Create(1000),
    'SIZEYC': Draw.Create(500),
    'FRAME': Draw.Create(fra),
    'NAME': Draw.Create(pthx),
    'TYPE': Draw.Create(2),
    'PARTS': Draw.Create(40),

    'CF1': Draw.Create(1),
    'CF2': Draw.Create(1),
    'CF3': Draw.Create(1),
    'CF4': Draw.Create(1),
    'CF5': Draw.Create(1),
    'CF6': Draw.Create(1),

}

##### util for creating folder if it doesn't exist

def checkDir(full_path_name):
     if not os.path.isdir(full_path_name):
          os.mkdir(full_path_name)

##### util for getting all selected cameras

def getCameras():
	allObjects =  Blender.Object.GetSelected()
	thisList = []
	for thisObj in allObjects:
		if type(thisObj.getData()) == Types.CameraType:
			thisList.append(thisObj)
	return thisList

#############################################################
# Store Settings For later re-use                           #
#############################################################
def GetSettings(cntx):

    State = {}
    cntx = cur.getRenderingContext()
    
    State['Rpath'] = cntx.getRenderPath()

    State['SizeX'] = cntx.imageSizeX()
    State['SizeY'] = cntx.imageSizeY()
    State['aspectRatioX'] = cntx.aspectRatioX()
    State['aspectRatioY'] = cntx.aspectRatioY()
    State['partsX'] = cntx.partsX()
    State['partsY'] = cntx.partsY()

    State['Frame'] = cntx.currentFrame()
    State['startFrame'] = cntx.startFrame()
    State['endFrame'] = cntx.endFrame()

    State['CameraObj'] = cur.getCurrentCamera()
    State['CameraIpo'] = State['CameraObj'].getIpo()
    State['CameraDat'] = State['CameraObj'].getData()
    State['CameraLen'] = State['CameraDat'].getLens()
    State['CameraEul'] = State['CameraObj'].getEuler()

    return (State)

#############################################################
# Restore Settings                                          #
#############################################################
def SetSettings(cntx,State):

    cntx.setRenderPath(State['Rpath'])

    cntx.imageSizeX(State['SizeX'])
    cntx.imageSizeY(State['SizeY'])
    cntx.aspectRatioX(State['aspectRatioX'])
    cntx.aspectRatioY(State['aspectRatioY'])
    cntx.partsX(State['partsX'])
    cntx.partsY(State['partsY'])

    cntx.currentFrame(State['Frame'])
    cntx.startFrame(State['startFrame'])
    cntx.endFrame(State['endFrame'])

    cur.setCurrentCamera(State['CameraObj'])
    State['CameraObj'].setEuler(State['CameraEul'])
    try:
        State['CameraObj'].setIpo(State['CameraIpo'])
    except:
        State['CameraObj'].clearIpo()
    State['CameraDat'].setLens(State['CameraLen'])

    return ()

#############################################################
# set image stuff                                           #
#############################################################
def SetImage(cntx):
    global DATAHASH

    if DATAHASH['TYPE'].val == 1:
        cntx.setImageType(Scene.Render.JPEG)
        ext = '.jpg'
    elif DATAHASH['TYPE'].val == 3:
        cntx.setImageType(Scene.Render.TARGA)
        ext = '.tga'
    else:
        cntx.setImageType(Scene.Render.PNG)
        ext= '.png'

    ## enable extensions
    cntx.enableExtensions(1)

    return (ext)

#############################################################
# Export camera location data                               #
#############################################################
def ExportCameraLocations ():
    pthx = DATAHASH['NAME'].val
    checkDir(pthx)
    exportFile = open(pthx + os.sep + "camExport", "w")
    for cam in getCameras() :
        camName = cam.getName()
        loc = cam.getLocation()
        exportFile.write(camName + ':' + str(loc[0]) + ',' + str(loc[2]) + ',' + str(loc[1]) +  '\n');
    exportFile.close

#############################################################
# Perform single Render                                     #
#############################################################
def DoCubeFace (i,Ex,Ey,Ez,pthx,ext,frchk,Current):

    ## Set the render path
    checkDir(pthx)
    camName = Current['CameraObj'].getName()
    checkDir(pthx + os.sep + camName)
    pth2 = (pthx + os.sep + camName + os.sep + str(i))
    cntx.setRenderPath(pth2)

    ## Set the camera angle
    Current['CameraObj'].setEuler([Ex,Ey,Ez])
    cntx.renderAnim()

    ## Rename the rendered file
    newname = (pth2 + ext);
    oldname = (pth2 + frchk);
    if os.path.isfile(newname):
        os.remove(newname)
    os.rename(oldname, newname)
    print "Renamed "+oldname+" to "+newname

#############################################################
# SET FOR RENDER   CUBE                                     #
#############################################################

def RenderCub():

    ## Get the current image render context
    cntx = cur.getRenderingContext()

    ############################## GET THE CURRENT DATA
    Current = GetSettings(cntx)

    ########################## SET THE DATA
    ## Clear the Ipo
    Current['CameraObj'].clearIpo()

    ## Set render path
    pthx = DATAHASH['NAME'].val

    ## Set image extension
    ext = SetImage(cntx)

    ## Set frame numbers for file correction
    frchk = `DATAHASH['FRAME'].val`
    frnmbr = DATAHASH['FRAME'].val

    if frnmbr < 10:
        frchk = ('000' + frchk)
    elif frnmbr < 100:
        frchk = ('00' + frchk)
    elif frnmbr < 1000:
        frchk = ('0' + frchk)

    ## disable extensions
    cntx.enableExtensions(0)

    ## Set the aspect ratio
    cntx.aspectRatioX(1)
    cntx.aspectRatioY(1)

    ## Set the image render size
    cntx.imageSizeX(DATAHASH['SIZE'].val)
    cntx.imageSizeY(DATAHASH['SIZE'].val)

    ## Set the lens to 16.0
    Current['CameraDat'].setLens(16.0)

    ## Set the start and end frames
    cntx.startFrame(DATAHASH['FRAME'].val)
    cntx.endFrame(DATAHASH['FRAME'].val)

    ########################## first anim
    print "Starting Rendering Process *CUBIC*"

    if (DATAHASH['CF1'].val==1):
        DoCubeFace (1,math.pi/2.0,0.0,0.0,pthx,ext,frchk,Current)

    if (DATAHASH['CF2'].val==1):
        DoCubeFace (2,math.pi/2.0,0.0,-math.pi/2.0,pthx,ext,frchk,Current)

    if (DATAHASH['CF3'].val==1):
        DoCubeFace (3,math.pi/2.0,0.0,-math.pi,pthx,ext,frchk,Current)

    if (DATAHASH['CF4'].val==1):
        DoCubeFace (4,math.pi/2.0,0.0,-3.0*math.pi/2.0,pthx,ext,frchk,Current)

    if (DATAHASH['CF5'].val==1):
        DoCubeFace (5,math.pi,0.0,0.0,pthx,ext,frchk,Current)

    if (DATAHASH['CF6'].val==1):
        DoCubeFace (6,0.0,0.0,0.0,pthx,ext,frchk,Current)

    print "Rendered Cubic Panorama"

    #############################################################
    # RESET AFTER RENDER                                        #
    #############################################################
    SetSettings(cntx,Current)
    cntx.enableExtensions(1)


#############################################################
# Batch cubic render                                        #
#############################################################

def BatchCubic():
    for cam in getCameras() :
        cur.setCurrentCamera(cam)
        RenderCub()

#############################################################
# MAIN WINDOW                                               #
#############################################################
def MainWindow():
    global EVENTHASH,VERSION
    global DATA


    #############################################################
    # Backgrounds                                               #
    #############################################################

    BGL.glClearColor(0.5, 0.5, 0.5, 0.0)
    BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)

    BGL.glColor3f(0, 0, 0) 			# Black
    BGL.glRectf(2, 2, 380, 480)

    BGL.glColor3f(1, 0.9, 0.7) 			# Light blue
    BGL.glRectf(3, 3, 379, 479)

    BGL.glColor3f(0.3, 0.27, 0.35) 		# Dark purple 0
    BGL.glRectf(4, 4, 378, 95)

    BGL.glColor3f(0, 0, 0) 			# Black 0
    BGL.glRectf(4, 96, 378, 130)

    BGL.glColor3f(0.3, 0.27, 0.35) 		# Dark purple 1
    BGL.glRectf(4, 131, 378, 201)

    BGL.glColor3f(0, 0, 0) 			# Black 1
    BGL.glRectf(4, 202, 378, 236)

    BGL.glColor3f(0.3, 0.27, 0.35) 		# Dark purple 2
    BGL.glRectf(4, 237, 378, 292)

    BGL.glColor3f(0, 0, 0) 			# Black 2
    BGL.glRectf(4, 293, 378, 327)

    BGL.glColor3f(0.3, 0.27, 0.35) 		# Dark purple 3
    BGL.glRectf(4, 328, 378, 378)

    BGL.glColor3f(0, 0, 0) 			# Black 3
    BGL.glRectf(4, 379, 378, 413)

    BGL.glColor3f(0.3, 0.27, 0.35) 		# Dark purple 3
    BGL.glRectf(4, 414, 378, 443)

    BGL.glColor3f(0, 0, 0) 			# Black 4
    BGL.glRectf(4, 444, 378, 478)

    #############################################################
    # Common Header                                             #
    #############################################################

    BGL.glColor3f(1, 0.9, 0.7)
    BGL.glRasterPos2d(15, 457)
    Draw.Text("BGC - Blender Go Cube v. "+VERSION)
    BGL.glRasterPos2d(15, 425)
    Draw.Text("(C) 2005 Stefano Selleri <a.k.a. S68> and macouno")
    Draw.Button("EXIT", EVENTHASH['EXIT'], 319, 449, 50, 24, "Exit BGC")
    Draw.Button("GO", EVENTHASH['DO_CUB'], 319, 208, 50, 25, "Render cubic panorama for selected cam")
    Draw.Button("GO", EVENTHASH['EXPORT_CAMS'], 319, 298, 50, 25, "Export Locations of selected objects")
    Draw.Button("GO", EVENTHASH['BATCH_CUB'], 319, 102, 50, 25, "Render cubic panorama for all selected cams")

    #############################################################
    # General Screen                                            #
    #############################################################
    BGL.glColor3f(1, 0.9, 0.7)
    BGL.glRasterPos2d(15, 392)
    Draw.Text("General settings:")

    DATAHASH['FRAME'] =  Draw.Slider(
                        "Frame: ", EVENTHASH['NOEVENT'], 15, 354, 175, 18,
                        DATAHASH['FRAME'].val, 1, 18000, 0,
                        "The frame to render. Current frame is default")

    types = "Image type %t|JPG %x1|PNG %x2|Targa %x3"

    DATAHASH['TYPE'] = Draw.Menu(types, EVENTHASH['NOEVENT'],
                                 190, 354, 175, 18, DATAHASH['TYPE'].val,
                                 "The image type. Type will remain set after the script is closed.")

    DATAHASH['NAME'] =  Draw.String(
                        "Path: ", EVENTHASH['NOEVENT'], 15, 334, 350, 18,
                        DATAHASH['NAME'].val, 128,
                        "Complete path and an image name without extension")
    #############################################################
    # Point data export screen                                  #
    #############################################################
    BGL.glColor3f(1, 0.9, 0.7)
    BGL.glRasterPos2d(15, 306)
    Draw.Text("Export Selected Object Locations")
    BGL.glColor3f(1, 1, 1)

    #############################################################
    # Cubic Screen                                              #
    #############################################################
    BGL.glColor3f(1, 0.9, 0.7)
    BGL.glRasterPos2d(15, 215)
    Draw.Text("Cubic panorama settings:")
    BGL.glColor3f(1, 1, 1)

    #############################################################
    # Object Screen                                             #
    #############################################################
    BGL.glColor3f(1, 0.9, 0.7)
    BGL.glRasterPos2d(15, 109)
    Draw.Text("Cubic render all selected cameras")
    BGL.glColor3f(1, 1, 1)

    DATAHASH['SIZE'] =  Draw.Slider(
                        "Size: ", EVENTHASH['NOEVENT'], 15, 158, 240, 18,
                        DATAHASH['SIZE'].val, 4, 10000, 0,
                        "The image will be a square")

    ##### Toggles to switch on/off determined faces
    DATAHASH['CF1'] =   Draw.Toggle(
                        "1", EVENTHASH['NOEVENT'], 257, 158, 18, 18,
                        DATAHASH['CF1'].val,
                        "Render Face 1 (Front) Image ?")
    DATAHASH['CF2'] =   Draw.Toggle(
                        "2", EVENTHASH['NOEVENT'], 275, 158, 18, 18,
                        DATAHASH['CF2'].val,
                        "Render Face 2 (Right) Image ?")
    DATAHASH['CF3'] =   Draw.Toggle(
                        "3", EVENTHASH['NOEVENT'], 293, 158, 18, 18,
                        DATAHASH['CF3'].val,
                        "Render Face 3 (Back) Image ?")
    DATAHASH['CF4'] =   Draw.Toggle(
                        "4", EVENTHASH['NOEVENT'], 311, 158, 18, 18,
                        DATAHASH['CF4'].val,
                        "Render Face 4 (Left) Image ?")
    DATAHASH['CF5'] =   Draw.Toggle(
                        "5", EVENTHASH['NOEVENT'], 293, 176, 18, 18,
                        DATAHASH['CF5'].val,
                        "Render Face 5 (Top) Image ?")
    DATAHASH['CF6'] =   Draw.Toggle(
                        "6", EVENTHASH['NOEVENT'], 293, 140, 18, 18,
                        DATAHASH['CF6'].val,
                        "Render Face 6 (Bottom) Image ?")

    Draw.Button("All", EVENTHASH['CUB_ALL'], 257, 176, 36, 18,
                "Set all six renders to ON (Default)")

    Draw.Button("None", EVENTHASH['CUB_NONE'], 257, 140, 36, 18,
                "Set all six renders to OFF")


#############################################################
# Graphics                                                  #
#############################################################

def draw():
    MainWindow()

#############################################################
# Event Handler                                             #
#############################################################

def event(evt, val):
	if (evt== Draw.QKEY and not val):
		Draw.Exit()

def bevent(evt):
    global EVENTHASH,DATAHASH
    if   (evt == EVENTHASH['EXIT']):
        print 'EXIT'
        Draw.Exit()
    elif (evt == EVENTHASH['REDRAW']):
        Draw.Redraw()
    elif (evt == EVENTHASH['DO_CUB']):
        RenderCub()
        Draw.Redraw()
    elif (evt == EVENTHASH['EXPORT_CAMS']):
        ExportCameraLocations()
        Draw.Redraw()
    elif (evt == EVENTHASH['BATCH_CUB']):
        BatchCubic()
        Draw.Redraw()
    elif (evt == EVENTHASH['CUB_ALL']):
        DATAHASH['CF1'].val = 1
        DATAHASH['CF2'].val = 1
        DATAHASH['CF3'].val = 1
        DATAHASH['CF4'].val = 1
        DATAHASH['CF5'].val = 1
        DATAHASH['CF6'].val = 1
        Draw.Redraw()
    elif (evt == EVENTHASH['CUB_NONE']):
        DATAHASH['CF1'].val = 0
        DATAHASH['CF2'].val = 0
        DATAHASH['CF3'].val = 0
        DATAHASH['CF4'].val = 0
        DATAHASH['CF5'].val = 0
        DATAHASH['CF6'].val = 0
        Draw.Redraw()
        
#############################################################
# Registering all functions                                 #
#############################################################

Draw.Register(draw, event, bevent)
