#-----------------------------------------------------------------------------
# AviInTrans
# Copyright (c) 2003 David G. Drumright (ockham)
# 6/15/03
#-----------------------------------------------------------------------------
import poser
import os
import sys
scene = poser.Scene()

from Tkinter import *
root = Tk()

#-----------------------------------------------------------------------------
# Global vars
#-----------------------------------------------------------------------------

global ActorList, FigureList, Choices, StopRendering, Rendering

StopRendering = 0
Rendering     = 0
Choices       = {}
FigureList    = {}
ActorList     = {}
CurrActor     = None
CurrMaterial  = None

#-----------------------------------------------------------------------------
# Next section is TK
#------------------------------------------------------------

class App:
  def __init__(self, master, textMessage):
    global Choices
    global FigureList, ActorList, ActorMenu, MaterialMenu

    self.master = master
    master.title("Fit AVI to a screen inside main animation.")

    self.OutNameLabel = Label(self.master,text="Base name for output files")
    self.OutNameLabel.grid(row=1, column=0, sticky=E, padx=3)
    self.OutNameEntry = Entry(self.master, width=22)
    self.OutNameEntry.grid(row=1, column=1, columnspan=2, sticky=W, pady=2)

    MenuButton1 = Menubutton(self.master, relief=RAISED,
      text="    Choose Actor")
    MenuButton1.grid(row=2, column=0, sticky=E, pady=2, padx=3)

    ActorMenu = Menu(MenuButton1, tearoff=0)
    for fig in scene.Figures():
      n = fig.Name()
      ActorMenu.add_command(label="Figure: %s" % (n),
        command=lambda m=n, self=self : self.sel_figure(m))
      FigureList[n] = 1

    for act in scene.Actors():
      n = act.Name()
      ActorMenu.add_command(label="Actor: %s" % (n),
        command=lambda m=n, self=self : self.sel_actor(m))
      ActorList[n] = 1

    MenuButton1["menu"] = ActorMenu

    self.ScreenNameEntry = Entry(self.master, width=22)
    self.ScreenNameEntry.grid(row=2,column=1, columnspan=2, sticky=W)

    MenuButton2 = Menubutton(self.master, relief=RAISED,
      text="Choose Material")
    MenuButton2.grid(row=3, column=0, sticky=E, padx=3)
    MaterialMenu = Menu(MenuButton2, tearoff=0)
    MenuButton2["menu"] = MaterialMenu

    self.MatlNameEntry = Entry(self.master, width=22)
    self.MatlNameEntry.grid(row=3,column=1, columnspan=2, sticky=W)

    self.AviNameLabel = Label(self.master,text="Base name of BMP files")
    self.AviNameLabel.grid(row=4, column=0, sticky=E, pady=2, padx=3)
    self.AviNameEntry = Entry(self.master, width=22)
    self.AviNameEntry.grid(row=4,column=1, columnspan=2, sticky=W, pady=4)

    self.StartFrameLabel = Label(self.master, text="Start Frame")
    self.StartFrameLabel.grid(row=5, column=0, sticky=E, pady=4, padx=3)
    self.StartFrameEntry = Entry(self.master, width=22)
    self.StartFrameEntry.grid(row=5,column=1, columnspan=2, sticky=W, pady=4)

    self.ButtonPanel = Frame(self.master, borderwidth=2, relief=FLAT)
    self.ButtonPanel.grid(row=6, column=0, columnspan=3, pady=5)

    self.buttonGo = Button(self.ButtonPanel, text="Go", width=10,
      command=self.handleGo)
    self.buttonGo.grid(row=0, column=0, padx=5)

    self.buttonLoad = Button(self.ButtonPanel, text="Recall", width=10,
      command=self.handleLoad)
    self.buttonLoad.grid(row=0, column=1, padx=5)

    self.buttonCancel = Button(self.ButtonPanel, text="Cancel", width=10,
      command=self.handleCancel)
    self.buttonCancel.grid(row=0, column=2, padx=5)

    syslist = sys.path
    self.DirBase = os.path.abspath(syslist[-1])+"/"
    #self.DirBase = os.path.normpath(self.DirBase)
    #print "DirBase=%s" % (self.DirBase)

  # - - - - - - - - - - - - - - - - - -

  def RenderFrames(self):
    # Run through the frames.  For each frame, apply the corresponding
    # member of the Screen image sequence to the selected object.
    # Save the complete image at this step.
    global Choices, StopRendering, Rendering

    Rendering = 1
    for fnum in range(scene.NumFrames()):
      #print "frame:",fnum
      if StopRendering:
        Rendering = 0
        break

      want_render = 0
      for actname in Choices.keys():

        #print "actname:",actname

        for matname in Choices[actname].keys():

          #print "matname:",matname

          try:    avi   = Choices[actname][matname]["avi"]
          except: avi   = None
          try:    start = int(Choices[actname][matname]["start"])
          except: start = 1
          try:    idx   = int(Choices[actname][matname]["idx"])
          except: idx   = 1

          if avi == None:
            raise "missing BMP sequence for %s %s" % (actname, matname)

          #print "fnum=%d start=%d avi=%s idx=%d" % (fnum, start, avi, idx)

          # do we have work to do on this frame?
          if start <= fnum+1:
            #print "work to do!"

            scene.SetFrame(fnum)

            try:    act = scene.Actor(actname)
            except: raise "actor name is incorrect: '%s'" % (actname)

            try:    mat = act.Material(matname)
            except: raise "material name is incorrect: '%s'" % (matname)

            # build the name of the map file
            InName = "%s/%s_%.4d.BMP" % (self.DirBase, avi, idx)

            # convert these to os dependent names
            RealInName = os.path.normpath(InName)

            # make sure we still have files left for this sequence
            if os.path.exists(RealInName):
              print "EXISTS: fnum=%d RealInName: %s" % (fnum, RealInName)

              # yes, we do, so we want to render this frame
              want_render = 1

              # increment the counter for this map
              Choices[actname][matname]["idx"] = idx+1

              # save the original map, if any - TODO: restore this map later?
              Choices[actname][matname]["save"] = mat.TransparencyMapFileName()

              # Apply the In image to the Screen object.
              mat.SetTransparencyMapFileName(RealInName)

              # not sure why we want to memorize this actor?
              act.Memorize()
            else:
              print "DOES NOT EXIST: fnum=%d RealInName: %s" % (fnum, RealInName)

      #want_render = 1
      if want_render:
        scene.Render()

        # build the name of the output file
        OutName = "%s/frames/%s_%.4d.BMP" % (self.DirBase,
          self.OutNameEntry.get(), fnum+1)
        RealOutName = os.path.normpath(OutName)
        #print "saving: %s" % (RealOutName)
        scene.SaveImage("bmp", RealOutName)

      # remove this map so the images (which may be gone later) don't
      # cling to the PZ3. -- maybe we should restore the saved original???
      #mat.SetTextureMapFileName(None)

  def store_choices(self):
    global CurrActor, CurrMaterial, Choices
    if CurrActor == None or CurrMaterial == None: return

    start = self.StartFrameEntry.get()
    avi   = self.AviNameEntry.get()
    idx   = 1

    try: x = Choices[CurrActor]
    except KeyError: Choices[CurrActor] = {}

    Choices[CurrActor][CurrMaterial] = { "start":start, "avi":avi, "idx":idx }

  def restore_choices(self):
    global CurrActor, CurrMaterial, Choices

    try: start = Choices[CurrActor][CurrMaterial]["start"]
    except: start = "-None-"
    self.StartFrameEntry.delete(0, "end")
    self.StartFrameEntry.insert(0, start)

    try: avi = Choices[CurrActor][CurrMaterial]["avi"]
    except: avi = "-None-"
    self.AviNameEntry.delete(0, "end")
    self.AviNameEntry.insert(0, avi)

    try: idx = Choices[CurrActor][CurrMaterial]["idx"]
    except: idx = 1

  def save_choices(self):
    global Choices
    buf = "%s\n%s\n" % (self.OutNameEntry.get(), self.DirBase)
    self.store_choices()
    fname = "%s/%s" % (self.DirBase, "choices.dat")
    for actname in Choices.keys():
      for matname in Choices[actname].keys():
        try:    start = Choices[actname][matname]["start"]
        except: start = "-None-"
        try:    avi = Choices[actname][matname]["avi"]
        except: avi = "-None-"
        try:    idx = Choices[actname][matname]["idx"]
        except: idx = 1
        buf = "%s%s:%s:%s:%s:%s\n" % (buf, actname, matname, start, avi, idx)
    try: fp = open(fname, "w")
    except (IOError): raise "Can't create file '%s'" % (fname)
    fp.write(buf)
    fp.close()

  def load_choices(self):
    global Choices, CurrActor, CurrMaterial

    fname = "%s/%s" % (self.DirBase, "choices.dat")
    try: fp = open(fname)
    except (IOError): raise "Can't read file '%s'" % (fname)
    buf = fp.read(100000)
    fp.close()
    Choices = {}
    failsafe = 1000
    CurrActor = None
    CurrMaterial = None

    line = re.split(r'\n', buf)
    self.OutNameEntry.delete(0, "end")
    self.OutNameEntry.insert(0, line[0])
    self.DirBase = line[1]
    #self.DirBase = os.path.normpath(self.DirBase)
    #print "DirBase=%s" % (self.DirBase)
    for i in range(2, len(line)):
      if len(line[i]) == 0: break
      a = re.split(':', line[i])
      if not a: raise "%s (%d): bad data '%s'" % (fname, i+1, line[i])
      actname = a[0]
      matname = a[1]
      start   = a[2]
      avi     = a[3]
      idx     = a[4]
      if CurrActor == None: CurrActor = actname
      if CurrMaterial == None: CurrMaterial = matname
      try: x = Choices[actname]
      except: Choices[actname] = {}
      Choices[actname][matname] = { "start":start, "avi":avi, "idx":idx }

    self.ScreenNameEntry.delete(0, "end")
    self.ScreenNameEntry.insert(0, CurrActor)
    self.MatlNameEntry.delete(0, "end")
    self.MatlNameEntry.insert(0, CurrMaterial)
    self.restore_choices()

  def sel_material(self, value):
    global CurrActor, CurrMaterial

    self.store_choices()
    CurrMaterial = value
    self.MatlNameEntry.delete(0, "end")
    self.MatlNameEntry.insert(0, value)
    self.restore_choices()

  def sel_figure(self, value):
    pass

  def sel_actor(self, value):
    global ActorMenu, MaterialMenu, CurrActor, CurrMaterial

    self.store_choices()
    act = scene.Actor(value)
    self.ScreenNameEntry.delete(0, "end")
    self.ScreenNameEntry.insert(0, value)
    CurrActor = act.Name()
    mats = act.Materials()
    nmats = MaterialMenu.index(END)
    if nmats != None:
      MaterialMenu.delete(0, nmats)
    prev_material = CurrMaterial
    CurrMaterial = None
    found_match = 0
    for mat in mats:
      mname = mat.Name()
      if CurrMaterial == None: CurrMaterial = mname
      if prev_material == mname: found_match = 1
      MaterialMenu.add_command(label=mname, 
        command=lambda m=mname, self=self : self.sel_material(m))
    if found_match: CurrMaterial = prev_material
    self.restore_choices()

  def handleLoad(self):
    self.load_choices()

  def handleGo(self):
    global Choices

    self.store_choices()
    self.save_choices()
    self.RenderFrames()
    self.master.destroy()
    self.master.quit()

  # - - - - - - - - - - - - - - - - - -

  def handleCancel(self):
    global StopRendering, Rendering
    if Rendering:
      StopRendering = 1
      return
    self.master.destroy()
    self.master.quit()

#------------------------------------------------------------
# Activate the loop
#------------------------------------------------------------

app = App(root, "")
root.mainloop()
