Ejemplo n.º 1
0
 def __init__(self, *args, **keyargs):
     """Constructor"""
     # construct the base class
     super(FBOWindow, self).__init__(*args, **keyargs)
     # construct the fbo and attach it
     self.fbo = FBO(self.width, self.height)
     self.fbo.attach()
Ejemplo n.º 2
0
    def __init__(self, *args, **kwargs):
        super(SSAO, self).__init__(*args, **kwargs)
        self.sf = 3
        w, h = self.size[0] / self.sf, self.size[1] / self.sf
        
        self.normdepth = FBO(["color0", "depth"], size=(w,h))
        self.ping = FBO(['color0'], size=(w,h))
        self.pong = FBO(["color0"], size=(w,h))

        self.add_shader("fsquad", GL_VERTEX_SHADER, "fsquad.v.glsl")
        self.add_shader("ssao_pass1", GL_FRAGMENT_SHADER, "ssao_pass1.f.glsl")
        self.add_shader("ssao_pass2", GL_FRAGMENT_SHADER, "ssao_pass2.f.glsl")
        self.add_shader("ssao_pass3", GL_FRAGMENT_SHADER, "ssao_pass3.f.glsl", "phong.f.glsl")
        self.add_shader("hblur", GL_FRAGMENT_SHADER, "hblur.f.glsl")
        self.add_shader("vblur", GL_FRAGMENT_SHADER, "vblur.f.glsl")

        #override the default shader with this passthru + ssao_pass1 to store depth
        self.add_program("ssao_pass1", ("passthru", "ssao_pass1"))
        self.add_program("ssao_pass2", ("fsquad", "ssao_pass2"))
        self.add_program("hblur", ("fsquad", "hblur"))
        self.add_program("vblur", ("fsquad", "vblur"))
        self.add_program("ssao_pass3", ("passthru", "ssao_pass3"))

        randtex = np.random.rand(3, w, h)
        randtex /= randtex.sum(0)
        self.rnm = Texture(randtex.T, wrap_x=GL_REPEAT, wrap_y=GL_REPEAT, 
            magfilter=GL_NEAREST, minfilter=GL_NEAREST)
        self.rnm.init()

        self.clips = args[2], args[3]
Ejemplo n.º 3
0
class FBOWindow(PyprocessingWindow):
    """This is a pyglet window where drawing in fact occurs inside an FBO.
    The flip method is overridden so that instead of merely swapping the
    back and front buffers, the FBO is first blitted onto the back buffer.
    The idea is to provide a stable drawing canvas which is not erased or
    corrupted by the flip."""
    def __init__(self, *args, **keyargs):
        """Constructor"""
        # construct the base class
        super(FBOWindow, self).__init__(*args, **keyargs)
        # construct the fbo and attach it
        self.fbo = FBO(self.width, self.height)
        self.fbo.attach()

    def flip(self):
        """Override the flip method."""
        # cease using the FBO and start using the regular frame buffer
        self.fbo.detach()
        # save the OpenGL state
        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity()
        glPushAttrib(GL_ALL_ATTRIB_BITS)
        glViewport(0, 0, self.width, self.height)
        # Draws a quad with the fbo as a texture
        glDisable(GL_BLEND)
        glDisable(GL_DEPTH_TEST)
        glDisable(GL_LIGHTING)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
        glEnable(GL_TEXTURE_2D)
        glColor3f(1, 1, 1)
        glBindTexture(GL_TEXTURE_2D, self.fbo.img)
        glBegin(GL_QUADS)
        for v, t in [((-1, -1, 0), (0, 0)), ((-1, 1, 0), (0, 1)),
                     ((1, 1, 0), (1, 1)), ((1, -1, 0), (1, 0))]:
            glTexCoord2f(*t)
            glVertex3f(*v)
        glEnd()
        # restore the state
        glMatrixMode(GL_PROJECTION)
        glPopMatrix()
        glMatrixMode(GL_MODELVIEW)
        glPopMatrix()
        glPopAttrib()

        # do the actual flip
        super(FBOWindow, self).flip()
        # reattach the fbo for further drawing
        self.fbo.attach()

    def on_resize(self, w, h):
        super(FBOWindow, self).on_resize(w, h)
        self.fbo.detach()
        self.fbo = FBO(w, h)
        self.fbo.attach()
