# Set Gamma v1.0
# Set the gamma value, like in the Script that ships with Poser, just with less clicking
# When clicking Set/reset, the selections and values will be saved and stored in the Poser data directory under "acb/gamma" (when exiting the script), so they're available the next time you run this script. The script's size is also saved for the different rooms (if a room can be identified)
# - poor python coding by Dizzi
import poser
import wx
import wx.aui
import os.path
import wx.lib.masked.numctrl
import math
import pickle

class SetGamma(wx.Panel):
	SavePath=os.path.join(poser.PrefsLocation(), "acb", "gamma")
	PanelLayout={}
	DicSelection={}
	
	def __init__(self,parent,title, pane):
		wx.Panel.__init__(self, parent, -1, wx.Point(-1, -1), wx.DefaultSize)
		
		self.man=poser.WxAuiManager()
		self.PanelLayoutFile=os.path.join(self.SavePath, "PanelLayout_"+self.TryFindRoom()+".config")
		if os.path.exists(self.PanelLayoutFile):
			fd=open(self.PanelLayoutFile)
			self.PanelLayout=pickle.load(fd)
			fd.close()
			if self.PanelLayout.has_key("PanelLayout"):
				self.man.LoadPaneInfo(self.PanelLayout["PanelLayout"], pane)
		self.sizer = wx.BoxSizer(wx.VERTICAL)
		self.SetSizer(self.sizer)
		
		self.rbAffect = wx.RadioBox(self, 1, "Affect", wx.Point(-1, -1), wx.DefaultSize, ["Material", "Actor", "All"], 1, wx.RA_SPECIFY_COLS)
		self.sizer.Add(self.rbAffect)

		staticBox = wx.StaticBox(self, -1, "Inputs")
		self.szInput = wx.StaticBoxSizer(staticBox, wx.VERTICAL)
		self.sizer.Add(self.szInput)
		self.cbDisplacement = wx.CheckBox(self, -1, "Displacement")
		self.szInput.Add(self.cbDisplacement)
		self.cbBump = wx.CheckBox(self, -1, "Bump")
		self.szInput.Add(self.cbBump)
		self.cbGradient = wx.CheckBox(self, -1, "Gradient_Bump")
		self.szInput.Add(self.cbGradient)
		self.cbTransparency = wx.CheckBox(self, -1, "Transparency")
		self.szInput.Add(self.cbTransparency)
		self.cbOther = wx.CheckBox(self, -1, "Other")
		self.szInput.Add(self.cbOther)
		
		fgsGridInputs=wx.FlexGridSizer(2,2,2,1)
		self.sizer.Add(fgsGridInputs)
		lblGamma = wx.StaticText(self, -1, "Value: ", wx.Point(-1, -1), wx.DefaultSize, wx.ALIGN_RIGHT)
		self.txtGamma = wx.lib.masked.NumCtrl(self, 20)
		self.txtGamma.SetFractionWidth(2)
		self.txtGamma.SetIntegerWidth(1)
		self.txtGamma.SetValue(2.2)
		self.txtGamma.SetMax(5.0)
		self.txtGamma.SetMin(0.2)
		self.txtGamma.SetAllowNone(False)
		self.txtGamma.SetAllowNegative(False)
		self.txtGamma.SetGroupDigits(False)
		
		fgsGridInputs.Add(lblGamma, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
		fgsGridInputs.Add(self.txtGamma)
		
		self.btnReset = wx.Button(self, 11, "Reset", wx.Point(-1,-1), (50,-1))
		self.btnReset.SetToolTip(wx.ToolTip("use global gamma setting"))
		fgsGridInputs.Add(self.btnReset)
		self.btnSet = wx.Button(self, 12, "Set", wx.Point(-1,-1), (50,-1))
		self.btnSet.SetToolTip(wx.ToolTip("use entered gamma value"))
		fgsGridInputs.Add(self.btnSet)
		
		self.Layout()
		
		self.Bind(wx.EVT_SIZE,self.EvtChildFocus)
		self.Bind(wx.EVT_CHILD_FOCUS, self.EvtChildFocus)
		self.Bind(wx.EVT_RIGHT_DOWN, self.ShowContextMenu)
		self.Bind(wx.EVT_MENU, self.ExecuteMenuCommand)

		self.Bind(wx.EVT_BUTTON, self.EvtButton)
		
		if not os.path.exists(self.SavePath):
			os.makedirs(self.SavePath)

		self.MemoryFile=os.path.join(self.SavePath, "memory.config")
		if os.path.exists(self.MemoryFile):
			fd=open(self.MemoryFile)
			dic=pickle.load(fd)
			self.DicSelection=dic
			if (dic.has_key("affect")):
				self.rbAffect.SetSelection(dic["affect"])
			if (dic.has_key("inputs_d")):
				self.cbDisplacement.SetValue(dic["inputs_d"])
			if (dic.has_key("inputs_b")):
				self.cbBump.SetValue(dic["inputs_b"])
			if (dic.has_key("inputs_g")):
				self.cbGradient.SetValue(dic["inputs_g"])
			if (dic.has_key("inputs_t")):
				self.cbTransparency.SetValue(dic["inputs_t"])
			if (dic.has_key("inputs_o")):
				self.cbOther.SetValue(dic["inputs_o"])
			if (dic.has_key("gamma")):
				self.txtGamma.SetValue(dic["gamma"])
			fd.close()
		
	def __del__(self):
		try:
			fd=open(self.MemoryFile, "w")
			pickle.dump(self.DicSelection,fd)
			fd.close()
		except:
			pass
		try:
			fd=open(self.PanelLayoutFile, "w")
			pickle.dump(self.PanelLayout,fd)
			fd.close()
		except:
			pass
	def EvtChildFocus(self, event):
		self.SaveLayout()
		event.Skip()
	def SaveLayout(self):
		pane=self.man.GetPane(self)
		pane.BestSize(pane.floating_size)
		self.PanelLayout["PanelLayout"]=self.man.SavePaneInfo(pane)
	def EvtButton(self, event):
		dic=self.DicSelection
		dic["affect"]=self.rbAffect.GetSelection()
		dic["inputs_d"]=self.cbDisplacement.GetValue()
		dic["inputs_b"]=self.cbBump.GetValue()
		dic["inputs_g"]=self.cbGradient.GetValue()
		dic["inputs_t"]=self.cbTransparency.GetValue()
		dic["inputs_o"]=self.cbOther.GetValue()
		dic["gamma"]=self.txtGamma.GetValue()
			
		type=self.rbAffect.GetSelection()
		mats=[]
		if type==0:
			mat=poser.Scene().CurrentMaterial()
			if (mat==None):
				return
			mats.append(mat)
		elif type==1:
			act=poser.Scene().CurrentActor()
			mats = act.Materials()
		elif type==2:
			for a in poser.Scene().Actors():
				if (a.IsProp()):
					ms = a.Materials()
					if (ms!=None):
						mats.extend(ms)

			for figure in poser.Scene().Figures():
				ms = figure.Materials()
				if (ms!=None):
					mats.extend(ms)
		else:
			return
		if mats==None:
			return
		if (event.Id==11):
			self.SetGamma(mats, 0, True)
		if (event.Id==12):
			self.SetGamma(mats, self.txtGamma.GetValue(), False)
				
	def SetGamma(self, materials, value, useGlobalGamma):
		for mat in materials:
			shdrTree = mat.ShaderTree(); 
			if shdrTree!=None:
				for node in shdrTree.Nodes():
					for input in node.Inputs():
						name = input.InternalName()
						if input.InNode():
							if name == "Transparency_Max":
								if self.cbTransparency.GetValue():
									self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
							elif name == "Displacement":
								if self.cbDisplacement.GetValue():
									self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
							elif name == "Bump":
								if self.cbBump.GetValue():
									self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
							elif name == "Gradient_Bump":
								if self.cbGradient.GetValue():
									self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
							else:
								if self.cbOther.GetValue():
									self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
	def SetGammaPerNode(self, node, value, useGlobalGamma):
		if node!=None:
			for input in node.Inputs():
				if input.InternalName() == "Image_Source":
					texture = input.Texture()
					if texture!=None:
						if useGlobalGamma==True:
							texture.SetUseSceneGamma(1)
						else:
							texture.SetGamma(value)
				self.SetGammaPerNode(input.InNode(), value, useGlobalGamma)
	
	def TryFindRoom(self):
		for pane in self.man.GetAllPanes():
			if pane.name.startswith("Hair") and pane.IsShown():
				return "Hair"
			elif pane.name.startswith("Cloth") and pane.IsShown():
				return "Cloth"
			elif pane.name.startswith("Material") and pane.IsShown():
				return "Material"
		return "Default"

	def ShowContextMenu(self, event):
		pane = self.man.GetPane(self)
		menu = wx.Menu()
		dock = menu.Append(1, "Docked", kind=wx.ITEM_CHECK)
		float = menu.Append(2, "Floating", kind=wx.ITEM_CHECK)
		if pane.IsDocked():
			dock.Check()
		else: 
			float.Check()
		menu.AppendSeparator()
		drag = menu.Append(3, "Drag-Docking Enabled", kind=wx.ITEM_CHECK)
		if pane.IsLeftDockable():
			drag.Check()
		self.PopupMenu(menu)
		menu.Destroy()

	def ExecuteMenuCommand(self, e):
		pane = self.man.GetPane(self)
		id = e.GetId()
		if id == 1:
			if pane.IsDocked():
				return
			pane.Dock()
			self.man.Update()
		elif id == 2:
			if pane.IsFloating():
				return
			pane.Float()
			self.man.Update()
		elif id == 3:
			pane.Dockable(e.IsChecked())
				
name = "Set Gamma"
man = poser.WxAuiManager()
root = man.GetManagedWindow()

pane = wx.aui.AuiPaneInfo()
pane.Caption(name).CaptionVisible().CloseButton().Resizable().DestroyOnClose()
pane.BestSize(wx.Size(50, 50)).Right().PinButton().Dock()
win = SetGamma(root, name, pane)
man.AddPane(win, pane)
pane.Show()
man.Update()


