import math import gtk import gtk.gtkgl from OpenGL.GL import * from Line import Line from Circle import Circle class SketchWidget: def __init__(self, sketch): self.sketch = sketch try: # try double-buffered self.glconfig = gtk.gdkgl.Config(mode = (gtk.gdkgl.MODE_RGB | gtk.gdkgl.MODE_DOUBLE | gtk.gdkgl.MODE_DEPTH)) except gtk.gdkgl.NoMatches: # try single-buffered self.glconfig = gtk.gdkgl.Config(mode = (gtk.gdkgl.MODE_RGB | gtk.gdkgl.MODE_DEPTH)) self.widget = gtk.gtkgl.DrawingArea(self.glconfig) self.widget.connect_after('realize', self.init) self.widget.connect('configure_event', self.reshape) self.widget.connect('expose_event', self.draw) def init(self, glarea): # get GLContext and GLDrawable glcontext = glarea.get_gl_context() gldrawable = glarea.get_gl_drawable() # GL calls if not gldrawable.gl_begin(glcontext): return # glEnable(GL_BLEND) # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) # glEnable(GL_POLYGON_SMOOTH) # glEnable(GL_LINE_SMOOTH) gldrawable.gl_end() def reshape(self, glarea, event): # get GLContext and GLDrawable glcontext = glarea.get_gl_context() gldrawable = glarea.get_gl_drawable() # GL calls if not gldrawable.gl_begin(glcontext): return x, y, width, height = glarea.get_allocation() glViewport(0, 0, width, height) glMatrixMode(GL_PROJECTION) glOrtho(-2, 2, -1.5, 1.5, 1.0, -1.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() gldrawable.gl_end() return True def draw(self, glarea, event): # get GLContext and GLDrawable glcontext = glarea.get_gl_context() gldrawable = glarea.get_gl_drawable() # GL calls if not gldrawable.gl_begin(glcontext): return glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) for shape in self.sketch: if isinstance(shape, Line): self.drawLine(shape, 0.03) elif isinstance(shape, Circle): self.drawCircle(shape, 0.03) if gldrawable.is_double_buffered(): gldrawable.swap_buffers() else: glFlush() gldrawable.gl_end() return True def drawLine(self, shape, size): pt0 = shape.getPt(0) pt1 = shape.getPt(1) self.drawFilledLine(pt0[0], pt0[1], pt1[0], pt1[1], size) def drawCircle(self, shape, size): steps = 16 step = 2 * math.pi / steps center = shape.getCenter() rad = shape.getRadius() for i in range(steps + 1): angle = i * step next_angle = (i + 1) * step x0 = center[0] + rad * math.cos(angle) y0 = center[1] + rad * math.sin(angle) x1 = center[0] + rad * math.cos(next_angle) y1 = center[1] + rad * math.sin(next_angle) self.drawFilledLineUncapped(x0, y0, x1, y1, size) self.drawFilledCircle(x0, y0, size, 8) def drawFilledLine(self, x0, y0, x1, y1, size): self.drawFilledLineUncapped(x0, y0, x1, y1, size) self.drawFilledCircle(x0, y0, size, 16) self.drawFilledCircle(x1, y1, size, 16) def drawFilledLineUncapped(self, x0, y0, x1, y1, size): glBegin(GL_QUADS) angle = math.atan2(y1 - y0, x1 - x0) ninety = math.pi / 2 x_left = size * math.cos(angle + ninety) y_left = size * math.sin(angle + ninety) x_right = size * math.cos(angle - ninety) y_right = size * math.sin(angle - ninety) glVertex(x0 + x_left, y0 + y_left) glVertex(x0 + x_right, y0 + y_right) glVertex(x1 + x_right, y1 + y_right) glVertex(x1 + x_left, y1 + y_left) glEnd() def drawFilledCircle(self, x, y, radius, steps): glBegin(GL_TRIANGLE_FAN) glVertex(x, y) for i in range(steps + 1): angle = i * 2 * math.pi / steps glVertex(x + radius * math.cos(angle), y + radius * math.sin(angle)) glEnd()