changeset 353:941cfe1e1691

lightsim now reads levels from dmxserver
author drewp@bigasterisk.com
date Mon, 11 Jun 2007 00:53:16 +0000
parents 9d1f323fb3d3
children f3909c2df943
files bin/dmxserver bin/lightsim lightsim/openglsim.py lightsim/skyline/layers.xcf
diffstat 4 files changed, 150 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/bin/dmxserver	Sun Jun 10 17:25:23 2007 +0000
+++ b/bin/dmxserver	Mon Jun 11 00:53:16 2007 +0000
@@ -78,13 +78,16 @@
         reactor.callLater(1,self.purgeclients)
 
         now=time.time()
-        cids=self.clientlevels.keys()
+        cids = self.lastseen.keys()
         for cid in cids:
             lastseen=self.lastseen[cid]
-            if lastseen<now-purge_age:
+            if lastseen < now - purge_age:
                 print ("forgetting client %s (no activity for %s sec)" %
                        (cid,purge_age))
-                del self.clientlevels[cid]
+                try:
+                    del self.clientlevels[cid]
+                except KeyError:
+                    pass
                 del self.clientfreq[cid]
                 del self.lastseen[cid]
         
@@ -167,18 +170,33 @@
         if levellist!=self.clientlevels.get(cid,None):
             self.clientlevels[cid]=levellist
             self.clientschanged=1
-            if cid not in self.lastseen:
-                print "hello new client %s" % cid
-                self.clientfreq[cid]=Updatefreq()
-                
+        self.trackClientFreq(cid)
+        return "ok"
+
+    def xmlrpc_currentlevels(self, cid):
+        """get a list of levels we're currently sending out. All
+        channels beyond the list you get back, they're at zero."""
+        # if this is still too slow, it might help to return a single
+        # pickled string
+        self.trackClientFreq(cid)
+        trunc = self.combinedlevels[:]
+        i = len(trunc) - 1
+        if i < 0:
+            return []
+        while trunc[i] == 0 and i >= 0:
+            i -= 1
+        if i < 0:
+            return []
+        trunc = trunc[:i+1]
+        return trunc
+    
+    def trackClientFreq(self, cid):
+        if cid not in self.lastseen:
+            print "hello new client %s" % cid
+            self.clientfreq[cid]=Updatefreq()
         self.lastseen[cid]=time.time()
         self.clientfreq[cid].update()
