commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] r10532 - gnuradio/branches/developers/jblum/gui_guts/g


From: jblum
Subject: [Commit-gnuradio] r10532 - gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter
Date: Fri, 27 Feb 2009 09:50:29 -0700 (MST)

Author: jblum
Date: 2009-02-27 09:50:28 -0700 (Fri, 27 Feb 2009)
New Revision: 10532

Added:
   
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/common.py
Modified:
   
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/Makefile.am
   
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/channel_plotter.py
   
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/plotter_base.py
   
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/waterfall_plotter.py
Log:
interface for caching drawing with compiled lists

Modified: 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/Makefile.am
===================================================================
--- 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/Makefile.am
 2009-02-27 03:35:20 UTC (rev 10531)
+++ 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/Makefile.am
 2009-02-27 16:50:28 UTC (rev 10532)
@@ -1,5 +1,5 @@
 #
-# Copyright 2004,2005,2008 Free Software Foundation, Inc.
+# Copyright 2004,2005,2008,2009 Free Software Foundation, Inc.
 # 
 # This file is part of GNU Radio
 # 
@@ -31,6 +31,7 @@
 ourpython_PYTHON =                     \
        __init__.py                     \
        channel_plotter.py              \
+       common.py                       \
        gltext.py                       \
        plotter_base.py                 \
        waterfall_plotter.py

Modified: 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/channel_plotter.py
===================================================================
--- 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/channel_plotter.py
  2009-02-27 03:35:20 UTC (rev 10531)
+++ 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/channel_plotter.py
  2009-02-27 16:50:28 UTC (rev 10532)
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -23,6 +23,7 @@
 from plotter_base import grid_plotter_base
 from OpenGL.GL import *
 from gnuradio.wxgui import common
+import common as _common
 import numpy
 import gltext
 import math
@@ -47,15 +48,21 @@
                """
                #init
                grid_plotter_base.__init__(self, parent, PADDING)
+               #setup legend cache
+               self._legend_cache = _common.gl_cache(self._draw_legend)
+               self.register_init(self._legend_cache.init)
+               self.register_draw(self._legend_cache.draw)
+               #setup channel plotter
                self._channels = dict()
                self.enable_legend(False)
+               self.register_init(self._init_channel_plotter)
+               self.register_draw(self._draw_waveforms)
 
-       def _gl_init(self):
+       def _init_channel_plotter(self):
                """
                Run gl initialization tasks.
                """
                glEnableClientState(GL_VERTEX_ARRAY)
-               self._grid_compiled_list_id = glGenLists(1)
 
        def enable_legend(self, enable=None):
                """
@@ -66,24 +73,14 @@
                if enable is None: return self._enable_legend
                self.lock()
                self._enable_legend = enable
-               self.changed(True)
+               self._legend_cache.changed(True)
                self.unlock()
 
-       def draw(self):
+       def _draw_waveforms(self):
                """
-               Draw the grid and waveforms.
+               Draw the waveforms for each channel.
+               Scale the waveform data to the grid using gl matrix operations.
                """
-               self.lock()
-               self.clear()
-               #store the grid drawing operations
-               if self.changed():
-                       glNewList(self._grid_compiled_list_id, GL_COMPILE)
-                       self._draw_grid()
-                       self._draw_legend()
-                       glEndList()
-                       self.changed(False)
-               #draw the grid
-               glCallList(self._grid_compiled_list_id)
                #use scissor to prevent drawing outside grid
                glEnable(GL_SCISSOR_TEST)
                glScissor(
@@ -92,19 +89,6 @@
                        self.width-self.padding_left-self.padding_right-1,
                        self.height-self.padding_top-self.padding_bottom-1,
                )
