ComplexTools/BlendShape_Editor.py

ComplexTools/BlendShape_Editor.py
1 # Copyright 2009 Autodesk, Inc. All rights reserved.
2 # Use of this software is subject to the terms of the Autodesk license agreement
3 # provided at the time of installation or download, or which otherwise accompanies
4 # this software in either electronic or hard copy form.
5 #
6 # Script description:
7 # Blend shaped editor.
8 # Press Attach and it will grab all BlendShape Model in the scene and create an editor for them.
9 # Press Detach and it will release all BlendShape and clears all UI
10 #
11 # Topic: FBEventName, FBSlider
12 #
13 
14 from pyfbsdk import *
15 from pyfbsdk_additions import *
16 
17 class SliderControl(FBVBoxLayout):
18  def _sliderCallback(self,control,event):
19  if event.Type == FBEventName.kFBEventChange:
20  self.value.Text = "%3.2f" % self.slider.Value
21  self._linkedproperty.Data=self.slider.Value
22  if self.key.State==1:
23  self._isCandidate=True
24  elif event.Type ==FBEventName.kFBEventOnClick:
25  self._onChange=True
26  elif event.Type ==FBEventName.kFBEventExit:
27  self._onChange=False
28 
29  def _valueCallback(self, control, event):
30  self._onChange=True
31  self.slider.Value = float(self.value.Text)
32  self._linkedproperty.Data = float(self.value.Text)
33  self.value.Text = "%3.2f" % float(self.value.Text)
34  self._onChange=False
35  if self.key.State==1:
36  self._isCandidate=True
37 
38  def _nameCallback(self, control, event):
39  print "NameChanged"
40 
41  def _keyCallback(self, control, event):
42  self.Key()
43 
44  def _clearCallback(self, control, event):
45  self.ClearAnimation()
46 
47  def _IdleCallback(self, control, event):
48  if not self._onChange:
49  self.updateView()
50 
51  def __init__(self, Aproperty):
52  from pyfbsdk import FBAddRegionParam
53  from pyfbsdk import FBAttachType
54 
56  self._linkedproperty = Aproperty
57  self._onChange = False
58  self._isCandidate = False
59  self.slider = pyfbsdk.FBSlider()
60  self.value = pyfbsdk.FBEdit()
61  self.name = pyfbsdk.FBLabel()
62  self.name.Justify = FBTextJustify.kFBTextJustifyRight
63  self.key = pyfbsdk.FBButton()
64  self.key.State=1
65  self.key.Caption = "Key"
66  self.clear = pyfbsdk.FBButton()
67  self.clear.Caption = "Clear"
68 
69  if Aproperty.IsAnimatable() and Aproperty.GetDataTypeName().lower()=="shape": ##check that we have an animatable shape property
70  self.slider.Min = Aproperty.GetMin()
71  self.slider.Max = Aproperty.GetMax()
72  self.slider.Value = Aproperty.Data
73  self.value.Text = "%3.2f" % Aproperty.Data
74  self.name.Caption = Aproperty.GetName()
75  else:
76  print "notAdouble"
77 
78  self.slider.OnChange.Add(self._sliderCallback)
79  self.value.OnChange.Add(self._valueCallback)
80  self.key.OnClick.Add(self._keyCallback)
81  self.OnIdle.Add(self._IdleCallback)
82  self.clear.OnClick.Add(self._clearCallback)
83 
84  ##add the slider view
85  self.Add(self.slider, 150, width = 35)
86 
87  ## add the button clear
88  self.Add(self.clear, 25)
89 
90  ## add the button key
91  self.Add(self.key, 25)
92 
93  ## add the name
94  self.Add(self.name, 25)
95 
96 
97  ##add the Value
98  self.Add(self.value, 25)
99 
100 
101  def add(self,name,content):
102  self.tabpanel.Items.append(name)
103  self.tabcontents.append(content)
104  self.setContent(len(self.tabpanel.Items) - 1)
105 
106  def setContent(self,index):
107  self.tabpanel.ItemIndex = index
108  self.SetControl("mainlyt",self.tabcontents[index])
109 
110  def Key(self):
111  self._linkedproperty.Key()
112  self._isCandidate=False
113 
114  def Reset(self):
115  self._isCandidate=True
116  self.value.Text="0.0"
117  self._valueCallback(None,FBEventChange())
118 
119  def ClearAnimation(self):
120  self._isCandidate=True
121  self._linkedproperty.GetAnimationNode().FCurve.EditClear()
122 
123 
124  def Clear(self):
125  self._linkedproperty.GetAnimationNode().KeyRemove()
126 
127  def updateView(self):
128  if not self._onChange:
129  precision = 0.005
130  currentvalue = float(self.value.Text)
131  if currentvalue < self._linkedproperty.Data-precision or currentvalue > self._linkedproperty.Data+precision:
132  self.value.Text="%3.2f" %self._linkedproperty.Data
133  self.slider.Value = self._linkedproperty.Data
134  if not self._isCandidate and self._linkedproperty.GetAnimationNode().IsKey():
135  if self.key.State!=1:
136  self.key.State=1
137  else:
138  if self.key.State!=0:
139  self.key.State=0
140  if self._linkedproperty.IsAnimatable() and self._linkedproperty.GetAnimationNode().KeyCount>0:
141  self.key.Caption="Key *"
142  else:
143  self.key.Caption="Key"
144 
145 def GetBlendShapeProp(aModel):
146  myproplist = list()
147  for prop in aModel.PropertyList:
148  if prop != None and prop.IsAnimatable() and prop.GetDataTypeName().lower()=="shape":
149  myproplist.append(prop)
150  return myproplist
151 
152 class ModelBlendShapeUI (FBHBoxLayout):
153  def _KeyAllCallBack(self,control, event):
154  for each in self._mySliderList:
155  each.Key()
156 
157  def _ResetAllCallBack(self,control, event):
158  for each in self._mySliderList:
159  each.Reset()
160 
161  def _ClearAllCallBack(self,control, event):
162  for each in self._mySliderList:
163  each.ClearAnimation()
164 
165  def __init__(self, Amodel):
166  from pyfbsdk import FBAddRegionParam
167  from pyfbsdk import FBAttachType
168 
170  self._linkedModel = Amodel
171  self._mySliderList=list()
172  ## populate the propertylist
173  self.bkeyall=FBButton()
174  self.bkeyall.Caption="Key All"
175  self.brstall=FBButton()
176  self.brstall.Caption="Reset All"
177  self.bclrall=FBButton()
178  self.bclrall.Caption="Clear All"
179 
180  ## Creation of the buttonLayout
181  self._myButtonsLay = FBVBoxLayout()
182  self.Add(self._myButtonsLay, 75)
183 
184  self.bkeyall.OnClick.Add(self._KeyAllCallBack)
185  self._myButtonsLay.Add(self.bkeyall, 25)
186 
187  ##brstall
188  self.brstall.OnClick.Add(self._ResetAllCallBack)
189  self._myButtonsLay.Add(self.brstall, 25)
190 
191  ##bclrall
192  self.bclrall.OnClick.Add(self._ClearAllCallBack)
193  self._myButtonsLay.Add(self.bclrall, 25)
194 
195  # add all the slider ctrl
196  for prop in GetBlendShapeProp(self._linkedModel):
197  slider = SliderControl(prop)
198  self._mySliderList.append(slider)
199  self.Add(slider, 75, space = 10)
200 
201 
202 
203 def GetBlendShapeModel():
204  modelslist = list()
205  for component in FBSystem().Scene.Components:
206  if str(type(component)).lower().find("fbmodel")>-1:
207  bblend=False
208  for prop in component.PropertyList:
209  if not prop==None and prop.IsAnimatable() and prop.GetDataTypeName().lower()=="shape":
210  bblend=True
211  break
212  if bblend:
213  modelslist.append(component)
214  return modelslist
215 
216 
217 def DetachFromBlendShape(control, event):
218  global regions
219  global models
220 
221  for region in regions.itervalues():
222  lyt.RemoveRegion(region)
223  regions = {}
224  models = []
225 
226 def AttachToBlendShape(control, event):
227  DetachFromBlendShape(None, None)
228 
229  global models
230  models = GetBlendShapeModel()
231 
232  anchor = FBAttachType.kFBAttachTop
233  anchorRegion = ""
234  for i, model in enumerate(models):
235  lytName = model.Name
236  blendShapeEditor = ModelBlendShapeUI(model)
237 
238  arrowName = "ArrowName" + str( i )
239  x = FBAddRegionParam(0,FBAttachType.kFBAttachLeft,"")
240  y = FBAddRegionParam(0,anchor,anchorRegion)
241  w = FBAddRegionParam(2000,FBAttachType.kFBAttachNone,"")
242  h = FBAddRegionParam(0,FBAttachType.kFBAttachNone,"")
243  lyt.AddRegion(arrowName ,arrowName , x, y, w, h)
244 
245  b = FBArrowButton()
246  regions[model] = arrowName
247  lyt.SetControl(arrowName ,b)
248 
249  # important : we set the content AFTER having added the button arrow
250  # to its parent layout
251  b.SetContent( model.Name, blendShapeEditor, 2000, 300 )
252  blendShapeEditor.Restructure(True)
253 
254  anchor = FBAttachType.kFBAttachBottom
255  anchorRegion = arrowName
256 
257 
258 def SceneChanged(scene, event):
259  if event.Type == FBSceneChangeType.kFBSceneChangeDetach and \
260  event.ChildComponent in models:
261  lyt.RemoveRegion(regions[event.ChildComponent])
262  models.remove(event.ChildComponent)
263 
264 
265 def OnToolDestroy(control,event):
266  # Important: each time we run this script we need to remove
267  # the SceneChanged from the Scene else they will accumulate
268  FBSystem().Scene.OnChange.Remove(SceneChanged)
269 
270 
271 models = []
272 regions = {}
273 
274 # Tool creation will serve as the hub for all other controls
275 tool = FBCreateUniqueTool("Blend Shape Editor")
276 
277 tool.StartSizeX = 400
278 tool.StartSizeY = 200
279 
280 scroll = FBScrollBox()
281 scroll.SetContentSize(2000,10000)
282 
283 mainLyt = FBVBoxLayout()
284 x = FBAddRegionParam(0,FBAttachType.kFBAttachLeft,"")
285 y = FBAddRegionParam(0,FBAttachType.kFBAttachTop,"")
286 w = FBAddRegionParam(0,FBAttachType.kFBAttachRight,"")
287 h = FBAddRegionParam(0,FBAttachType.kFBAttachBottom,"")
288 tool.AddRegion("main","main", x, y, w, h)
289 tool.SetControl("main",mainLyt)
290 
291 btnbar = FBHBoxLayout()
292 btn = FBButton()
293 btn.Caption = "Attach"
294 btn.OnClick.Add(AttachToBlendShape)
295 btnbar.Add(btn, 75)
296 
297 btn = FBButton()
298 btn.Caption = "Detach"
299 btn.OnClick.Add(DetachFromBlendShape)
300 btnbar.Add(btn, 75)
301 
302 mainLyt.Add(btnbar, 30)
303 
304 mainLyt.AddRelative(scroll)
305 
306 lyt = scroll.Content
307 
308 # Register for scene event
309 FBSystem().Scene.OnChange.Add(SceneChanged)
310 
311 # register when this tool is destroyed.
312 tool.OnUnbind.Add(OnToolDestroy)
313 
314 ShowTool(tool)