-        return "ok"
-
-    def xmlrpc_currentlevels(self):
-        """get a list of levels we're currently sending out. All
-        channels beyond the list you get back, they're at zero."""
-        return self.combinedlevels
+        
 
 parser=OptionParser()
 parser.add_option("-f","--fast-updates",action='store_true',
--- a/bin/lightsim	Sun Jun 10 17:25:23 2007 +0000
+++ b/bin/lightsim	Mon Jun 11 00:53:16 2007 +0000
@@ -12,9 +12,9 @@
 logging.basicConfig(format="%(asctime)s %(levelname)-5s %(name)s %(filename)s:%(lineno)d: %(message)s")
 log.setLevel(logging.DEBUG)
 import Tkinter as tk
-from light9 import networking, Patch, showconfig, dmxclient
+from light9 import networking, Patch, showconfig, dmxclient, updatefreq
 from light9.namespaces import L9
-
+from louie import dispatcher
 
 try:
     from OpenGL import Tk as Togl
@@ -26,57 +26,81 @@
   
 from lightsim.openglsim import Surface
 
-
-
+def poll(graph, serv, pollFreq):
+    pollFreq.update()
+    dispatcher.send("status", key="pollFreq", value=str(pollFreq))
+    d = serv.callRemote("currentlevels", dmxclient._id)
+    def received(dmxLevels):
+        level = {} # filename : level
+        for i, lev in enumerate(dmxLevels):
+            if lev == 0:
+                continue
 
-def poll(graph, serv):
-    dmxLevels = serv.currentlevels(dmxclient._id)
-    level = {} # filename : level
-    for i, lev in enumerate(dmxLevels):
-        if lev == 0:
-            continue
+            try:
+                chan = Patch.get_channel_uri(Patch.get_channel_name(i + 1))
+            except KeyError:
+                continue
+
+            for lyr in graph.objects(chan, L9['previewLayer']):
+                for imgPath in graph.objects(lyr, L9['path']):
+                    level[str(imgPath)] = lev
 
-        try:
-            chan = Patch.get_channel_uri(Patch.get_channel_name(i + 1))
-        except KeyError:
-            continue
+        ogl.newLevels(levels=level)
+    d.addCallback(received)
+    return d
 
-        for lyr in graph.objects(chan, L9['previewLayer']):
-            for imgPath in graph.objects(lyr, L9['path']):
-                level[str(imgPath)] = lev
-
-    print level
-    ogl.newLevels(levels=level)
-
+class StatusKeys(tk.Frame):
+    # watch out- this might be an accidental redo of what curvecalc
+    # has. Or, maybe CC should use this obj
+    def __init__(self, master):
+        tk.Frame.__init__(self, master)
+        dispatcher.connect(self.status, "status")
+        self.row = {} # key name : (Frame, value Label)
+        
+    def status(self, key, value):
+        if key not in self.row:
+            f = tk.Frame(self)
+            f.pack(side='top')
+            tk.Label(f, text=key, font="arial 8").pack(side='left')
+            l = tk.Label(f, text=value, font="arial 8")
+            l.pack(side='left')
+            self.row[key] = (f, l)
+        else:
+            row, lab = self.row[key]
+            lab.config(text=value)
 
 root = tk.Frame()
 root.pack(expand=True, fill='both')
-QuitButton = tk.Button(root, {'text':'Quit'})
-QuitButton.bind('<ButtonRelease-1>', sys.exit)
-QuitButton.pack()
-
-filenames=['lightsim/skyline/bg.png',
-           'lightsim/skyline/cyc-lo-red.png',
-           'lightsim/skyline/cyc-lo-grn.png',
-           ]
+pollFreq = updatefreq.Updatefreq(samples=5)
+graph = showconfig.getGraph()
+filenames = []
+for lyr in graph.objects(None, L9['previewLayer']):
+    for p in graph.objects(lyr, L9['path']):
+        filenames.append(str(p))
 
-scales = {} # filename : scale
-for f in filenames:
-    scales[f] = tk.Scale(
-        root, label=f, from_=0, to=1, res=.05, orient='horiz',
-        command=lambda *args: ogl.newLevels(
-          levels=dict([(f, s.get()) for f,s in scales.items()])))
-    scales[f].pack()
-ogl = Surface(root, filenames)
+ogl = Surface(root, filenames, width=120, height=80, imgRescaleTo=128)
 ogl.pack(side='top', expand=True, fill='both')
 
-graph = showconfig.getGraph()
-serv = Proxy(networking.dmxServerUrl())
-LoopingCall(poll, graph, serv).start(1)
+sk = StatusKeys(root)
+sk.pack(side='top', fill='x')
+
 
 
-root.winfo_toplevel().bind("<Control-Key-q>",lambda ev: reactor.stop)
-root.winfo_toplevel().bind("<Destroy>",lambda ev: reactor.stop)
-root.winfo_toplevel().protocol('WM_DELETE_WINDOW', reactor.stop)
+serv = Proxy(networking.dmxServerUrl())
+LoopingCall(poll, graph, serv, pollFreq).start(.1)
+
+top = root.winfo_toplevel()
+top.wm_title(dmxclient._id)
+top.bind("<Control-Key-q>",lambda ev: reactor.stop)
+top.bind("<Destroy>",lambda ev: reactor.stop)
+top.protocol('WM_DELETE_WINDOW', reactor.stop)
 tksupport.install(ogl, ms=20)
-reactor.run()
+
+if 0:
+    import hotshot, hotshot.stats
+    p = hotshot.Profile("/tmp/pro")
+    p.runcall(reactor.run)
+    p.close()
+    hotshot.stats.load("/tmp/pro").sort_stats('time').print_stats()
+else:
+    reactor.run()
--- a/lightsim/openglsim.py	Sun Jun 10 17:25:23 2007 +0000
+++ b/lightsim/openglsim.py	Mon Jun 11 00:53:16 2007 +0000
@@ -6,7 +6,7 @@
 import numarray as num
 import Tkinter as tk
 import Image
-
+from louie import dispatcher
 try:
     from OpenGL import Tk as Togl
     from OpenGL.GL import *
@@ -27,20 +27,24 @@
     glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, imgString)
 
 class Surface(Togl.Opengl):