Ejemplo n.º 4
0
 def __init__(self, *args, **keyargs):
     """Constructor"""
     # construct the base class
     super(FBOWindow, self).__init__(*args, **keyargs)
     # construct the fbo and attach it
     self.fbo = FBO(self.width, self.height)
     self.fbo.attach()
Ejemplo n.º 5
0
class FBOWindow(PyprocessingWindow):
    """This is a pyglet window where drawing in fact occurs inside a FBO.
    The flip method is overridden so that instead of merely swapping the
    back and front buffers, the FBO is first blitted onto the back buffer.
    The idea is to provide a stable drawing canvas which is not erased or
    corrupted by the flip."""
    def __init__(self, *args, **keyargs):
        """Constructor"""
        # construct the base class
        super(FBOWindow, self).__init__(*args, **keyargs)
        # construct the fbo and attach it
        self.fbo = FBO(self.width, self.height)
        self.fbo.attach()

    def flip(self):
        """Override the flip method."""
        # cease using the FBO and start using the regular frame buffer
        self.fbo.detach()
        # save the OpenGL state
        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity()
        glViewport(0, 0, self.width, self.height)
        # prepares and blits the FBO buffer onto the back buffer.
        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, self.fbo.framebuffer)
        glReadBuffer(GL_COLOR_ATTACHMENT0_EXT)
        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0)
        glDrawBuffer(GL_BACK)
        glBlitFramebufferEXT(0, 0, self.width, self.height, 0, 0, self.width,
                             self.height, GL_COLOR_BUFFER_BIT, GL_NEAREST)
        glMatrixMode(GL_PROJECTION)
        glPopMatrix()
        glMatrixMode(GL_MODELVIEW)
        glPopMatrix()
        # do the actual flip
        super(FBOWindow, self).flip()
        # reattach the fbo for further drawing
        self.fbo.attach()

    def on_resize(self, w, h):
        super(FBOWindow, self).on_resize(w, h)
        self.fbo.detach()
        self.fbo = FBO(w, h)
        self.fbo.attach()
