Esempio n. 1
0
class TextLabel(object):
    def __init__(self,
                 text,
                 glyph_text,
                 tx=0,
                 ty=0,
                 sphere_mode=False,
                 **kwargs):
        self.fader = Fader(in_time=0.05, out_time=0.2)
        self.size, self.indices, self.vertices, self.texcoords, self.normals, self.colors = glyph_text.generate_geometry(
            text, **kwargs)

        self.tx = tx
        self.ty = ty

        # scale and rearrange vertices for the shader
        self.sphere_mode = sphere_mode
        if not sphere_mode:
            self.vertices = np.hstack(
                [self.vertices[:, 1][:, None], -self.vertices[:, 0][:, None]])
        else:
            self.vertices = np.hstack(
                [-self.vertices[:, 1][:, None], self.vertices[:, 0][:, None]])
        self.fadein()

    def fadein(self):
        self.fader.fadein()

    def fadeout(self):
        self.fader.fadeout()

    def isalive(self):
        return self.fader.fadestate != self.fader.FADEOFF

    def update(self, dt):
        self.fader.update(dt)

    def draw(self, shader):
        # must have valid client state set and shader bound!
        # draw the points
        glColor4f(1, 1, 1, self.fader.get())
        glPushMatrix()
        if not self.sphere_mode:
            glTranslatef(self.tx, self.ty, 0)
        else:
            # TODO better way of fixing this?
            glRotatef(180, 0, 0, 1)

        pyglet.gl.glVertexPointer(2, GL_FLOAT, 0, self.vertices.ctypes.data)
        pyglet.gl.glColorPointer(4, GL_FLOAT, 0, self.colors.ctypes.data)
        pyglet.gl.glTexCoordPointer(2, GL_FLOAT, 0, self.texcoords.ctypes.data)
        pyglet.gl.glDrawElements(GL_TRIANGLES, len(self.indices),
                                 GL_UNSIGNED_INT, self.indices.ctypes.data)
        glPopMatrix()
