예제 #1
0
    def __init__(self, size, name):
        self.width, self.height = size.xy
        self.name = name  # for debugging only

        self.data = array.array("c", chr(0) * self.width * self.height * 4)

        stride = self.width * 4
        self.surface = cairo.ImageSurface.create_for_data(
            self.data, cairo.FORMAT_ARGB32, self.width, self.height, stride
        )
        self.texture = glGenTextures(1)

        self.cr = cairo.Context(self.surface)
        self.pango = pangocairo.CairoContext(self.cr)
        self.layout = self.pango.create_layout()

        # force subpixel rendering
        self.font_options = cairo.FontOptions()
        self.font_options.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
        self.cr.set_font_options(self.font_options)

        glBindTexture(GL_TEXTURE_2D, self.texture)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

        v = np.array([0, 0, 0, 0, 1, size.x, 0, 0, 1, 1, size.x, size.y, 0, 1, 0, 0, size.y, 0, 0, 0], np.float32)
        i = np.array([0, 1, 2, 3], np.uint32)
        self.vbo = VBO(GL_QUADS, v, i)
예제 #2
0
파일: player.py 프로젝트: ext/scfa
    def __init__(self, pos):
        self.pos = pos
        self.vel = Vector2f(0,0)
        self.texture = Image('texture/player.png', filter=GL_NEAREST)
        self.in_air = False
        self.jumping = 0
        self.hp = Player.max_hp
        self.hp_ratio = 0.8
        self.dir = 1
        self.cave_visited = False
        self.cave_quest = False
        self.have_ham = False
        self.have_cheese = False
        self.have_bread = False
        self.have_sandwich = False
        self.is_killed = False
        self.derp = False

        v = np.array([
                0,1,0, 0,1,
                1,1,0, 1,1,
                1,3,0, 1,0,
                0,3,0, 0,0,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.vbo = VBO(GL_QUADS, v, i)
예제 #3
0
파일: map.py 프로젝트: ext/scfa
    def __init__(self, filename):
        self.filename = os.path.join('data', filename)

        with open(self.filename) as fp:
            data = json.load(fp)

        self.width  = data['width']
        self.height = data['height']

        self.tile_width  = data['tilewidth']
        self.tile_height = data['tileheight']

        # hardcoded
        dx = self.tile_width  / 128.0
        dy = self.tile_height / 128.0
        tile_div = 128 / self.tile_width

        # load tilemap
        self.texture = Image(data['tilesets'][0]['image'], filter=GL_NEAREST)

        n = len(data['layers'][0]['data'])
        ver = np.zeros((n*4, 5), np.float32)
        for i, tile in enumerate(data['layers'][0]['data']):
            x = i % self.width
            y = -(i / self.width)

            tile -= 1 # start with 0 index
            tx = tile % tile_div
            ty = tile / tile_div

            ver[i*4+0] = (x  , y  , 0, tx*dx,    ty*dy+dy)
            ver[i*4+1] = (x+1, y  , 0, tx*dx+dx, ty*dy+dy)
            ver[i*4+2] = (x+1, y+1, 0, tx*dx+dx, ty*dy)
            ver[i*4+3] = (x  , y+1, 0, tx*dx,    ty*dy)

        ver = ver.flatten()
        ind = np.array(range(n*4), np.uint32)
        self.vbo = VBO(GL_QUADS, ver, ind)

        self.grid = np.array(data['layers'][0]['data'], np.uint32)

        # load objects
        self.obj1 = list(self.twiddle(data['layers'][1]['objects']))
        self.obj2 = list(self.twiddle(data['layers'][2]['objects']))
        self.obj3 = list(self.twiddle(data['layers'][3]['objects']))

        self.pickups = []
예제 #4
0
class HUD:
    def __init__(self, size, name):
        self.width, self.height = size.xy
        self.name = name  # for debugging only

        self.data = array.array("c", chr(0) * self.width * self.height * 4)

        stride = self.width * 4
        self.surface = cairo.ImageSurface.create_for_data(
            self.data, cairo.FORMAT_ARGB32, self.width, self.height, stride
        )
        self.texture = glGenTextures(1)

        self.cr = cairo.Context(self.surface)
        self.pango = pangocairo.CairoContext(self.cr)
        self.layout = self.pango.create_layout()

        # force subpixel rendering
        self.font_options = cairo.FontOptions()
        self.font_options.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
        self.cr.set_font_options(self.font_options)

        glBindTexture(GL_TEXTURE_2D, self.texture)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

        v = np.array([0, 0, 0, 0, 1, size.x, 0, 0, 1, 1, size.x, size.y, 0, 1, 0, 0, size.y, 0, 0, 0], np.float32)
        i = np.array([0, 1, 2, 3], np.uint32)
        self.vbo = VBO(GL_QUADS, v, i)

    def clear(self, color=(0, 0, 0, 0)):
        self.cr.save()
        self.cr.set_source_rgba(color[0], color[1], color[2], color[3])
        self.cr.set_operator(cairo.OPERATOR_SOURCE)
        self.cr.paint()
        self.cr.restore()

    @classmethod
    def create_font(cls, font="Sans", size=12, raw=None):
        if raw is None:
            raw = "%s %f" % (font, size)
        return pango.FontDescription(raw)

    def text(self, text, font, color=(0, 0, 0, 1), alignment=pango.ALIGN_LEFT, justify=False, width=None):
        cr = self.cr
        cr.set_source_rgba(*color)

        self.layout.context_changed()
        self.layout.set_font_description(font)

        if width:
            self.layout.set_width(int(width * pango.SCALE))

        self.layout.set_alignment(alignment)
        self.layout.set_justify(justify)
        self.layout.set_markup(text)
        self.pango.show_layout(self.layout)

        return self.layout.get_pixel_extents()

    def rectangle(self, x, y, w, h, color=(0, 0, 0, 1)):
        self.cr.save()
        self.cr.set_source_rgba(color[0], color[1], color[2], color[3])
        self.cr.rectangle(x, y, w, h)
        self.cr.fill()
        self.cr.restore()

    def __enter__(self):
        self.cr.save()
        return self

    def __exit__(self, type, value, traceback):
        if type is None:
            glBindTexture(GL_TEXTURE_2D, self.texture)
            glTexImage2D(
                GL_TEXTURE_2D, 0, GL_RGBA, self.width, self.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, self.data.tostring()
            )

    def draw(self):
        glBindTexture(GL_TEXTURE_2D, self.texture)
        glTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, self.width, self.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, self.data.tostring()
        )

        self.vbo.draw()
예제 #5
0
파일: map.py 프로젝트: ext/scfa
class Map(object):
    def __init__(self, filename):
        self.filename = os.path.join('data', filename)

        with open(self.filename) as fp:
            data = json.load(fp)

        self.width  = data['width']
        self.height = data['height']

        self.tile_width  = data['tilewidth']
        self.tile_height = data['tileheight']

        # hardcoded
        dx = self.tile_width  / 128.0
        dy = self.tile_height / 128.0
        tile_div = 128 / self.tile_width

        # load tilemap
        self.texture = Image(data['tilesets'][0]['image'], filter=GL_NEAREST)

        n = len(data['layers'][0]['data'])
        ver = np.zeros((n*4, 5), np.float32)
        for i, tile in enumerate(data['layers'][0]['data']):
            x = i % self.width
            y = -(i / self.width)

            tile -= 1 # start with 0 index
            tx = tile % tile_div
            ty = tile / tile_div

            ver[i*4+0] = (x  , y  , 0, tx*dx,    ty*dy+dy)
            ver[i*4+1] = (x+1, y  , 0, tx*dx+dx, ty*dy+dy)
            ver[i*4+2] = (x+1, y+1, 0, tx*dx+dx, ty*dy)
            ver[i*4+3] = (x  , y+1, 0, tx*dx,    ty*dy)

        ver = ver.flatten()
        ind = np.array(range(n*4), np.uint32)
        self.vbo = VBO(GL_QUADS, ver, ind)

        self.grid = np.array(data['layers'][0]['data'], np.uint32)

        # load objects
        self.obj1 = list(self.twiddle(data['layers'][1]['objects']))
        self.obj2 = list(self.twiddle(data['layers'][2]['objects']))
        self.obj3 = list(self.twiddle(data['layers'][3]['objects']))

        self.pickups = []

    @staticmethod
    def twiddle(src):
        for obj in src:
            t = obj['type']
            if t == 'food': item = Food(**obj)
            elif t == 'kebab': item = Schebab(**obj)
            elif t == 'key': item = QuestItem(**obj)
            else: raise ValueError, 'unknown type %s' % t
            yield item

    def draw(self, *args, **kwargs):
        Shader.upload_model(Matrix.identity())
        self.texture.texture_bind()
        self.vbo.draw(*args, **kwargs)

    def tile_at(self, pos):
        x = int(pos.x)
        y = -int(pos.y)
        if x < 0 or y < 0: return -1
        i = y * self.width + x
        try:
            return self.grid[i]
        except IndexError:
            return -1

    def update(self):
        self.pickups = [x for x in self.pickups if not x.killed]
예제 #6
0
파일: player.py 프로젝트: ext/scfa
class Player(object):
    weight = 70.0
    max_hp = 100

    def __init__(self, pos):
        self.pos = pos
        self.vel = Vector2f(0,0)
        self.texture = Image('texture/player.png', filter=GL_NEAREST)
        self.in_air = False
        self.jumping = 0
        self.hp = Player.max_hp
        self.hp_ratio = 0.8
        self.dir = 1
        self.cave_visited = False
        self.cave_quest = False
        self.have_ham = False
        self.have_cheese = False
        self.have_bread = False
        self.have_sandwich = False
        self.is_killed = False
        self.derp = False

        v = np.array([
                0,1,0, 0,1,
                1,1,0, 1,1,
                1,3,0, 1,0,
                0,3,0, 0,0,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.vbo = VBO(GL_QUADS, v, i)

    def update(self, dt, map):
        acc = 0.0
        acc -= 9.8 * dt

        if self.jumping > 0:
            acc += self.jumping / Player.weight * dt
            self.jumping -= 25.0

        self.vel.y += acc * dt

        # handle vertical
        self.in_air = True
        t1 = map.tile_at(self.pos + Vector2f(0, self.vel.y))
        t2 = map.tile_at(self.pos + Vector2f(0.999, self.vel.y))
        if walkable(t1) and walkable (t2):
            self.pos.y += self.vel.y
        else:
            if self.vel.y < -0.4:
                game.land.play()
            self.in_air = False
            self.vel.y = 0
            self.pos.y = math.floor(self.pos.y)
            if not walkable(map.tile_at(self.pos+Vector2f(0,0.1))):
                self.pos.y += 1

        # handle horizontal
        t1 = map.tile_at(self.pos + Vector2f(self.vel.x, 0.01))
        t2 = map.tile_at(self.pos + Vector2f(self.vel.x + 1.0, 0.01))
        if walkable(t1) and walkable(t2):
            self.pos.x += self.vel.x
        elif self.vel.x < 0:
            self.pos.x = math.floor(self.pos.x)
        elif self.vel.x > 0:
            self.pos.x = math.ceil(self.pos.x)

        # flip direction
        if self.vel.x > 0:
            self.dir = 1
        elif self.vel.x < 0:
            self.dir = -1

        # kill players falling down the hole
        if not self.is_killed and self.pos.y < -30 and self.pos.x >= 130 and self.pos.x <= 135:
            game.message('Player was killed while jumping down a hole')
            game.over()
            self.is_killed = True

        if not self.is_killed and self.hp <= 0.0001:
            game.message('player got lost in the woods and died')
            game.over()
            self.is_killed = True

        # subtract health
        d = (self.pos - Vector2f(53,-8)).length()
        d2 = (self.pos - Vector2f(354,-18)).length()
        d3 = (self.pos - Vector2f(200,-48)).length()
        d4 = (self.pos - Vector2f(384,-87)).length()
        if d >= 14.0 and d2 >= 14.0 and d3 >= 17.0 and d4 >= 20.0:
            self.hp -= 1.7 * dt
        else:
            self.hp += (Player.max_hp / 100.0) * dt

        self.hp = min(max(self.hp, 0.0), Player.max_hp)
        self.hp_ratio = float(self.hp) / Player.max_hp

        # test if possible to make sandwhich (without sudo)
        if d < 2 and self.have_cheese and self.have_ham and self.have_bread and not self.have_sandwich:
            game.message('Sandwich made')
            self.have_sandwich = True

        # check cave
        dc = (self.pos - Vector2f(354,-18)).length()
        if dc < 2.0 and not self.derp:
            if not self.cave_visited:
                if self.have_sandwich:
                    game.message('Dward: om nom nom, thank you for the sandwich')
                    game.message('Quest finished: "Make me a sandwich".')
                    self.derp = True
                else:
                    game.message('Dwarf: Hey there, could you fetch me a sandwich?')
                    self.cave_visited = True
                    if not self.cave_quest:
                        game.message('Quest started: "Make me a sandwich".')
                        self.cave_quest = True
        elif dc > 30.0:
            self.cave_visited = False

    def draw(self):
        model = Matrix.identity()

        # translate
        model[3,0] = self.pos.x + (self.dir == -1 and 1.0 or 0.0)
        model[3,1] = self.pos.y
        model[0,0] = self.dir

        Shader.upload_model(model)
        self.texture.texture_bind()
        self.vbo.draw()

    def jump(self):
        if not self.in_air:
            self.vel.y += 18.0 / Player.weight
            self.jumping = 900.0

    def unjump(self):
        self.jumping = 0

    def frobnicate(self, stuff):
        min2 = self.pos + Vector2f(0.25,0)
        max = self.pos + Vector2f(0.75,2)
        for obj in stuff:
            omin = obj.pos
            omax = obj.pos + Vector2f(1,1)

            if max.x < omin.x or min2.x > omax.x: continue
            if max.y < omin.y or min2.y > omax.y: continue

            self.hp = min(self.hp + obj.hp, Player.max_hp)
            obj.kill()
예제 #7
0
파일: game.py 프로젝트: ext/scfa
    def init(self, size, fullscreen=False):
        flags = OPENGL|DOUBLEBUF
        if fullscreen:
            flags |= FULLSCREEN

        pygame.display.set_mode(size.xy, flags)
        pygame.display.set_caption('Super Chainsaw Food Adventure')

        i = pygame.display.Info()
        self.size = Vector2i(i.current_w, i.current_h)

        glMatrixMode(GL_MODELVIEW)
        glEnable(GL_TEXTURE_2D)
        glDisable(GL_CULL_FACE)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)

        self.stage = 1
        self.projection = Matrix.perspective(75, self.size, 0.1, 100)
        self.ortho = Matrix.ortho(self.size)

        v = np.array([
                0,0,0, 0,0,
                1,0,0, 1,0,
                1,1,0, 1,1,
                0,1,0, 0,1,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.quad = VBO(GL_QUADS, v, i)

        # parallax
        self.parallax_rep = 25
        v = np.array([
                0,0,0, 0,1,
                1,0,0, self.parallax_rep, 1,
                1,1,0, self.parallax_rep,0,
                0,1,0, 0,0,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.repquad = VBO(GL_QUADS, v, i)
        self.parallax = Image('texture/sky.png', wrap=GL_REPEAT)
        self.parallax2 = Image('texture/sky2.png', wrap=GL_REPEAT)

        self.fbo = FBO(self.size, format=GL_RGB8, depth=True)

        self.shader = Shader('derp')
        self.passthru = Shader('passtru')
        self.herp = Shader('herp')

        self.map = Map('map.json')
        self.player = Player(Vector2f(55,-9))
        self.clock = pygame.time.Clock()
        self.hud = HUD(Vector2i(500,100))
        self.hpmeter = HUD(Vector2i(20, 500))
        self.font = self.hud.create_font(size=16)
        self.font2 = self.hud.create_font(size=12)

        self.land = pygame.mixer.Sound('data/sound/land.wav')
        self.ding = pygame.mixer.Sound('data/sound/ding.wav')
        self.eat = pygame.mixer.Sound('data/sound/eat.wav')
        self.wind = pygame.mixer.Sound('data/sound/wind.wav')

        self.wind.play(loops=-1)

        self.set_stage(1)
        self.killfade = None
        self.killfade2 = 1.0 # fade amount
        self.textbuf = []
        self.texttime = -10.0
        self.message('<b>Welcome adventurer!</b>\nYou can start exploring the world but beware of wandering away too far.')
        self.message('When outside of lights your <i>HP</i> will drain and you will get lost in the woods.')
        self.message('Eat food to temporary increase your <i>HP</i>.')
        self.message('Quest started: "Find the chainsaw".')
        self.message('Quest started: "Frobnicate something".')

        with self.hud:
            self.hud.clear((0,1,1,1))
예제 #8
0
파일: game.py 프로젝트: ext/scfa
class Game(object):
    def __init__(self):
        self._running = False
        self.camera = Vector2f(0,5)

    def init(self, size, fullscreen=False):
        flags = OPENGL|DOUBLEBUF
        if fullscreen:
            flags |= FULLSCREEN

        pygame.display.set_mode(size.xy, flags)
        pygame.display.set_caption('Super Chainsaw Food Adventure')

        i = pygame.display.Info()
        self.size = Vector2i(i.current_w, i.current_h)

        glMatrixMode(GL_MODELVIEW)
        glEnable(GL_TEXTURE_2D)
        glDisable(GL_CULL_FACE)
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA)

        self.stage = 1
        self.projection = Matrix.perspective(75, self.size, 0.1, 100)
        self.ortho = Matrix.ortho(self.size)

        v = np.array([
                0,0,0, 0,0,
                1,0,0, 1,0,
                1,1,0, 1,1,
                0,1,0, 0,1,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.quad = VBO(GL_QUADS, v, i)

        # parallax
        self.parallax_rep = 25
        v = np.array([
                0,0,0, 0,1,
                1,0,0, self.parallax_rep, 1,
                1,1,0, self.parallax_rep,0,
                0,1,0, 0,0,
                ], np.float32)
        i = np.array([0,1,2,3], np.uint32)
        self.repquad = VBO(GL_QUADS, v, i)
        self.parallax = Image('texture/sky.png', wrap=GL_REPEAT)
        self.parallax2 = Image('texture/sky2.png', wrap=GL_REPEAT)

        self.fbo = FBO(self.size, format=GL_RGB8, depth=True)

        self.shader = Shader('derp')
        self.passthru = Shader('passtru')
        self.herp = Shader('herp')

        self.map = Map('map.json')
        self.player = Player(Vector2f(55,-9))
        self.clock = pygame.time.Clock()
        self.hud = HUD(Vector2i(500,100))
        self.hpmeter = HUD(Vector2i(20, 500))
        self.font = self.hud.create_font(size=16)
        self.font2 = self.hud.create_font(size=12)

        self.land = pygame.mixer.Sound('data/sound/land.wav')
        self.ding = pygame.mixer.Sound('data/sound/ding.wav')
        self.eat = pygame.mixer.Sound('data/sound/eat.wav')
        self.wind = pygame.mixer.Sound('data/sound/wind.wav')

        self.wind.play(loops=-1)

        self.set_stage(1)
        self.killfade = None
        self.killfade2 = 1.0 # fade amount
        self.textbuf = []
        self.texttime = -10.0
        self.message('<b>Welcome adventurer!</b>\nYou can start exploring the world but beware of wandering away too far.')
        self.message('When outside of lights your <i>HP</i> will drain and you will get lost in the woods.')
        self.message('Eat food to temporary increase your <i>HP</i>.')
        self.message('Quest started: "Find the chainsaw".')
        self.message('Quest started: "Frobnicate something".')

        with self.hud:
            self.hud.clear((0,1,1,1))

    def running(self):
        return self._running

    @event(pygame.QUIT)
    def quit(self, event=None):
        self._running = False

    @event(pygame.KEYDOWN)
    def on_keypress(self, event):
        if event.key == 113 and event.mod & KMOD_CTRL: # ctrl+q
            return self.quit()
        if event.key == 27: # esc
            return self.quit()

        if event.key == 119:
            self.player.jump()

    @event(pygame.KEYUP)
    def on_keyrelease(self, event):
        if event.key == 119:
            self.player.unjump()

    def poll(self):
        global event_table
        for event in pygame.event.get():
            func = event_table.get(event.type, None)
            if func is None:
                continue
            func(self, event)

    def update(self):
        if self.killfade is not None:
            t = pygame.time.get_ticks() / 1000.0
            s = (t - self.killfade) / 2.5
            self.killfade2 = 1.0 - s

            if s > 1.0:
                self.quit()

            # so player keeps falling
            dt = 1.0 / self.clock.tick(60)
            self.player.vel.y = 0
            self.player.update(dt, self.map)

            return

        key = pygame.key.get_pressed()

        self.player.vel.x = 0
        if key[97 ]: self.player.vel.x = -0.15
        if key[100]: self.player.vel.x =  0.15

        if key[260]: self.camera.x -= 0.1
        if key[262]: self.camera.x += 0.1
        if key[258]: self.camera.y -= 0.1
        if key[264]: self.camera.y += 0.1

        dt = 1.0 / self.clock.tick(60)
        self.player.update(dt, self.map)
        self.player.frobnicate(self.map.pickups)
        self.map.update()

    def render(self):
        glClearColor(1,0,1,1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

        with self.hpmeter as hud:
            hud.clear((0.3,0,0,1))
            hud.cr.identity_matrix()

            hud.rectangle(0,0, hud.width, hud.height * self.player.hp_ratio, (0,0.3,0,1))

            hud.cr.translate(18,0)
            hud.cr.rotate(math.pi*0.5)
            hud.text(' Energy: %d / %d' % (int(math.ceil(self.player.hp/10)) * 10, Player.max_hp), self.font2, color=(1,0.8,0,1))

        with self.hud:
            self.hud.clear((0,0,0,0))
            self.hud.cr.identity_matrix()

            t = pygame.time.get_ticks() / 1000.0
            s = (t - self.texttime) / 4.0

            if s > 1.0:
                if len(self.textbuf) > 0:
                    self.texttime = pygame.time.get_ticks() / 1000.0
                    self.text = self.textbuf.pop(0)
            else:
                a = min(1.0-s, 0.2) * 5
                self.hud.cr.translate(0,25)
                self.hud.text(self.text, self.font, color=(1,0.8,0,a), width=self.hud.width, alignment=ALIGN_CENTER)

        view = Matrix.lookat(
            self.player.pos.x, self.player.pos.y+7, 15,
            self.player.pos.x, self.player.pos.y+7, 0,
            0,1,0)

        with self.fbo as frame:
            frame.clear(0,0.03,0.15,1)

            Shader.upload_projection_view(self.projection, view)
            Shader.upload_player(self.player)
            self.shader.bind()

            # parallax background
            pm1 = Matrix.identity()
            pm1[3,0] = self.player.pos.x * 0.35 - 20
            pm1[3,1] = self.player.pos.y * 0.5 - 20
            pm1[0,0] = 42.0 * self.parallax_rep
            pm1[1,1] = 42.0
            self.parallax.texture_bind()
            Shader.upload_model(pm1)
            self.repquad.draw()

            Shader.upload_projection_view(self.projection, view)

            self.map.draw()

            # entities
            for obj in self.map.pickups:
                obj.draw(self.quad)
            self.player.draw()

            # parallax 2
            pm1 = Matrix.identity()
            pm1[3,0] = self.player.pos.x * -2.0 + 100
            pm1[3,1] = self.player.pos.y * 0.5 - 45 * 3 + 10
            pm1[0,0] = 45.0 * self.parallax_rep * 3
            pm1[1,1] = 45 * 3
            self.parallax2.texture_bind()
            Shader.upload_model(pm1)
            self.repquad.draw()

        mat = Matrix.identity()
        mat[0,0] = self.size.x
        mat[1,1] = self.size.y
        Shader.upload_projection_view(self.ortho, Matrix.identity())
        Shader.upload_model(mat)

        self.fbo.bind_texture()
        self.herp.bind()
        self.quad.draw()

        # messagebox
        mat = Matrix.identity()
        mat[3,0] = self.size.x / 2 - self.hud.width / 2
        mat[3,1] = self.size.y - self.hud.height
        Shader.upload_model(mat)
        self.hud.draw()

        # hpmeter
        mat = Matrix.identity()
        mat[3,1] = self.size.y / 2 - self.hpmeter.height / 2
        Shader.upload_model(mat)
        self.hpmeter.draw()

        Shader.unbind()

        pygame.display.flip()

    def run(self):
        self._running = True
        while self.running():
            self.poll()
            self.update()
            self.render()

    def message(self, text):
        self.textbuf.append(text)

    def set_stage(self, n):
        if n == 1:
            self.map.pickups.extend(self.map.obj1)
        elif n == 2:
            self.map.pickups.extend(self.map.obj2)
        elif n == 3:
            self.map.pickups.extend(self.map.obj3)

    def over(self):
        self.killfade = pygame.time.get_ticks() / 1000.0