TheShowResult = True
TheFramesPerSecond = 5
TheImageWidth = 640
TheImageHeight = 480
TheSkipLastTurntableFrameImages = False
TheSkipLastTurntableFrameMovies = True
TheUseRaytracing = False
TheAntiAliasing = 4
TheRaytracingSampling = 4
TheRaytracingPreset = ('02-InteractiveShadows.xml', u'Shadows - Interactive', 1)
__all__ = ['SaveBehaviorAsMovieCustom', 'instantiate']
from MessageInterpreter import MessageInterpreter
from ScriptRunner import ScriptRunner
from UserCustomization import UserCustomBase
from GenericPopupMenu import GenericPopupMenuItem
from ConfirmDialog import ConfirmDialog
import BehaviorIO
import wx, os, glob, base64
TheRotator = "Q1dTCQoIAAB4nH1VfVMTRxjf3Xt5chcIAcKBASRoFA1IDvGV1ipisGLSWAPKdCZ6R7Ih59wL3l0y8F+HT1Cn//WfOvWD2I8QmSn9Cp1+Cbp7Fx1pO+7knt19Xn77vGV3H8n3EBr5HaEBjB4MJxBCa+Tk5OT9WJItMao1qEtzSwi9z/wCnMFGGi3yaXugZZtBe5F2qRsGUolPSOx6VnO6Znbpfdo2u5bnrwYVr2vRtU4Qes5LZjJQMS1303Kobbl0MMZoWsGebR4osapt7RW+CLHyOYRiOeYuLVtBKK36vnkAtmc2tx1biaFdGipbT8tlxqS+4nidgDpel8o+fc2UVCZ6Sl93aBDKLd906JLCzSkHmG2H4d5KsWg2vR262PCc4mptuXhV128UdzqWHVpuMhZ1QssORuPjzEaDBoG1Y9lWePAxQ77v+UGqv9kPqe+adj/yFgOifqDGu13qOcl46dCmZfZt9nzLZcftftp6zIz6fYjAdPbYrn9YcBCE1Onjhey0RLzsWH3gyNt+cvYde/xUBVY+VSBzml9jPoQ0f5r5IJ6rO69oI1zz3JCVhfozp5UeuSxAsxFaXRorTn4BZOrznlqJeorLzbDRpr4c60DXYgm2qWxTdzdsixUzbAssQXJU3G0pCFk/qBF9bjWZzDH3Bcdyhe1KWWyaoSlFHSPyHEpR0eW4O0Re+oTZbK61Lbsp7nWCthQy12lqzXRdL8xxee7OHTI/L5V4TSUaU+5mgsO5DAy/wrbAEkv812SzLJm2teuC69Uapk2VgNOK16Rq5EPAK5BYq1aelEubpTQ7OgqZNzP73/lqhUcUsdRKdatWelmpPitd3nJNFn4u9HI+NW37IPbLj9uYNnNNr9FxmM1iigGu8wBrDd/aC4f+lc/BU6kf/k+htP+vrxz3wjkNa4ImaTChaIPjkoQklMhoY5qmjWsT2hktq01qU9q0dlab0XLarHZOO59VsvnshezF7Fz2UvZytkBmE0QRQE0OiIM4NZQelkdGM2Pa+MQZKTs5NX12Jje7ApgAEUGQQUwAUYEkgQyAnAIyBCQN8jDACJDRSazMYyALQK4AWQRSBKIDWQJyFcgykGtAris3cOomTt3CIN5WVpjyV6B+DeSOssDW94CsAtwHWAN4AFACuAWwDvAQyCMgj4FUgHwHuArkCZAVIE+BFADXQNwEcQvEZyA+l1F0ZbI7EhOMCNvwLx5YEBMSEmUJIRmxizSBFKapIpTkF68wGOljialhpoCxogo9/SFjgaAmH/f0PDo8Tg8ipBjSUSs1Zw4dvTk8PjKkVnrs75MTQzKGjeE8qo/0WqNGpjX2jkt+Wx/B6xrhy5/Xx0krddEcYpBEEJPpv3BPf1441imePXSEiIoRlSMKFH9wMMX1CQNaZzYm8I8TDqGYeeFI6Z+YG5QJbdLKMiq1Uq3JCOQUaypCrCfZVthI4gi5Pr0xjSJ0m39y9Sy3ARZOj8/VGWxI0SKH0zMI9fQj/QdU+LOgzzu4PrvwDcd6u3D3bXUWTycEftCbQ4rnHW4kxaevn0NjL3lG8igOGDd/xe/w+TxcYGlFF5GA0BxrVXSJl+EyEhEqIDKB5lnakSAIyXSbZ+YP3cgsfGsuMLphXnmh1pMLZRZFW30B9cRGArXBAAO3Fo3BapG8kOryhozakpEx9NaSoTAeE6vVqzg9zsP4wMM4/hjG95H75CEulZ+czyNRwGpyqKf3HqH6ch4ZA9VlwsokEdYFcz2dIuOablzXjRu6cVM3bunGbd0Q2W8bTcejLTD1u6NFFL/PX3w5Fz9/ORF7+tE/lPwecw=="
TheTemplate = "PGh0bWw+CjxoZWFkPgo8dGl0bGU+JXM8L3RpdGxlPgo8L2hlYWQ+Cjxib2R5Pgo8ZW1iZWQgc3JjPSIlcyIgcXVhbGl0eT0iaGlnaCIgYmdjb2xvcj0iI2ZmZmZmZiIgd2lkdGg9IjY0MCIgaGVpZ2h0PSI0ODAiIG5hbWU9IiVzIiBhbGlnbj0ibWlkZGxlIiBhbGxvd1NjcmlwdEFjY2Vzcz0ic2FtZURvbWFpbiIgYWxsb3dGdWxsU2NyZWVuPSJmYWxzZSIgdHlwZT0iYXBwbGljYXRpb24veC1zaG9ja3dhdmUtZmxhc2giIHBsdWdpbnNwYWdlPSJodHRwOi8vd3d3LmFkb2JlLmNvbS9nby9nZXRmbGFzaHBsYXllciIgLz4KPC9ib2R5Pgo8L2h0bWw+Cg=="
tempShot = 'temporaryKeyShot1'
theCreateAsMovie = False
theCreateAsTiff = True
class SynchronizedScript( ScriptRunner ):
def __init__( self, scriptName, behavior, label, directory,
filename, duration, args ):
ScriptRunner.__init__( self, scriptName, args )
self.myBehavior = behavior
self.myLabel = label
self.myDirectory = directory
self.myFilename = filename
self.myDuration = duration
def Main( self ):
if TheUseRaytracing:
self.sendMessageSync('RT_SWITCH_REQUEST', (True,))
self.sendMessageSync("SHOT_CREATE",
("ShotKeyframed", tempShot,
"%s Shot" % (self.myBehavior),
"", False, "", None, True, 0))
self.sendMessageSync("SHOT_SET_PARAMETERS",
(tempShot,
{'Duration' : self.myDuration,
'TransitionType' : u"Cut to shot",
'Keyframe' : None,
'Keyframe2' : None},
True))
(root,ext) = os.path.splitext(self.myFilename)
self.sendMessage("BEHAVIOR_METHOD_EXECUTE",(self.myBehavior,
'PlayFromStart'))
if theCreateAsMovie:
createHow = 0
elif theCreateAsTiff:
createHow = 2
else:
createHow = 1
self.sendMessageSync('SAVE_SHOT_AS_MOVIE_AT_RESOLUTION',
(TheImageWidth, TheImageHeight,
TheFramesPerSecond,
createHow, TheAntiAliasing, False,
os.path.join(self.myDirectory,root),(tempShot,),
('Full Frames (Uncompressed)', 7500),
(-1, int(TheRaytracingSampling*100.0/6.0),
TheRaytracingPreset)),
userConditions='SHOT_PLAYING_DONE',
userTimeout = 36000)
self.sendMessage("BEHAVIOR_METHOD_EXECUTE",(self.myBehavior,
'StopAndResetToStart'))
self.sendMessage("SHOT_DELETE", (tempShot,))
if TheUseRaytracing:
self.sendMessageSync('RT_SWITCH_REQUEST', (False,))
showIt = None
if not theCreateAsMovie and not theCreateAsTiff:
imagefiles = glob.glob(os.path.join(self.myDirectory,
"%s_*.jpg" % (root)))
if imagefiles:
swfName = "%s.swf" % (root)
swfCopy = os.path.join(self.myDirectory, swfName )
swf = open( swfCopy, "wb" )
swf.write(base64.decodestring(TheRotator))
imagesFilename = os.path.join( self.myDirectory,
"images.xml" )
images = open( imagesFilename, "w" )
images.write( '<?xml version="1.0" encoding="utf-8"?>\n' )
images.write( '<behavior name="%s" width="%d" height="%d" how="%d">\n' % (self.myLabel,TheImageWidth,TheImageHeight,createHow))
cntr = 0
for f in imagefiles:
fn = os.path.split(f)[1]
images.write( '\t<image file="%s" frame="%d"/>\n' % (fn,cntr) )
cntr += 1
images.write( '</behavior>\n' );
images.close()
htmlId = self.myLabel
htmlFilename = os.path.join( self.myDirectory,
"%s.html" % (root) )
html = open( htmlFilename, "w" )
html.write( base64.decodestring(TheTemplate) % (htmlId, swfName, htmlId) )
html.close()
if TheShowResult:
showIt = swfCopy
if TheShowResult:
if theCreateAsMovie:
showIt = os.path.join(self.myDirectory,self.myFilename)
elif theCreateAsTiff:
showIt = self.myDirectory
if showIt:
os.startfile(os.path.normpath(showIt))
class CallScriptBatch:
def __init__(self, behAndLab, directory, filename, duration):
(self.myBehavior,self.myLabel) = behAndLab
self.myDirectory = directory
self.myFilename = filename
self.myDuration = duration
def instantiate( self, scriptName, args ):
return SynchronizedScript( scriptName,
self.myBehavior,
self.myLabel,
self.myDirectory,
self.myFilename,
self.myDuration,
args )
class ContextMenu( UserCustomBase ):
def __init__( self ):
self.myInterpreter = LocalInterpreter()
def filechoose(self):
msg = "Please specify filename for images or movie"
wild = "JPEG Image (*.jpg)|*.jpg|TIFF Image (*.tif)|*.tif|Movie File (*.avi)|*.avi|"
userPath = 'c:/'
dialog = wx.FileDialog(None, msg,
defaultDir="c:/",
defaultFile="",
wildcard=wild,
style=wx.SAVE | wx.OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
dir = dialog.GetDirectory()
f = dialog.GetFilename()
(r,ext) = os.path.splitext(f)
global theCreateAsMovie
global theCreateAsTiff
if (".tiff" == ext) or (".tif" == ext):
theCreateAsMovie = False
theCreateAsTiff = True
elif ".avi" == ext:
theCreateAsMovie = True
theCreateAsTiff = False
elif (".jpeg" == ext) or (".jpg" == ext):
theCreateAsMovie = False
theCreateAsTiff = False
else:
theCreateAsMovie = False
theCreateAsTiff = True
return (dir, f)
else:
dialog.Destroy()
return None
def getInterpreter( self, isInteractive ):
return (self.myInterpreter if isInteractive else None)
def appendPopupMenuItems( self, id, popupMenu, item ):
menuItem = None
if "BehaviorSelector" == id:
it = item.getType()
if "Turntable" == it:
menuItem = GenericPopupMenuItem(_( 'Save turntable as a movie ...'),
self.__cbCustomBehaviorTT,
item )
elif "KeyframeAnimation" == it:
menuItem = GenericPopupMenuItem(_( 'Save keyframe animation as a movie ...'),
self.__cbCustomBehaviorKF,
item )
if menuItem:
popupMenu.append( menuItem )
def __cbCustomBehaviorTT( self, item ):
dirfile = self.filechoose()
if dirfile:
(directory,filename) = dirfile
self.myInterpreter.SaveMovieTurntable( item.name(),
directory, filename )
def __cbCustomBehaviorKF( self, item ):
dirfile = self.filechoose()
if dirfile:
(directory,filename) = dirfile
self.myInterpreter.SaveMovieKeyframe( item.name(),
directory, filename )
class LocalInterpreter( MessageInterpreter ):
def __init__( self ):
MessageInterpreter.__init__( self )
self.myDocument = None
def SET_DOCUMENT( self, message ):
(self.myDocument,) = message.data
def APPLICATION_CLOSE_SCENE( self, message ):
self.myDocument = None
def document(self):
return self.myDocument
def SaveMovieTurntable(self, behavior, directory, filename):
(duration,label) = self._GetTurntableDurationAndLabel(behavior)
self.SaveMovieBehavior((behavior,label), directory, filename, duration)
def SaveMovieKeyframe(self, behavior, directory, filename):
(duration,label) = self._GetKeyframeDurationAndLabel(behavior)
self.SaveMovieBehavior((behavior,label), directory, filename, duration)
def SaveMovieBehavior(self, behAndLab, directory, filename, duration):
(behavior,label) = behAndLab
m = "Save movie for behavior (%s) with these parameters:\n" % (label)
m += " Duration: %f seconds\n" % (float(duration))
m += " Frames per second: %d\n" % (int(TheFramesPerSecond))
m += " Width: %d\n" % (int(TheImageWidth))
m += " Height: %d\n" % (int(TheImageHeight))
if theCreateAsMovie:
m += " Create as AVI %s\n" % (filename)
elif theCreateAsTiff:
m += " Create as TIFF sequence %s\n" % (filename)
else:
m += " Create as JPEG sequence %s\n" % (filename)
m += " Directory %s\n" % (directory)
if TheUseRaytracing:
m += " Using raytracing with parameters\n"
m += " Sampling: %d" % (int(TheRaytracingSampling))
m += " Preset: %s" % TheRaytracingPreset
else:
m += " Using hardware with anti-aliasing %d" % (int(TheAntiAliasing))
print m
cd = ConfirmDialog()
cd.show( None, "Save behavior as movie", m, ('OK','Cancel') )
if 2 == cd.returnValue():
duration = 0.0
if duration > 0.0:
module = CallScriptBatch(behAndLab, directory, filename, duration)
self.sendMessage( "EXECUTE_MODULE", ("BehaviorMovieSave", module))
def _GetTurntableDurationAndLabel(self, turntable):
duration = 0.0
if self.myDocument:
behaviors = self.myDocument.get(BehaviorIO.id)
tt = behaviors[turntable]
rpm = float(tt.getParameterValue('RPM'))
if rpm > 0:
duration = 60.0 / rpm
if theCreateAsMovie:
if TheSkipLastTurntableFrameMovies:
duration -= 1.0/TheFramesPerSecond
else:
if TheSkipLastTurntableFrameImages:
duration -= 1.0/TheFramesPerSecond
label = tt.getLabel()
return (duration,label)
def _GetKeyframeDurationAndLabel(self, keyframe):
duration = 0.0
label = ''
if self.myDocument:
behaviors = self.myDocument.get(BehaviorIO.id)
tt = behaviors[keyframe]
tt.updateDuration()
duration = float(tt._FbxBehavior__myDuration)
label = tt.getLabel()
return (duration,label)
def instantiate():
return ContextMenu()