-    width = 512
-    height = 270
-    imgRescaleTo = 100
-    def __init__(self, master, filenames):
-        Togl.Opengl.__init__(self, master=master, width = self.width,
-                             height = self.height, double = True, depth = 0)
+    """widget that adds multiple image files together with adjustable scales"""
+    def __init__(self, master, filenames, width=512, height=270,
+                 imgRescaleTo=None):
+        """
+        imgRescaleTo can be a length of pixels to reduce all the input
+        images into. Try 64 for a low res drawing.
+        """
+        Togl.Opengl.__init__(self, master=master, width=width,
+                             height=height, double=True, depth=0)
+        self.width, self.height = width, height
 
         self.levels = {} # filename : brightness
   
         self.image = {} # filename : imgstr
         for filename in filenames:
             im = Image.open(filename)
-            if self.imgRescaleTo:
-                im.thumbnail((self.imgRescaleTo, self.imgRescaleTo))
+            if imgRescaleTo:
+                im.thumbnail((imgRescaleTo, imgRescaleTo))
             im = im.transpose(Image.FLIP_TOP_BOTTOM)
             self.imageWidth = im.size[0]
             self.imageHeight = im.size[1]
@@ -57,9 +61,35 @@
         self.bind("<Configure>", self.configure)
 
     def configure(self, ev):
-#        import pdb; pdb.set_trace()
         self.width, self.height = ev.width, ev.height
   
+    def redraw(self, event=None):
+        """you set self.levels to dict and call tkRedraw"""
+        assert 'GL_ARB_imaging' in glGetString(GL_EXTENSIONS).split()
+        start = time.time()
+        
+        glClearColor(0.0, 0.0, 0.0, 0)
+        glClear( GL_COLOR_BUFFER_BIT |GL_ACCUM_BUFFER_BIT)
+        glEnable(GL_BLEND)
+        glBlendFunc(GL_SRC_ALPHA, GL_ONE) # add
+        
+#        l=glGenLists(1)
+#        glNewList(l,GL_COMPILE)
+#        glEndList()
+
+        # drawing to glAccum might be good
+        layerTimes = []
+        for filename, mag in self.levels.items():
+            #print "pic %s at %f" % (filename, mag)
+            t = time.time()
+            self.drawWithAlpha(self.image[filename],
+                               self.imageWidth, self.imageHeight, mag)
+            layerTimes.append(time.time() - t)
+
+        dispatcher.send("status", key="redraw",
+                        value="%.1fms" % ((time.time() - start) * 1000))
+        
+
     def drawWithAlpha(self, imgString, w, h, alpha):
         """without opengl extensions"""
         if alpha == 0:
@@ -72,32 +102,23 @@
             ar[:,3] *= alpha
 
         #print "  scl", time.time() - t
+
+        # this might be a good way to scale the color channels too,
+        # but the blend might take two steps. Anyway,
+        # GL_CONSTANT_COLOR seems not to work, so i'm not exploring
+        # this right now.
+        #glBlendFunc(GL_CONSTANT_COLOR, GL_ONE)
+        #glBlendColor(.8, .5, .5, .5)
+        
         glPixelZoom(self.width / w, self.height / h)
         glDrawPixels(w, h,
                      GL_RGBA, GL_UNSIGNED_BYTE, ar.tostring())
         #print "  draw", time.time() - t
 
-    def redraw(self, event=None):
-        """you set self.levels to dict and call tkRedraw"""
-        assert 'GL_ARB_imaging' in glGetString(GL_EXTENSIONS).split()
-    
-        glClearColor(0.0, 0.0, 0.0, 0)
-        glClear( GL_COLOR_BUFFER_BIT |GL_ACCUM_BUFFER_BIT)
-        glEnable(GL_BLEND)
-        glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA)
-#        l=glGenLists(1)
-#        glNewList(l,GL_COMPILE)
-#        glEndList()
-
-        # drawing to glAccum might be good
-        for filename, mag in self.levels.items():
-            #print "pic %s at %f" % (filename, mag)
-            self.drawWithAlpha(self.image[filename],
-                               self.imageWidth, self.imageHeight, mag)
-
     def newLevels(self, event=None, levels=None):
-        self.levels = levels
-        self.tkRedraw()
+        if levels != self.levels:
+            self.levels = levels
+            self.tkRedraw()
   
 def main():
     root = tk.Frame()
Binary file lightsim/skyline/layers.xcf has changed