Files
@ 4455a7e86643
Branch filter:
Location: light9/lightsim/lightsim.py
4455a7e86643
4.6 KiB
text/x-python
added a note about the funny read order
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | # lightsim.py by Drew Perttula, 6/28/2002
version="1.01"
from __future__ import division
import Image, ImageTk, ImageChops,ImageEnhance
from Tkinter import Tk,Label,Scale,DoubleVar,Frame
import time, glob
class Imagemixer(Label):
"""tk widget that can load images (based on a glob pattern: each file should
be named like 'scene.light') and displays a weighted mix of the images"""
def __init__(self,parent,*k,**kw):
Label.__init__(self,parent,*k,**kw)
self.im={}
self.itk = ImageTk.PhotoImage(Image.new('RGB',(100,100)))
self.config(image=self.itk)
self.loadedscale=0
self.amounts={}
def loadallimgs(self,basename,scalefactor=1.0):
"""load images from disk, scale them immediately, subtract off
the image called 'ambient' (if present) from all other
images. Given basename like path/to/foo, loads images with
names like path/to/foo.light1, path/to/foo.light2, etc. The
filename after the . is considered to be the light name
throughout the program. """
if self.loadedscale==scalefactor: # already loaded at this scale
return
self.im={}
ambientimg=None
sizenotset=1
for fullname in glob.glob(basename+".*"):
x=fullname[fullname.find('.')+1:]
self.im[x]=Image.open(fullname)
if scalefactor!=1.0:
self.im[x]=self.im[x].resize([a*scalefactor for a in self.im[x].size])
if x=='ambient':
ambientimg=self.im[x]
if sizenotset:
self.config(width=self.im[x].size[0],height=self.im[x].size[1])
self.itk=ImageTk.PhotoImage(Image.new('RGB',self.im[x].size))
self.config(image=self.itk)
sizenotset=0
# subtract off an image called 'ambient' from all the rest
if ambientimg is not None:
for k in self.im.keys():
if k!='ambient':
self.im[k] = ImageChops.subtract(self.im[k],ambientimg)
self.loadedscale=scalefactor
self._remix() # update the image
def _remix(self):
"""mix all the images in self.im together according to the
weights in self.amounts. Each of those attributes are dicts
with the light names for keys."""
global fpslabel
i=None
amounts = self.amounts
layers=0
start=time.time()
for k in self.im.keys():
scale =amounts.get(k,0)
if scale!=0:
layers+=1
acc=ImageEnhance.Brightness(self.im[k]).enhance(scale) # scale the image before adding
# acc = ImageChops.add(base,self.im[k],1/scale) ## slower!
if i==None:
i=acc # use first layer directly
else:
i=ImageChops.add(i,acc) # add subsequent layers
dur = time.time()-start
fps=1.0/dur
fpslabel.config(text="%.02f fps, %.02f layers/sec"%(fps,layers/dur))
if i is not None:
self.itk.paste(i) # put image i in the PhotoImage
def setamounts(self,amounts):
self.amounts = amounts.copy()
self._remix()
def lightnames(self):
return self.im.keys()
basename='room'
root=Tk()
# Imagemixer._remix accesses this label, so it needs a name
fpslabel=Label()
fpslabel.pack()
Label(root,text="Use +/- to change image scale").pack()
mix=Imagemixer(root,relief='raised',bd=3)
scalefactor=.5
mix.loadallimgs(basename,scalefactor)
mix.pack()
#
# +/- keys should reload the images at new scales
#
def changescale(by=0):
global mix,scalefactor
scalefactor+=by
mix.loadallimgs(basename,scalefactor)
root.bind("<Key-plus>",lambda ev: changescale(.15))
root.bind("<Key-minus>",lambda ev: changescale(-.15))
amountvars={} # each light name maps to a Tkinter.DoubleVar object which the Scale adjusts
def redraw(*args):
global l,amountvars,update
# read the value out of each Scale
amounts = dict([(k,v.get()) for k,v in amountvars.items()])
mix.setamounts(amounts)
for x in mix.lightnames():
# the Scale sets this; the redraw() callback reads it
amountvars[x]=DoubleVar()
# a new frame for each slider row
f=Frame(root,bd=1,relief='groove')
f.pack(fill='x',expand=1)
# title
Label(f,text=x,width=10,anchor='e').pack(side='left')
# slider
s=Scale(f,from_=0,to=1,res=.01,
orient='horiz',
variable=amountvars[x],command=redraw)
s.pack(side='left',fill='x',expand=1)
if x=='ambient': # the 'ambient' level (if present) starts at 1
s.set(1)
root.mainloop()
|