-               #draw the waveforms
-               self._draw_waveforms()
-               glDisable(GL_SCISSOR_TEST)
-               self._draw_point_label()
-               #swap buffer into display
-               self.SwapBuffers()
-               self.unlock()
-
-       def _draw_waveforms(self):
-               """
-               Draw the waveforms for each channel.
-               Scale the waveform data to the grid using gl matrix operations.
-               """
                for channel in reversed(sorted(self._channels.keys())):
                        samples = self._channels[channel][SAMPLES_KEY]
                        num_samps = len(samples)
@@ -137,6 +121,7 @@
                                glVertexPointerf(points)
                                glDrawArrays(GL_POINTS, 0, len(points))
                        glPopMatrix()
+               glDisable(GL_SCISSOR_TEST)
 
        def _populate_point_label(self, x_val, y_val):
                """
@@ -164,7 +149,8 @@
                        x_index = 
(num_samps-1)*(x_val/self.x_scalar-self.x_min)/(self.x_max-self.x_min)
                        x_index_low = int(math.floor(x_index))
                        x_index_high = int(math.ceil(x_index))
-                       y_value = (samples[x_index_high] - 
samples[x_index_low])*(x_index - x_index_low) + samples[x_index_low]
+                       scale = x_index - x_index_low + 
self._channels[channel][TRIG_OFF_KEY]
+                       y_value = (samples[x_index_high] - 
samples[x_index_low])*scale + samples[x_index_low]
                        label_str += '\n%s: %s %s'%(channel, 
common.label_format(y_value), self.y_units)
                return label_str
 
@@ -201,7 +187,7 @@
                self.lock()
                if channel in self._channels.keys():
                        self._channels.pop(channel)
-                       self.changed(True)
+                       self._legend_cache.changed(True)
                self.unlock()
 
        def set_waveform(self, channel, samples=[], color_spec=(0, 0, 0), 
marker=None, trig_off=0):
@@ -214,7 +200,7 @@
                @param trig_off fraction of sample for trigger offset
                """
                self.lock()