Ejemplo n.º 6
0
class FBOWindow(PyprocessingWindow):
    """This is a pyglet window where drawing in fact occurs inside a FBO.
    The flip method is overridden so that instead of merely swapping the
    back and front buffers, the FBO is first blitted onto the back buffer.
    The idea is to provide a stable drawing canvas which is not erased or
    corrupted by the flip."""
    
    def __init__(self, *args, **keyargs):
        """Constructor"""
        # construct the base class
        super(FBOWindow, self).__init__(*args, **keyargs)
        # construct the fbo and attach it
        self.fbo = FBO(self.width, self.height)
        self.fbo.attach()
        
    def flip(self):
        """Override the flip method."""
        # cease using the FBO and start using the regular frame buffer
        self.fbo.detach()
        # save the OpenGL state
        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity()
        glViewport(0,0,self.width,self.height)
        # prepares and blits the FBO buffer onto the back buffer.
        glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, self.fbo.framebuffer)
        glReadBuffer(GL_COLOR_ATTACHMENT0_EXT)
        glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0)
        glDrawBuffer(GL_BACK)
        glBlitFramebufferEXT(0, 0, self.width, self.height, 0, 0, self.width, self.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
        glMatrixMode(GL_PROJECTION)
        glPopMatrix()
        glMatrixMode(GL_MODELVIEW)
        glPopMatrix()
        # do the actual flip
        super (FBOWindow, self).flip()
        # reattach the fbo for further drawing
        self.fbo.attach()
        
    def on_resize(self,w,h):
        super (FBOWindow, self).on_resize(w,h)
        self.fbo.detach()
        self.fbo = FBO(w,h)
        self.fbo.attach()
Ejemplo n.º 7
0
    def __init__(self, *args, **kwargs):
        super(SSAO, self).__init__(*args, **kwargs)
        self.sf = 3
        w, h = self.size[0] / self.sf, self.size[1] / self.sf

        self.normdepth = FBO(["color0", "depth"], size=(w, h))
        self.ping = FBO(['color0'], size=(w, h))
        self.pong = FBO(["color0"], size=(w, h))

        self.add_shader("fsquad", GL_VERTEX_SHADER, "fsquad.v.glsl")
        self.add_shader("ssao_pass1", GL_FRAGMENT_SHADER, "ssao_pass1.f.glsl")
        self.add_shader("ssao_pass2", GL_FRAGMENT_SHADER, "ssao_pass2.f.glsl")
        self.add_shader("ssao_pass3", GL_FRAGMENT_SHADER, "ssao_pass3.f.glsl",
                        "phong.f.glsl")
        self.add_shader("hblur", GL_FRAGMENT_SHADER, "hblur.f.glsl")
        self.add_shader("vblur", GL_FRAGMENT_SHADER, "vblur.f.glsl")

        #override the default shader with this passthru + ssao_pass1 to store depth
        self.add_program("ssao_pass1", ("passthru", "ssao_pass1"))
        self.add_program("ssao_pass2", ("fsquad", "ssao_pass2"))
        self.add_program("hblur", ("fsquad", "hblur"))
        self.add_program("vblur", ("fsquad", "vblur"))
        self.add_program("ssao_pass3", ("passthru", "ssao_pass3"))

        randtex = np.random.rand(3, w, h)
        randtex /= randtex.sum(0)
        self.rnm = Texture(randtex.T,
                           wrap_x=GL_REPEAT,
                           wrap_y=GL_REPEAT,
                           magfilter=GL_NEAREST,
                           minfilter=GL_NEAREST)
        self.rnm.init()

        self.clips = args[2], args[3]
Ejemplo n.º 8
0
 def on_resize(self, w, h):
     super(FBOWindow, self).on_resize(w, h)
     self.fbo.detach()
     self.fbo = FBO(w, h)
     self.fbo.attach()
Ejemplo n.º 9
0
 def on_resize(self,w,h):
     super (FBOWindow, self).on_resize(w,h)
     self.fbo.detach()
     self.fbo = FBO(w,h)
     self.fbo.attach()
Ejemplo n.º 10
0
class SSAO(FBOrender):
    def __init__(self, *args, **kwargs):
        super(SSAO, self).__init__(*args, **kwargs)
        self.sf = 3
        w, h = self.size[0] / self.sf, self.size[1] / self.sf

        self.normdepth = FBO(["color0", "depth"], size=(w, h))
        self.ping = FBO(['color0'], size=(w, h))
        self.pong = FBO(["color0"], size=(w, h))

        self.add_shader("fsquad", GL_VERTEX_SHADER, "fsquad.v.glsl")
        self.add_shader("ssao_pass1", GL_FRAGMENT_SHADER, "ssao_pass1.f.glsl")
        self.add_shader("ssao_pass2", GL_FRAGMENT_SHADER, "ssao_pass2.f.glsl")
        self.add_shader("ssao_pass3", GL_FRAGMENT_SHADER, "ssao_pass3.f.glsl",
                        "phong.f.glsl")
        self.add_shader("hblur", GL_FRAGMENT_SHADER, "hblur.f.glsl")
        self.add_shader("vblur", GL_FRAGMENT_SHADER, "vblur.f.glsl")

        #override the default shader with this passthru + ssao_pass1 to store depth
        self.add_program("ssao_pass1", ("passthru", "ssao_pass1"))
        self.add_program("ssao_pass2", ("fsquad", "ssao_pass2"))
        self.add_program("hblur", ("fsquad", "hblur"))
        self.add_program("vblur", ("fsquad", "vblur"))
        self.add_program("ssao_pass3", ("passthru", "ssao_pass3"))

        randtex = np.random.rand(3, w, h)
        randtex /= randtex.sum(0)
        self.rnm = Texture(randtex.T,
                           wrap_x=GL_REPEAT,
                           wrap_y=GL_REPEAT,
                           magfilter=GL_NEAREST,
                           minfilter=GL_NEAREST)
        self.rnm.init()

        self.clips = args[2], args[3]

    def draw(self, root, **kwargs):
        #First, draw the whole damned scene, but only read the normals and depth into ssao
        glPushAttrib(GL_VIEWPORT_BIT)
        glViewport(0, 0, self.size[0] / self.sf, self.size[1] / self.sf)
        self.draw_to_fbo(self.normdepth, root, shader="ssao_pass1", **kwargs)

        #Now, do the actual ssao calculations, and draw it into ping
        self.draw_fsquad_to_fbo(self.pong,
                                "ssao_pass2",
                                rnm=self.rnm,
                                normalMap=self.normdepth['color0'],
                                depthMap=self.normdepth['depth'],
                                nearclip=self.clips[0],
                                farclip=self.clips[1])

        #Blur the textures
        self.draw_fsquad_to_fbo(self.ping,
                                "hblur",
                                tex=self.pong['color0'],
                                blur=1. / (self.size[0] / self.sf))
        self.draw_fsquad_to_fbo(self.pong,
                                "vblur",
                                tex=self.ping['color0'],
                                blur=1. / (self.size[0] / self.sf))

        glPopAttrib()
        #Actually draw the final image to the screen
        win = glGetIntegerv(GL_VIEWPORT)
        #Why is this call necessary at all?!
        glViewport(*win)

        super(SSAO, self).draw(root,
                               shader="ssao_pass3",
                               shadow=self.pong['color0'],
                               window=[float(i) for i in win],
                               **kwargs)

        #self.draw_done()

    def clear(self):
        self.normdepth.clear()
        self.ping.clear()
        self.pong.clear()

    def draw_done(self):
        super(SSAO, self).draw_done()
        self.clear()
Ejemplo n.º 11
0
class SSAO(FBOrender):
    def __init__(self, *args, **kwargs):
        super(SSAO, self).__init__(*args, **kwargs)
        self.sf = 3
        w, h = self.size[0] / self.sf, self.size[1] / self.sf
        
        self.normdepth = FBO(["color0", "depth"], size=(w,h))
        self.ping = FBO(['color0'], size=(w,h))
        self.pong = FBO(["color0"], size=(w,h))

        self.add_shader("fsquad", GL_VERTEX_SHADER, "fsquad.v.glsl")
        self.add_shader("ssao_pass1", GL_FRAGMENT_SHADER, "ssao_pass1.f.glsl")
        self.add_shader("ssao_pass2", GL_FRAGMENT_SHADER, "ssao_pass2.f.glsl")
        self.add_shader("ssao_pass3", GL_FRAGMENT_SHADER, "ssao_pass3.f.glsl", "phong.f.glsl")
        self.add_shader("hblur", GL_FRAGMENT_SHADER, "hblur.f.glsl")
        self.add_shader("vblur", GL_FRAGMENT_SHADER, "vblur.f.glsl")

        #override the default shader with this passthru + ssao_pass1 to store depth
        self.add_program("ssao_pass1", ("passthru", "ssao_pass1"))
        self.add_program("ssao_pass2", ("fsquad", "ssao_pass2"))
        self.add_program("hblur", ("fsquad", "hblur"))
        self.add_program("vblur", ("fsquad", "vblur"))
        self.add_program("ssao_pass3", ("passthru", "ssao_pass3"))

        randtex = np.random.rand(3, w, h)
        randtex /= randtex.sum(0)
        self.rnm = Texture(randtex.T, wrap_x=GL_REPEAT, wrap_y=GL_REPEAT, 
            magfilter=GL_NEAREST, minfilter=GL_NEAREST)
        self.rnm.init()

        self.clips = args[2], args[3]

    def draw(self, root, **kwargs):
        #First, draw the whole damned scene, but only read the normals and depth into ssao
        glPushAttrib(GL_VIEWPORT_BIT)
        glViewport( 0,0, self.size[0]/self.sf, self.size[1]/self.sf)
        self.draw_to_fbo(self.normdepth, root, shader="ssao_pass1", **kwargs)
        
        #Now, do the actual ssao calculations, and draw it into ping
        self.draw_fsquad_to_fbo(self.pong, "ssao_pass2", rnm=self.rnm,
            normalMap=self.normdepth['color0'], depthMap=self.normdepth['depth'],
            nearclip=self.clips[0], farclip=self.clips[1] )
        
        #Blur the textures
        self.draw_fsquad_to_fbo(self.ping, "hblur", tex=self.pong['color0'], blur=1./(self.size[0]/self.sf))
        self.draw_fsquad_to_fbo(self.pong, "vblur", tex=self.ping['color0'], blur=1./(self.size[0]/self.sf))
        
        glPopAttrib()
        #Actually draw the final image to the screen
        win = glGetIntegerv(GL_VIEWPORT)
        #Why is this call necessary at all?!
        glViewport(*win)
        
        super(SSAO, self).draw(root, shader="ssao_pass3", shadow=self.pong['color0'], 
            window=[float(i) for i in win], **kwargs)
        
        #self.draw_done()
    
    def clear(self):
        self.normdepth.clear()
        self.ping.clear()
        self.pong.clear()
    
    def draw_done(self):
        super(SSAO, self).draw_done()
        self.clear()
Ejemplo n.º 12
0
class FBOWindow(PyprocessingWindow):
    """This is a pyglet window where drawing in fact occurs inside an FBO.
    The flip method is overridden so that instead of merely swapping the
    back and front buffers, the FBO is first blitted onto the back buffer.
    The idea is to provide a stable drawing canvas which is not erased or
    corrupted by the flip."""
    
    def __init__(self, *args, **keyargs):
        """Constructor"""
        # construct the base class
        super(FBOWindow, self).__init__(*args, **keyargs)
        # construct the fbo and attach it
        self.fbo = FBO(self.width, self.height)
        self.fbo.attach()
        
    def flip(self):
        """Override the flip method."""
        # cease using the FBO and start using the regular frame buffer
        self.fbo.detach()
        # save the OpenGL state
        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity()
        glPushAttrib(GL_ALL_ATTRIB_BITS)
        glViewport(0,0,self.width,self.height)
        # Draws a quad with the fbo as a texture
        glDisable(GL_BLEND)
        glDisable(GL_DEPTH_TEST)
        glDisable(GL_LIGHTING)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
        glEnable(GL_TEXTURE_2D)
        glColor3f(1,1,1)
        glBindTexture(GL_TEXTURE_2D, self.fbo.img)
        glBegin(GL_QUADS)
        for v,t in [((-1,-1,0),(0,0)),
                ((-1,1,0),(0,1)),
                ((1,1,0),(1,1)),
                ((1,-1,0),(1,0))]: 
           glTexCoord2f(*t)
           glVertex3f(*v)
        glEnd()
        # restore the state
        glMatrixMode(GL_PROJECTION)
        glPopMatrix()
        glMatrixMode(GL_MODELVIEW)
        glPopMatrix()
        glPopAttrib()

        # do the actual flip
        super (FBOWindow, self).flip()
        # reattach the fbo for further drawing
        self.fbo.attach()
        
    def on_resize(self,w,h):
        super (FBOWindow, self).on_resize(w,h)
        self.fbo.detach()
        self.fbo = FBO(w,h)
        self.fbo.attach()
Ejemplo n.º 13
0
Archivo: game.py Proyecto: 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))
Ejemplo n.º 14
0
Archivo: game.py Proyecto: 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