lightingPanel.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. #################################################################
  2. # lightingPanel.py
  3. # Written by Yi-Hong Lin, [email protected], 2004
  4. #################################################################
  5. # Import Tkinter, Pmw, and the floater code from this directory tree.
  6. from direct.tkwidgets.AppShell import AppShell
  7. from seColorEntry import *
  8. from direct.tkwidgets.VectorWidgets import Vector3Entry
  9. from direct.tkwidgets.Slider import Slider
  10. from Tkinter import Frame, Button, Menubutton, Menu
  11. import string, math, types, Pmw, Tkinter
  12. from pandac.PandaModules import *
  13. class lightingPanel(AppShell):
  14. #################################################################
  15. # lightingPanel(AppShell)
  16. # This will create a window to let user
  17. # create any kinds of lighting into the scene
  18. #################################################################
  19. # Override class variables
  20. appname = 'Lighting Panel'
  21. frameWidth = 400
  22. frameHeight = 400
  23. currentLight = None
  24. def __init__(self, lightList, parent = None, **kw):
  25. self.lightList = lightList
  26. self.lightColor = [0.3*255,0.3*255,0.3*255]
  27. self.type = ''
  28. INITOPT = Pmw.INITOPT
  29. optiondefs = (
  30. ('title', self.appname, None),
  31. )
  32. self.defineoptions(kw, optiondefs)
  33. # Initialize the superclass
  34. AppShell.__init__(self)
  35. # Execute option callbacks
  36. self.initialiseoptions(lightingPanel)
  37. self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
  38. def createInterface(self):
  39. # Handle to the toplevels interior
  40. interior = self.interior()
  41. menuBar = self.menuBar
  42. self.menuBar.destroy()
  43. # Create a frame to hold all stuff
  44. mainFrame = Frame(interior)
  45. self.listZone = Pmw.Group(mainFrame,tag_pyclass = None)
  46. self.listZone.pack(expand=0, fill=Tkinter.X,padx=3,pady=3)
  47. listFrame = self.listZone.interior()
  48. self.lightEntry = self.createcomponent(
  49. 'Lights List', (), None,
  50. Pmw.ComboBox, (listFrame,),label_text='Light :',
  51. labelpos = Tkinter.W, entry_width = 25, selectioncommand = self.selectLight,
  52. scrolledlist_items = self.lightList)
  53. self.lightEntry.pack(side=Tkinter.LEFT)
  54. self.renameButton = self.createcomponent(
  55. 'Rename Light', (), None,
  56. Button, (listFrame,),
  57. text = ' Rename ',
  58. command = self.renameLight)
  59. self.renameButton.pack(side=Tkinter.LEFT)
  60. self.addLighZone = Pmw.Group(listFrame,tag_pyclass = None)
  61. self.addLighZone.pack(side=Tkinter.LEFT)
  62. insideFrame = self.addLighZone.interior()
  63. self.lightsButton = Menubutton(insideFrame, text = 'Add light',borderwidth = 3,
  64. activebackground = '#909090')
  65. lightsMenu = Menu(self.lightsButton)
  66. lightsMenu.add_command(label = 'Add Ambient Light',
  67. command = self.addAmbient)
  68. lightsMenu.add_command(label = 'Add Directional Light',
  69. command = self.addDirectional)
  70. lightsMenu.add_command(label = 'Add Point Light',
  71. command = self.addPoint)
  72. lightsMenu.add_command(label = 'Add Spotlight',
  73. command = self.addSpot)
  74. self.lightsButton.pack(expand=0)
  75. self.lightsButton['menu'] = lightsMenu
  76. self.deleteButton = self.createcomponent(
  77. 'delete Light', (), None,
  78. Button, (listFrame,),
  79. text = ' Delete ',
  80. command = self.deleteLight)
  81. self.deleteButton.pack(side=Tkinter.LEFT)
  82. self.lightColor = seColorEntry(
  83. mainFrame, text = 'Light Color', value=self.lightColor)
  84. self.lightColor['command'] = self.setLightingColorVec
  85. self.lightColor['resetValue'] = [0.3*255,0.3*255,0.3*255,0]
  86. self.lightColor.pack(fill=Tkinter.X,expand=0)
  87. self.bind(self.lightColor, 'Set light color')
  88. # Notebook pages for light specific controls
  89. self.lightNotebook = Pmw.NoteBook(mainFrame, tabpos = None,
  90. borderwidth = 0)
  91. ambientPage = self.lightNotebook.add('Ambient')
  92. directionalPage = self.lightNotebook.add('Directional')
  93. pointPage = self.lightNotebook.add('Point')
  94. spotPage = self.lightNotebook.add('Spot')
  95. # Put this here so it isn't called right away
  96. self.lightNotebook['raisecommand'] = self.updateLightInfo
  97. # Directional light controls
  98. self.dSpecularColor = seColorEntry(
  99. directionalPage, text = 'Specular Color')
  100. self.dSpecularColor['command'] = self.setSpecularColor
  101. self.dSpecularColor.pack(fill = Tkinter.X, expand = 0)
  102. self.bind(self.dSpecularColor,
  103. 'Set directional light specular color')
  104. self.dPosition = Vector3Entry(
  105. directionalPage, text = 'Position')
  106. self.dPosition['command'] = self.setPosition
  107. self.dPosition['resetValue'] = [0,0,0,0]
  108. self.dPosition.pack(fill = Tkinter.X, expand = 0)
  109. self.bind(self.dPosition, 'Set directional light position')
  110. self.dOrientation = Vector3Entry(
  111. directionalPage, text = 'Orientation')
  112. self.dOrientation['command'] = self.setOrientation
  113. self.dOrientation['resetValue'] = [0,0,0,0]
  114. self.dOrientation.pack(fill = Tkinter.X, expand = 0)
  115. self.bind(self.dOrientation, 'Set directional light orientation')
  116. # Point light controls
  117. self.pSpecularColor = seColorEntry(
  118. pointPage, text = 'Specular Color')
  119. self.pSpecularColor['command'] = self.setSpecularColor
  120. self.pSpecularColor.pack(fill = Tkinter.X, expand = 0)
  121. self.bind(self.pSpecularColor,
  122. 'Set point light specular color')
  123. self.pPosition = Vector3Entry(
  124. pointPage, text = 'Position')
  125. self.pPosition['command'] = self.setPosition
  126. self.pPosition['resetValue'] = [0,0,0,0]
  127. self.pPosition.pack(fill = Tkinter.X, expand = 0)
  128. self.bind(self.pPosition, 'Set point light position')
  129. self.pConstantAttenuation = Slider(
  130. pointPage,
  131. text = 'Constant Attenuation',
  132. max = 1.0,
  133. resolution = 0.01,
  134. value = 1.0)
  135. self.pConstantAttenuation['command'] = self.setConstantAttenuation
  136. self.pConstantAttenuation.pack(fill = Tkinter.X, expand = 0)
  137. self.bind(self.pConstantAttenuation,
  138. 'Set point light constant attenuation')
  139. self.pLinearAttenuation = Slider(
  140. pointPage,
  141. text = 'Linear Attenuation',
  142. max = 1.0,
  143. resolution = 0.01,
  144. value = 0.0)
  145. self.pLinearAttenuation['command'] = self.setLinearAttenuation
  146. self.pLinearAttenuation.pack(fill = Tkinter.X, expand = 0)
  147. self.bind(self.pLinearAttenuation,
  148. 'Set point light linear attenuation')
  149. self.pQuadraticAttenuation = Slider(
  150. pointPage,
  151. text = 'Quadratic Attenuation',
  152. max = 1.0,
  153. resolution = 0.01,
  154. value = 0.0)
  155. self.pQuadraticAttenuation['command'] = self.setQuadraticAttenuation
  156. self.pQuadraticAttenuation.pack(fill = Tkinter.X, expand = 0)
  157. self.bind(self.pQuadraticAttenuation,
  158. 'Set point light quadratic attenuation')
  159. # Spot light controls
  160. self.sSpecularColor = seColorEntry(
  161. spotPage, text = 'Specular Color')
  162. self.sSpecularColor['command'] = self.setSpecularColor
  163. self.sSpecularColor.pack(fill = Tkinter.X, expand = 0)
  164. self.bind(self.sSpecularColor,
  165. 'Set spot light specular color')
  166. self.sConstantAttenuation = Slider(
  167. spotPage,
  168. text = 'Constant Attenuation',
  169. max = 1.0,
  170. resolution = 0.01,
  171. value = 1.0)
  172. self.sConstantAttenuation['command'] = self.setConstantAttenuation
  173. self.sConstantAttenuation.pack(fill = Tkinter.X, expand = 0)
  174. self.bind(self.sConstantAttenuation,
  175. 'Set spot light constant attenuation')
  176. self.sLinearAttenuation = Slider(
  177. spotPage,
  178. text = 'Linear Attenuation',
  179. max = 1.0,
  180. resolution = 0.01,
  181. value = 0.0)
  182. self.sLinearAttenuation['command'] = self.setLinearAttenuation
  183. self.sLinearAttenuation.pack(fill = Tkinter.X, expand = 0)
  184. self.bind(self.sLinearAttenuation,
  185. 'Set spot light linear attenuation')
  186. self.sQuadraticAttenuation = Slider(
  187. spotPage,
  188. text = 'Quadratic Attenuation',
  189. max = 1.0,
  190. resolution = 0.01,
  191. value = 0.0)
  192. self.sQuadraticAttenuation['command'] = self.setQuadraticAttenuation
  193. self.sQuadraticAttenuation.pack(fill = Tkinter.X, expand = 0)
  194. self.bind(self.sQuadraticAttenuation,
  195. 'Set spot light quadratic attenuation')
  196. self.sExponent = Slider(
  197. spotPage,
  198. text = 'Exponent',
  199. max = 1.0,
  200. resolution = 0.01,
  201. value = 0.0)
  202. self.sExponent['command'] = self.setExponent
  203. self.sExponent.pack(fill = Tkinter.X, expand = 0)
  204. self.bind(self.sExponent,
  205. 'Set spot light exponent')
  206. # MRM: Add frustum controls
  207. self.lightNotebook.setnaturalsize()
  208. self.lightNotebook.pack(expand = 1, fill = Tkinter.BOTH)
  209. mainFrame.pack(expand=1, fill = Tkinter.BOTH)
  210. def onDestroy(self, event):
  211. messenger.send('LP_close')
  212. '''
  213. If you have open any thing, please rewrite here!
  214. '''
  215. pass
  216. def renameLight(self):
  217. #################################################################
  218. # renameLight(self)
  219. # Call Back function
  220. # This function will be called when user push
  221. # the "Rename" button on the panel.
  222. #
  223. # Then, this function will collect data and send out them with a message
  224. # "LP_rename"
  225. # Which will be caught by sceneEditor and pass to dataHolder to
  226. # complete the renaming.
  227. #
  228. #################################################################
  229. oName = self.currentLight
  230. nName = self.lightEntry.get()
  231. messenger.send('LP_rename',[oName,nName])
  232. return
  233. def deleteLight(self):
  234. #################################################################
  235. # deleteLight(self)
  236. # Call Back Function.
  237. # This function will be called when user click on
  238. # the "Delete" button on the panel.
  239. #
  240. # Then, this function will send out a message with current seleted light
  241. # "LP_removeLight"
  242. # Which will be caught by sceneEditor and pass to dataHolder to
  243. # complete the delete process.
  244. #
  245. #################################################################
  246. messenger.send('LP_removeLight',[self.currentLight])
  247. return
  248. def updateList(self, list, node=None):
  249. #################################################################
  250. # updataList(self, list, node = None)
  251. # This function will take a list object which contains names of lights in the scene.
  252. # Also, if user has put node as a parameter,
  253. # this function will automatically select that node as the current working target.
  254. #################################################################
  255. self.lightList = list
  256. self.lightEntry.setlist(list)
  257. if node!=None:
  258. self.lightEntry.selectitem(index=node.getName(), setentry=True )
  259. self.updateDisplay(node)
  260. elif len(list)>0:
  261. self.lightEntry.selectitem(index=0, setentry=True )
  262. self.selectLight(list[0])
  263. else:
  264. self.lightEntry.clear()
  265. return
  266. def selectLight(self, lightName):
  267. #################################################################
  268. # selectLight(self, lightName)
  269. # This function will be called each time when
  270. # user select a light from the list on the panel.
  271. # Then, this function will send out the message,
  272. # 'LP_selectLight' to sceneEditorand get the current light information from dataHolder.
  273. #################################################################
  274. if lightName in self.lightList:
  275. messenger.send('LP_selectLight',[lightName])
  276. return
  277. def updateDisplay(self, lightNode):
  278. #################################################################
  279. # updateDisplay(self, lightNode)
  280. # This function will update the information showing on the panel.
  281. # For example, give a lightNode which is a Point Light.
  282. # This function will switch the page to specify the type.
  283. # Also, new node is the same type with the previous one,
  284. # then this is function won't do the page switching,
  285. # but will call other function to refresh the data to target node.
  286. #################################################################
  287. self.currentLight = lightNode
  288. if self.currentLight != None:
  289. color = lightNode.getLightColor()
  290. self.lightColor.set([255*color.getX(),255*color.getY(),255*color.getZ()])
  291. oldType = self.type
  292. self.type = lightNode.getType()
  293. else:
  294. self.lightColor.set([255*0.3,255*0.3,255*0.3])
  295. oldType = self.type
  296. self.type = 'ambient'
  297. if self.type=='ambient':
  298. self.lightNotebook.selectpage('Ambient')
  299. elif self.type =='directional':
  300. self.lightNotebook.selectpage('Directional')
  301. elif self.type =='point':
  302. self.lightNotebook.selectpage('Point')
  303. elif self.type =='spot':
  304. self.lightNotebook.selectpage('Spot')
  305. if oldType == self.type:
  306. # The same type with previous one, call updateLightInfo to refresh the values.
  307. self.updateLightInfo()
  308. return
  309. def updateLightInfo(self, page=None):
  310. #################################################################
  311. # updateLightInfo(self, page=None)
  312. # This function will refresh the data we user have done any selection.
  313. #################################################################
  314. if self.currentLight != None:
  315. light = self.currentLight.getLight()
  316. if self.type != 'ambient':
  317. specColor = light.getSpecularColor()
  318. if self.type =='directional':
  319. point = self.currentLight.getPosition()
  320. dir = self.currentLight.getOrientation()
  321. self.dSpecularColor.set([specColor.getX()*255,specColor.getY()*255,specColor.getZ()*255])
  322. self.dPosition.set([point.getX(),point.getY(),point.getZ()])
  323. self.dOrientation.set([dir.getX(),dir.getY(),dir.getZ()])
  324. elif self.type =='point':
  325. point = self.currentLight.getPosition()
  326. attenuation = light.getAttenuation()
  327. self.pSpecularColor.set([specColor.getX()*255,specColor.getY()*255,specColor.getZ()*255])
  328. self.pPosition.set([point.getX(),point.getY(),point.getZ()])
  329. self.pConstantAttenuation.set(attenuation.getX())
  330. self.pLinearAttenuation.set(attenuation.getY())
  331. self.pQuadraticAttenuation.set(attenuation.getZ())
  332. elif self.type =='spot':
  333. attenuation = light.getAttenuation()
  334. expo = light.getExponent()
  335. self.sSpecularColor.set([specColor.getX()*255,specColor.getY()*255,specColor.getZ()*255])
  336. self.sConstantAttenuation.set(attenuation.getX())
  337. self.sLinearAttenuation.set(attenuation.getY())
  338. self.sQuadraticAttenuation.set(attenuation.getZ())
  339. self.sExponent.set(expo)
  340. return
  341. def addAmbient(self):
  342. #################################################################
  343. # addAmbient(self)
  344. # This function will send out a message to
  345. # ask dataHolder to create a default ambient light
  346. #################################################################
  347. messenger.send('LP_addLight',['ambient'])
  348. return
  349. def addDirectional(self):
  350. #################################################################
  351. # addDirectional(self)
  352. # This function will send out a message to
  353. # sk dataHolder to create a default Directional light
  354. #################################################################
  355. messenger.send('LP_addLight',['directional'])
  356. return
  357. def addPoint(self):
  358. #################################################################
  359. # addPoint(self)
  360. # This function will send out a message to
  361. # ask dataHolder to create a default Point light
  362. #################################################################
  363. messenger.send('LP_addLight',['point'])
  364. return
  365. def addSpot(self):
  366. #################################################################
  367. # addSpot(self)
  368. # This function will send out a message to
  369. # ask dataHolder to create a default Spot light
  370. #################################################################
  371. messenger.send('LP_addLight',['spot'])
  372. return
  373. def setLightingColorVec(self,color):
  374. #################################################################
  375. # setLightingColorVec(self,color)
  376. # Call Back function. This will be called
  377. # when user try to change the color of light.
  378. #################################################################
  379. if self.currentLight==None:
  380. return
  381. self.currentLight.setColor(VBase4((color[0]/255),(color[1]/255),(color[2]/255),1))
  382. return
  383. def setSpecularColor(self,color):
  384. #################################################################
  385. # setSpecularColor(self,color)
  386. # Call Back function. This will be called
  387. # when user try to change the Specular color of light.
  388. #################################################################
  389. if self.currentLight==None:
  390. return
  391. self.currentLight.setSpecColor(VBase4((color[0]/255),(color[1]/255),(color[2]/255),1))
  392. return
  393. def setPosition(self,position):
  394. #################################################################
  395. # setPosition(self,position)
  396. # Call Back function. This will be called
  397. # when user try to change the position of light.
  398. #################################################################
  399. if self.currentLight==None:
  400. return
  401. self.currentLight.setPosition(Point3(position[0],position[1],position[2]))
  402. return
  403. def setOrientation(self, orient):
  404. #################################################################
  405. # setOrientation(self, orient)
  406. # Call Back function. This will be called
  407. # when user try to change the orientation of light.
  408. #################################################################
  409. if self.currentLight==None:
  410. return
  411. self.currentLight.setOrientation(Vec3(orient[0],orient[1],orient[2]))
  412. return
  413. def setConstantAttenuation(self, value):
  414. #################################################################
  415. # setConstantAttenuation(self, value)
  416. # Call Back function. This will be called
  417. # when user try to change the Constant Attenuation of light.
  418. #################################################################
  419. self.currentLight.setConstantAttenuation(value)
  420. return
  421. def setLinearAttenuation(self, value):
  422. #################################################################
  423. # setLinearAttenuation(self, value)
  424. # Call Back function. This will be called
  425. # when user try to change the Linear Attenuation of light.
  426. #################################################################
  427. self.currentLight.setLinearAttenuation(value)
  428. return
  429. def setQuadraticAttenuation(self, value):
  430. #################################################################
  431. # setQuadraticAttenuation(self, value)
  432. # Call Back function. This will be called
  433. # when user try to change the Quadratic Attenuation of light.
  434. #################################################################
  435. self.currentLight.setQuadraticAttenuation(value)
  436. return
  437. def setExponent(self, value):
  438. #################################################################
  439. # setExponent(self, value)
  440. # Call Back function. This will be called
  441. # when user try to change Exponent value of light.
  442. #################################################################
  443. self.currentLight.setExponent(value)
  444. return