class Phaser(pyglet.window.Window):

    MODE_NORMAL = 0
    MODE_TRACING = 1
    MODE_CREATING = 2

    def __init__(self):
        super(Phaser, self).__init__(
            WIDTH,
            HEIGHT)  # config=pyglet.gl.Config(sample_buffers=1, samples=2))
        self.xdim = WIDTH
        self.ydim = HEIGHT
        self.load_fonts()

        self.gesture_sound = pyglet.media.StaticSource(
            pyglet.resource.media('gesture.wav'))

        # add the faders
        self.faders = []
        self.title_fader = Fader(0.1, 0.9)
        self.faders.append(self.title_fader)

        self.mouse = (0, 0)
        self.title_image = pyglet.font.Text(self.fonts[40], 'PhaseSeq')
        self.mode_image = pyglet.font.Text(self.fonts[30], 'Trace mode')
        self.show_saved_image = pyglet.font.Text(self.fonts[20],
                                                 'Showing saved traces')
        self.create_image = pyglet.font.Text(self.fonts[30],
                                             'Creating classifier')
        self.showinst_image = pyglet.font.Text(
            self.fonts[20], 'Press H to toggle instructions')

        instructions = 'To create a classifier:\n'
        instructions += '- Right click to begin\n'
        instructions += '- Left click to place first path segment\n'
        instructions += '- Left click again to extend path\n'
        instructions += '- Optionally use <A> and <D> to change width\n'
        instructions += '- Repeat until path complete\n'
        instructions += '- Right click to save\n'
        instructions += '(Press <U> to undo last point while drawing)\n\n'
        instructions += 'To preserve traces on screen:\n'
        instructions += '- Hold <Shift> and perform a movement\n'
        instructions += '- Release <Shift> to stop recording\n'
        instructions += '- Perform these steps as many times as needed\n'
        instructions += '- Press <T> to toggle showing all stored recordings\n'
        instructions += '- Press <X> to clear all stored recordings\n'
        instructions += '\nOther keybindings:\n'
        instructions += '<C> clears all saved classifiers\n'
        instructions += '<L> loads saved classifiers from file\n'
        instructions += '<S> saves current set of classifiers to file\n'
        self.inst_label = pyglet.text.Label(instructions,
                                            font_size=16,
                                            x=self.width / 2,
                                            y=self.height - 100,
                                            anchor_x='center',
                                            multiline=True,
                                            width=self.width * 0.75)

        self.phase_trace = []
        self.trace_len = 150

        self.sequences = []
        self.active_sequence = None
        self.saved_traces = []
        self.show_saved_traces = False

        self.extents = [-0.05, 1.1, -0.6, 0.6]
        self.thickness = 0.07

        self.tracker = Tracker(WIDTH, HEIGHT)

        self.mode = Phaser.MODE_NORMAL
        self.show_instructions = False

        self.import_sequences()

    def start_sequence(self):
        self.active_sequence = []

    def end_sequence(self):
        if len(self.active_sequence) > 1:
            self.sequences.append(
                TriPhaseSequence(
                    self.make_path(self.active_sequence, self.thickness)))
        self.active_sequence = None

    def import_sequences(self):
        if not os.path.exists(SEQUENCES_FILE):
            print('No existing sequences file found!')
            return

        self.sequences = []
        self.active_sequence = None

        with open(SEQUENCES_FILE, 'r') as f:
            seq_data = f.readlines()

        for sd in seq_data:
            points = []
            sd = sd.split(',')
            for i in range(0, len(sd), 6):
                t = map(float, sd[i:i + 6])
                points.append(((t[0], t[1]), (t[2], t[3]), (t[4], t[5])))
            self.sequences.append(TriPhaseSequence(points))

        print('Imported %d sequences' % (len(self.sequences)))

    def export_sequences(self):
        if len(self.sequences) == 0:
            print('No sequences to export')
            return

        print('Exporting %d sequences to %s' %
              (len(self.sequences), SEQUENCES_FILE))
        with open(SEQUENCES_FILE, 'w') as f:
            for j, s in enumerate(self.sequences):
                points = list(itertools.chain.from_iterable(s.states))
                for i, p in enumerate(points):
                    f.write('%f,%f' % p)
                    if i < len(points) - 1:
                        f.write(',')
                    else:
                        if j < len(self.sequences) - 1:
                            f.write('\n')
                print('Sequence exported (%d points)' % (len(points) / 3))

    def load_fonts(self):
        # load fonts
        self.fonts = {}
        pyglet.font.add_file("rez.ttf")
        for i in range(6, 41):
            self.fonts[i] = pyglet.font.load('Rez', i)

    def start(self):
        pyglet.clock.schedule_interval(self.update, 1 / 60.0)
        pyglet.app.run()
        self.export_sequences()

    def update(self, dt):
        """Frame update"""
        # update the faders, so they fade in and out
        for fader in self.faders:
            fader.update(dt)

        self.tracker.update(pos=self.mouse)

        n = len(self.tracker.the_object.d_seq)
        for d in self.tracker.the_object.d_seq:
            state = (d[0, 0], -d[0, 1] * 4)
            self.phase_trace.append(state)

            if self.mode == Phaser.MODE_NORMAL:
                for i, seq in enumerate(self.sequences):
                    seq.update(state[0], state[1], dt / n)

                    if seq.active == 1.0:
                        self.gesture_sound.play()
                        self.title_image = pyglet.font.Text(
                            self.fonts[40], 'Gesture %d' % i)
                        self.title_fader.reset()

        if self.mode != Phaser.MODE_TRACING and len(
                self.phase_trace) > self.trace_len:
            self.phase_trace = self.phase_trace[len(self.phase_trace) -
                                                self.trace_len:]

        self.draw()

    def draw_axes(self):
        w = 0.8 * self.extents[1]
        y1 = 0.7 * self.extents[2]
        y2 = 0.7 * self.extents[3]

        glLineWidth(3.0)

        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        if self.mode == Phaser.MODE_TRACING:
            glColor4f(0.2, 0.9, 0.5, 0.3)
        else:
            glColor4f(0.2, 0.5, 0.9, 0.3)

        glBegin(GL_LINES)
        glVertex2f(0, y1)
        glVertex2f(0, y2)
        glVertex2f(0, 0)
        glVertex2f(w, 0)
        glEnd()

        if self.mode == Phaser.MODE_TRACING:
            glColor4f(0.2, 0.9, 0.6, 0.1)
            glBegin(GL_QUADS)
            glVertex2f(0, 0)
            glColor4f(0.2, 0.9, 0.6, 0.0)
            glVertex2f(0, y1)
            glVertex2f(w, y1)
            glColor4f(0.2, 0.9, 0.6, 0.1)
            glVertex2f(w, 0)
        else:
            glColor4f(0.2, 0.6, 0.9, 0.1)
            glBegin(GL_QUADS)
            glVertex2f(0, 0)
            glColor4f(0.2, 0.6, 0.9, 0.0)
            glVertex2f(0, y1)
            glVertex2f(w, y1)
            glColor4f(0.2, 0.6, 0.9, 0.1)
            glVertex2f(w, 0)
        glEnd()

        if self.mode == Phaser.MODE_TRACING:
            glColor4f(0.2, 0.9, 0.5, 0.4)
        else:
            glColor4f(0.2, 0.5, 0.9, 0.4)

        n = 10
        for i in range(n):
            x = w * ((i + 1) / float(n))
            glBegin(GL_LINES)
            glVertex2f(x, -0.01)
            glVertex2f(x, 0.01)
            glEnd()

        glLineWidth(1.0)

    def draw_trace(self):
        glBlendFunc(GL_SRC_ALPHA, GL_ONE)
        k = 1.0
        glLineWidth(3.0)
        glBegin(GL_LINE_STRIP)
        for vertex in reversed(self.phase_trace):
            if vertex:
                glColor4f(0.9, 0.7, 0.7, k)
                glVertex2f(vertex[0], vertex[1])
                if self.mode != Phaser.MODE_TRACING:
                    k = k * 0.95  #0.9
        glEnd()
        glLineWidth(1.0)

    def draw_tri(self, tri, color, phase=0):
        alpha = color[3]

        glColor4f(color[0], color[1], color[2], alpha)  #/2.0)
        glBegin(GL_TRIANGLES)
        glVertex2f(*tri[0])
        glVertex2f(*tri[1])
        glVertex2f(*tri[2])
        glEnd()

        # glBegin(GL_LINE_LOOP)

        # glColor4f(color[0], color[1], color[2], alpha)
        # glVertex2f(*tri[0])
        # glVertex2f(*tri[1])
        # glVertex2f(*tri[2])
        # glEnd()

    def draw_saved_traces(self):
        if not self.show_saved_traces:
            return

        glBlendFunc(GL_SRC_ALPHA, GL_ONE)
        glLineWidth(3.0)
        colours = [[0.9, 0.2, 0.2, 0.8], [0.2, 0.9, 0.2, 0.8],
                   [0.2, 0.2, 0.9, 0.8]]
        for i, st in enumerate(self.saved_traces):
            glBegin(GL_LINE_STRIP)
            glColor4f(*colours[i % 3])
            for j, vertex in enumerate(st):
                glVertex2f(vertex[0], vertex[1])
            glEnd()
        glLineWidth(1.0)

    def draw_sequences(self):
        for sequence in self.sequences:
            for i, elt in enumerate(sequence.states):
                if sequence.active > 0.1:
                    self.draw_tri(elt, (1, 1, 1, sequence.active))
                else:
                    if i == sequence.state:
                        self.draw_tri(elt,
                                      (0.6, 0.9, 0.6, sequence.trigger + 0.1))
                    else:
                        self.draw_tri(elt, (0.6, 0.9, 0.6, 0.25), phase=i)

        if self.active_sequence:
            self.draw_thick_line(self.active_sequence)

    def make_path(self, seq, thickness):
        """Convert a linear sequence to a set of triangles"""
        last = None
        last_l = None
        tris = []

        #if len(seq)>2:
        #    spl = spline.CardinalSpline(seq, tension=0.2)
        #    seq = [spl(x/3.0) for x in range(3*(len(seq)-1))]

        for pt in seq:
            if last:
                normal = geometry.normal(last, pt)
                strut = geometry.mul(normal, thickness)
                if not last_l:
                    last_r = (geometry.sub(strut, last))
                    last_l = (geometry.add(strut, last))

                tris.append((geometry.add(strut, pt), last_r, last_l))
                tris.append(
                    (geometry.add(strut, pt), geometry.sub(strut, pt), last_r))
                last_l = geometry.add(strut, pt)
                last_r = geometry.sub(strut, pt)

            last = pt
        return tris

    def draw_thick_line(self, seq):
        glColor4f(0.3, 0.8, 0.2, 0.5)

        if len(seq) == 1:
            glPointSize(4.0)
            glBegin(GL_POINTS)
            glVertex2f(*seq[0])
            glEnd()
            return

        tris = self.make_path(seq, self.thickness)

        for tri in tris:
            glBegin(GL_LINE_LOOP)
            for vertex in tri:
                glVertex2f(*vertex)
            glEnd()

    def draw_tracing_background(self):
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glBegin(GL_QUADS)
        glColor4f(0.33, 0.85, 0.26, 0.3)
        glVertex2f(0, 0)
        glColor4f(0.33, 0.85, 0.26, 0.3)
        glVertex2f(self.width, 0)
        glColor4f(0.55, 0.85, 0.46, 0.3)
        glVertex2f(self.width, self.height)
        glColor4f(0.55, 0.85, 0.46, 0.3)
        glVertex2f(0, self.height)
        glEnd()

    def draw_background(self):
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glBegin(GL_QUADS)
        glColor4f(0.02, 0.04, 0.12, 1)
        glVertex2f(0, 0)
        glColor4f(0.02, 0.04, 0.12, 1)
        glVertex2f(self.width, 0)
        glColor4f(0.03, 0.07, 0.22, 1)
        glVertex2f(self.width, self.height)
        glColor4f(0.13, 0.07, 0.22, 1)
        glVertex2f(0, self.height)
        glEnd()

    def draw(self):
        """Draw the entire screen"""
        glClearColor(0.02, 0.04, 0.12, 1)

        self.last_frame_time = time.clock()
        self.clear()
        if self.mode == Phaser.MODE_TRACING:
            self.draw_tracing_background()
        else:
            self.draw_background()

        glLoadIdentity()

        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        glOrtho(self.extents[0], self.extents[1], self.extents[2],
                self.extents[3], -1, 1)
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        self.draw_axes()
        self.draw_trace()
        self.draw_saved_traces()
        self.draw_sequences()

        glMatrixMode(GL_PROJECTION)
        glPopMatrix()
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        self.draw_title()
        self.draw_mode()
        self.draw_instructions()

    def on_key_press(self, symbol, modifiers):
        if self.mode == Phaser.MODE_NORMAL and symbol == pyglet.window.key.LSHIFT or symbol == pyglet.window.key.RSHIFT:
            self.mode = Phaser.MODE_TRACING
            self.phase_trace = []
        pyglet.window.Window.on_key_press(self, symbol, modifiers)

    def on_key_release(self, symbol, modifiers):
        if symbol == pyglet.window.key.C:
            print('Clearing sequences')
            self.sequences = []
            self.active_sequence = None
            if os.path.exists(SEQUENCES_FILE):
                os.unlink(SEQUENCES_FILE)
        elif symbol == pyglet.window.key.A:
            self.thickness -= 0.01
            print('thickness =', self.thickness)
        elif symbol == pyglet.window.key.D:
            self.thickness += 0.01
            print('thickness =', self.thickness)
        elif self.mode == Phaser.MODE_TRACING and symbol == pyglet.window.key.LSHIFT or symbol == pyglet.window.key.RSHIFT:
            self.mode = Phaser.MODE_NORMAL
            self.saved_traces.append(self.phase_trace)
            self.phase_trace = []
        elif symbol == pyglet.window.key.S:
            self.export_sequences()
        elif symbol == pyglet.window.key.L:
            self.import_sequences()
        elif symbol == pyglet.window.key.H:
            self.show_instructions = not self.show_instructions
        elif symbol == pyglet.window.key.U:
            if self.mode == Phaser.MODE_CREATING:
                if len(self.active_sequence) > 1:
                    self.active_sequence = self.active_sequence[:-1]
                else:
                    self.end_sequence()
                    self.mode = Phaser.MODE_NORMAL

        elif symbol == pyglet.window.key.X:
            self.saved_traces = []
            print('cleared saved traces')
        elif symbol == pyglet.window.key.T:
            self.show_saved_traces = not self.show_saved_traces

    def on_mouse_motion(self, x, y, dx, dy):
        self.mouse = (x, y)

    def new_state(self, x, y):
        x = x / float(self.width)
        y = y / float(self.height)
        rx = (1 - x) * self.extents[0] + (x) * self.extents[1]
        ry = (1 - y) * self.extents[2] + (y) * self.extents[3]
        self.active_sequence.append((rx, ry))

    def on_mouse_release(self, x, y, button, modifiers):
        self.mouse = (x, y)

        # left mouse click adds new segment to current sequence
        if button == pyglet.window.mouse.LEFT and self.active_sequence != None:
            self.new_state(x, y)
            return

        # right mouse ends an active sequence...
        if (button == pyglet.window.mouse.RIGHT \
                or (button == pyglet.window.mouse.LEFT and modifiers & 2)) \
                and self.active_sequence != None:
            self.end_sequence()
            self.mode = Phaser.MODE_NORMAL
            return

        # ...or starts a new one
        if (button == pyglet.window.mouse.RIGHT \
                or (button == pyglet.window.mouse.LEFT and modifiers & 2)) \
                and self.active_sequence == None:
            self.start_sequence()
            self.mode = Phaser.MODE_CREATING
            self.new_state(x, y)
            return

    def draw_instructions(self):
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        self.showinst_image.x = 10
        self.showinst_image.y = 30
        self.showinst_image.halign = 'left'
        self.showinst_image.valign = 'center'
        self.showinst_image.color = (1, 1, 1, 1)
        self.showinst_image.draw()
        if self.show_instructions:
            self.inst_label.draw()

    def draw_mode(self):
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        if self.mode == Phaser.MODE_TRACING:
            self.mode_image.x = self.width / 2
            self.mode_image.y = self.height - 40
            self.mode_image.halign = "center"
            self.mode_image.valign = "center"
            self.mode_image.color = (1, 1, 1, 1)
            self.mode_image.draw()
        elif self.mode == Phaser.MODE_CREATING:
            self.create_image.x = self.width / 2
            self.create_image.y = self.height - 40
            self.create_image.halign = "center"
            self.create_image.valign = "center"
            self.create_image.color = (1, 1, 1, 1)
            self.create_image.draw()

        if self.show_saved_traces:
            self.show_saved_image.x = self.width - 10
            self.show_saved_image.y = 30
            self.show_saved_image.halign = 'right'
            self.show_saved_image.valign = 'center'
            self.show_saved_image.color = (1, 1, 1, 1)
            self.show_saved_image.draw()

    def draw_title(self):
        """Draw the title, fading in and out"""
        k = self.title_fader.get()
        if k > 1e-3:
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
            self.title_image.x = self.width / 2
            self.title_image.y = self.height / 2
            self.title_image.halign = "center"
            self.title_image.valign = "center"
            self.title_image.color = (1, 1, 1, k)
            self.title_image.draw()