gr-wxgui: update copyrights
[debian/gnuradio] / gr-wxgui / src / python / plotter / plotter_base.py
1 #
2 # Copyright 2008, 2009, 2010 Free Software Foundation, Inc.
3 #
4 # This file is part of GNU Radio
5 #
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
9 # any later version.
10 #
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20 #
21
22 import wx
23 import wx.glcanvas
24 from OpenGL import GL
25 import common
26
27 BACKGROUND_COLOR_SPEC = (1, 0.976, 1, 1) #creamy white
28
29 ##################################################
30 # GL caching interface
31 ##################################################
32 class gl_cache(object):
33         """
34         Cache a set of gl drawing routines in a compiled list.
35         """
36
37         def __init__(self, draw):
38                 """
39                 Create a new cache.
40                 @param draw a function to draw gl stuff
41                 """
42                 self.changed(True)
43                 self._draw = draw
44
45         def init(self):
46                 """
47                 To be called when gl initializes.
48                 Create a new compiled list.
49                 """
50                 self._grid_compiled_list_id = GL.glGenLists(1)
51
52         def draw(self):
53                 """
54                 Draw the gl stuff using a compiled list.
55                 If changed, reload the compiled list.
56                 """
57                 if self.changed():
58                         GL.glNewList(self._grid_compiled_list_id, GL.GL_COMPILE)
59                         self._draw()
60                         GL.glEndList()
61                         self.changed(False)
62                 #draw the grid
63                 GL.glCallList(self._grid_compiled_list_id)
64
65         def changed(self, state=None):
66                 """
67                 Set the changed flag if state is not None.
68                 Otherwise return the changed flag.
69                 """
70                 if state is None: return self._changed
71                 self._changed = state
72
73 ##################################################
74 # OpenGL WX Plotter Canvas
75 ##################################################
76 class plotter_base(wx.glcanvas.GLCanvas, common.mutex):
77         """
78         Plotter base class for all plot types.
79         """
80
81         def __init__(self, parent):
82                 """
83                 Create a new plotter base.
84                 Initialize the GLCanvas with double buffering.
85                 Initialize various plotter flags.
86                 Bind the paint and size events.
87                 @param parent the parent widgit
88                 """
89                 attribList = (wx.glcanvas.WX_GL_DOUBLEBUFFER, wx.glcanvas.WX_GL_RGBA)
90                 wx.glcanvas.GLCanvas.__init__(self, parent, attribList=attribList);
91                 self.use_persistence=False
92                 self.persist_alpha=2.0/15
93                 self.clear_accum=True
94                 self._gl_init_flag = False
95                 self._resized_flag = True
96                 self._init_fcns = list()
97                 self._draw_fcns = list()
98                 self._gl_caches = list()
99                 self.Bind(wx.EVT_PAINT, self._on_paint)
100                 self.Bind(wx.EVT_SIZE, self._on_size)
101                 self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None)
102
103         def set_use_persistence(self,enable):
104                 self.use_persistence=enable 
105                 self.clear_accum=True
106
107         def set_persist_alpha(self,analog_alpha):
108                 self.persist_alpha=analog_alpha
109
110         def new_gl_cache(self, draw_fcn, draw_pri=50):
111                 """
112                 Create a new gl cache.
113                 Register its draw and init function.
114                 @return the new cache object
115                 """
116                 cache = gl_cache(draw_fcn)
117                 self.register_init(cache.init)
118                 self.register_draw(cache.draw, draw_pri)
119                 self._gl_caches.append(cache)
120                 return cache
121
122         def register_init(self, init_fcn):
123                 self._init_fcns.append(init_fcn)
124
125         def register_draw(self, draw_fcn, draw_pri=50):
126                 """
127                 Register a draw function with a layer priority.
128                 Large pri values are drawn last.
129                 Small pri values are drawn first.
130                 """
131                 for i in range(len(self._draw_fcns)):
132                         if draw_pri < self._draw_fcns[i][0]:
133                                 self._draw_fcns.insert(i, (draw_pri, draw_fcn))
134                                 return
135                 self._draw_fcns.append((draw_pri, draw_fcn))
136
137         def _on_size(self, event):
138                 """
139                 Flag the resize event.
140                 The paint event will handle the actual resizing.
141                 """
142                 self.lock()
143                 self._resized_flag = True
144                 self.clear_accum=True
145                 self.unlock()
146
147         def _on_paint(self, event):
148                 """
149                 Respond to paint events.
150                 Initialize GL if this is the first paint event.
151                 Resize the view port if the width or height changed.
152                 Redraw the screen, calling the draw functions.
153                 """
154                 self.lock()
155                 self.SetCurrent()
156                 #check if gl was initialized
157                 if not self._gl_init_flag:
158                         GL.glClearColor(*BACKGROUND_COLOR_SPEC)
159                         for fcn in self._init_fcns: fcn()
160                         self._gl_init_flag = True
161                 #check for a change in window size
162                 if self._resized_flag:
163                         self.width, self.height = self.GetSize()
164                         GL.glMatrixMode(GL.GL_PROJECTION)
165                         GL.glLoadIdentity()
166                         GL.glOrtho(0, self.width, self.height, 0, 1, 0)
167                         GL.glMatrixMode(GL.GL_MODELVIEW)
168                         GL.glLoadIdentity()
169                         GL.glViewport(0, 0, self.width, self.height)
170                         for cache in self._gl_caches: cache.changed(True)
171                         self._resized_flag = False
172                 #clear, draw functions, swap
173                 GL.glClear(GL.GL_COLOR_BUFFER_BIT)
174
175                 if False:
176                   GL.glEnable (GL.GL_LINE_SMOOTH)
177                   GL.glEnable (GL.GL_POLYGON_SMOOTH)
178                   GL.glEnable (GL.GL_BLEND)
179                   GL.glBlendFunc (GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA)
180                   GL.glHint (GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST) #GL.GL_DONT_CARE)
181                   GL.glHint(GL.GL_POLYGON_SMOOTH_HINT, GL.GL_NICEST)
182                   #GL.glLineWidth (1.5)
183
184                   GL.glEnable(GL.GL_MULTISAMPLE) #Enable Multisampling anti-aliasing
185
186
187                 for fcn in self._draw_fcns: fcn[1]()
188
189                 if self.use_persistence:
190                   if self.clear_accum:
191                     #GL.glClear(GL.GL_ACCUM_BUFFER_BIT)
192                     GL.glAccum(GL.GL_LOAD, 1.0)
193                     self.clear_accum=False
194
195                   GL.glAccum(GL.GL_MULT, 1.0-self.persist_alpha)
196                   GL.glAccum(GL.GL_ACCUM, self.persist_alpha)
197                   GL.glAccum(GL.GL_RETURN, 1.0)
198                 self.SwapBuffers()
199                 self.unlock()
200
201         def update(self):
202                 """
203                 Force a paint event.
204                 """
205                 if not self._gl_init_flag: return
206                 wx.PostEvent(self, wx.PaintEvent())