-               if channel not in self._channels.keys(): self.changed(True)
+               if channel not in self._channels.keys(): 
self._legend_cache.changed(True)
                self._channels[channel] = {
                        SAMPLES_KEY: samples,
                        COLOR_SPEC_KEY: color_spec,

Added: 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/common.py
===================================================================
--- 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/common.py
                           (rev 0)
+++ 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/common.py
   2009-02-27 16:50:28 UTC (rev 10532)
@@ -0,0 +1,115 @@
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import threading
+import time
+import wx
+from OpenGL import GL
+
+##################################################
+# Interface with thread safe lock/unlock
+##################################################
+class mutex(object):
+       _lock = threading.Lock()
+       def lock(self): self._lock.acquire()
+       def unlock(self): self._lock.release()
+
+##################################################
+# Period update thread for point label
+##################################################
+class point_label_thread(threading.Thread, mutex):
+
+       def __init__(self, plotter):
+               self._plotter = plotter
+               self._coor_queue = list()
+               #bind plotter mouse events
+               self._plotter.Bind(wx.EVT_MOTION, lambda evt: 
self.enqueue(evt.GetPosition()))
+               self._plotter.Bind(wx.EVT_LEAVE_WINDOW, lambda evt: 
self.enqueue(None))
+               #start the thread
+               threading.Thread.__init__(self)
+               self.start()
+
+       def enqueue(self, coor):
+               self.lock()
+               self._coor_queue.append(coor)
+               self.unlock()
+
+       def run(self):
+               last_ts = time.time()
+               last_coor = coor = None
+               while True:
+                       time.sleep(1.0/30.0)
+                       self.lock()
+                       #get most recent coor change
+                       if self._coor_queue:
+                               coor = self._coor_queue[-1]
+                               self._coor_queue = list()
+                       self.unlock()
+                       #update if coor change, or enough time expired
+                       if last_coor != coor or (time.time() - last_ts) > 
(1.0/2.0):
+                               try: 
self._plotter.set_point_label_coordinate(coor)
+                               except: return
+                               last_coor = coor
+                               last_ts = time.time()
+
+##################################################
+# GL caching interface
+##################################################
+class gl_cache(object):
+       """
+       Cache a set of gl drawing routines in a compiled list.
+       """
+
+       def __init__(self, draw):
+               """
+               Create a new cache.
+               @param draw a function to draw gl stuff
+               """
+               self.changed(True)
+               self._draw = draw
+
+       def init(self):
+               """
+               To be called when gl initializes.
+               Create a new compiled list.
+               """
+               self._grid_compiled_list_id = GL.glGenLists(1)
+
+       def draw(self):
+               """
+               Draw the gl stuff using a compiled list.
+               If changed, reload the compiled list.
+               """
+               if self.changed():
+                       GL.glNewList(self._grid_compiled_list_id, GL.GL_COMPILE)
+                       self._draw()
+                       GL.glEndList()
+                       self.changed(False)
+               #draw the grid
+               GL.glCallList(self._grid_compiled_list_id)
+
+       def changed(self, state=None):
+               """
+               Set the changed flag if state is not None.
+               Otherwise return the changed flag.
+               """
+               if state is None: return self._changed
+               self._changed = state

Modified: 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/plotter_base.py
===================================================================
--- 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/plotter_base.py
     2009-02-27 03:35:20 UTC (rev 10531)
+++ 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/plotter_base.py
     2009-02-27 16:50:28 UTC (rev 10532)
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -23,6 +23,7 @@
 import wx.glcanvas
 from OpenGL.GL import *
 from gnuradio.wxgui import common
+import common as _common
 import threading
 import gltext
 import math
@@ -42,7 +43,7 @@
 ##################################################
 # OpenGL WX Plotter Canvas
 ##################################################
-class _plotter_base(wx.glcanvas.GLCanvas):
+class _plotter_base(wx.glcanvas.GLCanvas, _common.mutex):
        """
        Plotter base class for all plot types.
        """
@@ -55,18 +56,27 @@
                Bind the paint and size events.
                @param parent the parent widgit
                """
-               self._global_lock = threading.Lock()
                attribList = (wx.glcanvas.WX_GL_DOUBLEBUFFER, 
wx.glcanvas.WX_GL_RGBA)
                wx.glcanvas.GLCanvas.__init__(self, parent, 
attribList=attribList)
-               self.changed(False)
                self._gl_init_flag = False
                self._resized_flag = True
-               self._update_ts = 0
+               self._init_fcns = list()
+               self._draw_fcns = list()
                self.Bind(wx.EVT_PAINT, self._on_paint)
                self.Bind(wx.EVT_SIZE, self._on_size)
 
-       def lock(self): self._global_lock.acquire()
-       def unlock(self): self._global_lock.release()
+       def register_init(self, fcn): self._init_fcns.append(fcn)
+       def register_draw(self, fcn, z=50):
+               """
+               Register a draw function with a layer priority.
+               Large z values are drawn last.
+               Small z values are drawn first.
+               """
+               for i in range(len(self._draw_fcns)):
+                       if z < self._draw_fcns[i][0]:
+                               self._draw_fcns.insert(i, (z, fcn))
+                               return
+               self._draw_fcns.append((z, fcn))
 
        def _on_size(self, event):
                """
@@ -84,7 +94,7 @@
                #check if gl was initialized
                if not self._gl_init_flag:
                        glClearColor(*BACKGROUND_COLOR_SPEC)
-                       self._gl_init()
+                       for fcn in self._init_fcns: fcn()
                        self._gl_init_flag = True
                #check for a change in window size
                if self._resized_flag:
@@ -97,9 +107,13 @@
                        glLoadIdentity()
                        glViewport(0, 0, self.width, self.height)
                        self._resized_flag = False
-                       self.changed(True)
                        self.unlock()
-               self.draw()
+               #clear, draw functions, swap
+               glClear(GL_COLOR_BUFFER_BIT)
+               self.lock()
+               for fcn in self._draw_fcns: fcn[1]()
+               self.unlock()
+               self.SwapBuffers()
 
        def update(self):
                """
@@ -109,16 +123,6 @@
                wx.PostEvent(self, wx.PaintEvent())
                self._update_ts = time.time()
 
-       def clear(self): glClear(GL_COLOR_BUFFER_BIT)
-
-       def changed(self, state=None):
-               """
-               Set the changed flag if state is not None.
-               Otherwise return the changed flag.
-               """
-               if state is not None: self._changed = state
-               else: return self._changed
-
 ##################################################
 # Grid Plotter Base Class
 ##################################################
@@ -126,6 +130,11 @@
 
        def __init__(self, parent, padding):
                _plotter_base.__init__(self, parent)
+               #setup grid cache
+               self._grid_cache = _common.gl_cache(self._draw_grid)
+               self.register_init(self._grid_cache.init)
+               self.register_draw(self._grid_cache.draw)
+               #setup padding
                self.padding_top, self.padding_right, self.padding_bottom, 
self.padding_left = padding
                #store title and unit strings
                self.set_title('Title')
@@ -134,28 +143,23 @@
                #init the grid to some value
                self.set_x_grid(-1, 1, 1)
                self.set_y_grid(-1, 1, 1)
+               #setup point label cache
+               self._point_label_cache = 
_common.gl_cache(self._draw_point_label)
+               self.register_init(self._point_label_cache.init)
+               self.register_draw(self._point_label_cache.draw, 75)
                #setup point label
                self.enable_point_label(False)
-               self._mouse_coordinate = None
-               self.Bind(wx.EVT_MOTION, self._on_motion)
-               self.Bind(wx.EVT_LEAVE_WINDOW, self._on_leave_window)
+               self.set_point_label_coordinate(None)
+               _common.point_label_thread(self)
 
-       def _on_motion(self, event):
+       def set_point_label_coordinate(self, coor):
                """
-               Mouse motion, record the position X, Y.
+               Set the point label coordinate.
+               @param coor the coordinate x, y tuple or None 
                """
                self.lock()
-               self._mouse_coordinate = event.GetPosition()
-               #update based on last known update time
-               if time.time() - self._update_ts > 0.03: self.update()
-               self.unlock()
-
-       def _on_leave_window(self, event):
-               """
-               Mouse leave window, set the position to None.
-               """
-               self.lock()
-               self._mouse_coordinate = None
+               self._point_label_coordinate = coor
+               self._point_label_cache.changed(True)
                self.update()
                self.unlock()
 
@@ -168,7 +172,7 @@
                if enable is None: return self._enable_point_label
                self.lock()
                self._enable_point_label = enable
-               self.changed(True)
+               self._point_label_cache.changed(True)
                self.unlock()
 
        def set_title(self, title):
@@ -178,7 +182,7 @@
                """
                self.lock()
                self.title = title
-               self.changed(True)
+               self._grid_cache.changed(True)
                self.unlock()
 
        def set_x_label(self, x_label, x_units=''):
@@ -190,7 +194,7 @@
                self.lock()
                self.x_label = x_label
                self.x_units = x_units
-               self.changed(True)
+               self._grid_cache.changed(True)
                self.unlock()
 
        def set_y_label(self, y_label, y_units=''):
@@ -202,7 +206,7 @@
                self.lock()
                self.y_label = y_label
                self.y_units = y_units
-               self.changed(True)
+               self._grid_cache.changed(True)
                self.unlock()
 
        def set_x_grid(self, x_min, x_max, x_step, x_scalar=1.0):
@@ -218,7 +222,7 @@
                self.x_max = float(x_max)
                self.x_step = float(x_step)
                self.x_scalar = float(x_scalar)
-               self.changed(True)
+               self._grid_cache.changed(True)
                self.unlock()
 
        def set_y_grid(self, y_min, y_max, y_step, y_scalar=1.0):
@@ -234,7 +238,7 @@
                self.y_max = float(y_max)
                self.y_step = float(y_step)
                self.y_scalar = float(y_scalar)
-               self.changed(True)
+               self._grid_cache.changed(True)
                self.unlock()
 
        def _draw_grid(self):
@@ -378,8 +382,8 @@
                The values of the X, Y coordinate will be scaled to the current 
X, Y bounds.
                """
                if not self.enable_point_label(): return
-               if not self._mouse_coordinate: return
-               x, y = self._mouse_coordinate
+               if not self._point_label_coordinate: return
+               x, y = self._point_label_coordinate
                if x < self.padding_left or x > self.width-self.padding_right: 
return
                if y < self.padding_top or y > self.height-self.padding_bottom: 
return
                #scale to window bounds

Modified: 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/waterfall_plotter.py
===================================================================
--- 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/waterfall_plotter.py
        2009-02-27 03:35:20 UTC (rev 10531)
+++ 
gnuradio/branches/developers/jblum/gui_guts/gr-wxgui/src/python/plotter/waterfall_plotter.py
        2009-02-27 16:50:28 UTC (rev 10532)
@@ -1,5 +1,5 @@
 #
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -23,6 +23,7 @@
 from plotter_base import grid_plotter_base
 from OpenGL.GL import *
 from gnuradio.wxgui import common
+import common as _common
 import numpy
 import gltext
 import math
@@ -92,6 +93,13 @@
                """
                #init
                grid_plotter_base.__init__(self, parent, PADDING)
+               #setup legend cache
+               self._legend_cache = _common.gl_cache(self._draw_legend)
+               self.register_init(self._legend_cache.init)
+               self.register_draw(self._legend_cache.draw)
+               #setup waterfall plotter
+               self.register_init(self._init_waterfall)
+               self.register_draw(self._draw_waterfall)
                self._resize_texture(False)
                self._minimum = 0
                self._maximum = 0
@@ -102,42 +110,20 @@
                self.set_num_lines(0)
                self.set_color_mode(COLORS.keys()[0])
 
-       def _gl_init(self):
+       def _init_waterfall(self):
                """
                Run gl initialization tasks.
                """
-               self._grid_compiled_list_id = glGenLists(1)
                self._waterfall_texture = glGenTextures(1)
 
-       def draw(self):
-               """
-               Draw the grid and waveforms.
-               """
-               self.lock()
-               #resize texture
-               self._resize_texture()
-               #store the grid drawing operations
-               if self.changed():
-                       glNewList(self._grid_compiled_list_id, GL_COMPILE)
-                       self._draw_grid()
-                       self._draw_legend()
-                       glEndList()
-                       self.changed(False)
-               self.clear()
-               #draw the grid
-               glCallList(self._grid_compiled_list_id)
-               self._draw_waterfall()
-               self._draw_point_label()
-               #swap buffer into display
-               self.SwapBuffers()
-               self.unlock()
-
        def _draw_waterfall(self):
                """
                Draw the waterfall from the texture.
                The texture is circularly filled and will wrap around.
                Use matrix modeling to shift and scale the texture onto the 
coordinate plane.
                """
+               #resize texture
+               self._resize_texture()
                #setup texture
                glBindTexture(GL_TEXTURE_2D, self._waterfall_texture)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
@@ -239,7 +225,7 @@
                self.lock()
                if color_mode in COLORS.keys():
                        self._color_mode = color_mode
-                       self.changed(True)
+                       self._legend_cache.changed(True)
                self.update()
                self.unlock()
 
@@ -268,7 +254,7 @@
                if self._minimum != minimum or self._maximum != maximum:
                        self._minimum = minimum
                        self._maximum = maximum
-                       self.changed(True)
+                       self._legend_cache.changed(True)
                if self._fft_size != len(samples):
                        self._fft_size = len(samples)
                        self._resize_texture(True)





reply via email to

[Prev in Thread] Current Thread [Next in Thread]