Beispiel #1
0
class Applet(pyglet.window.Window):
    def update(self, dt):
        cam = self.cam
        if self.exclusive:
            if key.A in self.keys:
                cam.roll += 4
            if key.S in self.keys:
                cam.roll -= 4
            x0, y0, z0 = cam.x, cam.y, cam.z
            cam.move(0, 0, -self.speed * 128 * 0.003)
            x1, y1, z1 = cam.x, cam.y, cam.z

            iz0, iz1 = int(z0), int(z1)
            # Now checking if you passed a torus
            if iz0 // 10 != iz1 // 10:
                dx, dy, dz = x1 - x0, y1 - y0, z1 - z0
                for i in xrange(iz1 - iz0):
                    # Passed a torus boundary
                    torus = iz0 // 10 + i + 1
                    if torus >= len(self.world.tori):
                        break
                    tz = torus * 10
                    tx, ty = self.world.tori[torus]
                    factor = (tz - z0) / dz
                    ax, ay = factor * dx + x0, factor * dy + y0
                    distance = hypot(ax - tx, ay - ty)
                    if distance > TORUS_MAJOR:
                        # Oops, you just got out of a torus!
                        self.score -= 10
                        if OVERLAY:
                            def hit(err):
                                w, h = self.get_size()
                                glPushAttrib(GL_CURRENT_BIT)
                                glEnable(GL_BLEND)
                                glColor4f(1, 0, 0, err / 100.0)
                                glBegin(GL_QUADS)
                                glVertex2f(0, 0)
                                glVertex2f(0, h)
                                glVertex2f(w, h)
                                glVertex2f(w, 0)
                                glEnd()
                                glPopAttrib()
                                return err - 1
                            if not self.debug:
                                self.overlays[hit] = 50
                    else:
                        self.score += 1
                        self.progress += 1

            self.speed += DELTA
        for entity in self.world.tracker:
            entity.update()

    def __init__(self, *args, **kwargs):
        super(Applet, self).__init__(*args, **kwargs)
        l = clock()
        self.fps = 0
        self.world = load_world("world.json")
        self.speed = INITIAL_SPEED
        self.score = 20
        self.progress = 0
        self.keys = []
        self.overlays = {}
        self.info = True
        self.debug = False

        self.label = pyglet.text.Label('', font_name='Consolas', font_size=12, x=10, y=self.height - 20,
                                       color=(255,) * 4, multiline=True, width=600)
        # Resize is called on startup anyways, so we can start with 0 values.
        self.cam = Camera()

        self.exclusive = False
        pyglet.clock.schedule_interval(self.update, 1.0 / TICKS_PER_SECOND)

        def update_fps(dt):
            self.fps = pyglet.clock.get_fps()

        pyglet.clock.schedule_interval(update_fps, 1)

        glClearColor(0, 0, 0, 1)
        glClearDepth(1.0)

        texture.init()
        if not texture.badcard:
            print 'Not bad card'
            glEnable(GL_BLEND)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
            glEnable(GL_LINE_SMOOTH)
            glEnable(GL_POLYGON_SMOOTH)
            glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
            glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST)

        glAlphaFunc(GL_GEQUAL, 0.9)
        glDepthFunc(GL_LEQUAL)
        glEnable(GL_DEPTH_TEST)
        glShadeModel(GL_SMOOTH)

        glMatrixMode(GL_MODELVIEW)

        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        glEnable(GL_LIGHT1)

        glEnable(GL_POLYGON_OFFSET_FILL)

        fv4 = GLfloat * 4

        glLightfv(GL_LIGHT0, GL_POSITION, fv4(.5, .5, 1, 0))
        glLightfv(GL_LIGHT0, GL_SPECULAR, fv4(.5, .5, 1, 1))
        glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4(1, 1, 1, 1))
        glLightfv(GL_LIGHT1, GL_POSITION, fv4(1, 0, .5, 0))
        glLightfv(GL_LIGHT1, GL_DIFFUSE, fv4(.5, .5, .5, 1))
        glLightfv(GL_LIGHT1, GL_SPECULAR, fv4(1, 1, 1, 1))

        self.torus_id = compile(torus, 3.0, 0.25, TORUS_DETAIL ** 2, TORUS_DETAIL ** 2, (.07, .37, 1, 2))
        self.cl_torus_id = compile(torus, 3.0, 0.25, TORUS_DETAIL ** 2, TORUS_DETAIL ** 2, (0, 1, 0, 1))

        self.asteroid_ids = [model_list(load_model(r"asteroids\01.obj"), 5, 5, 5, (0, 0, 0)),
                             model_list(load_model(r"asteroids\02.obj"), 5, 5, 5, (0, 0, 0)),
                             model_list(load_model(r"asteroids\03.obj"), 5, 5, 5, (0, 0, 0)),
                             model_list(load_model(r"asteroids\04.obj"), 5, 5, 5, (0, 0, 0)),
                             model_list(load_model(r"asteroids\05.obj"), 5, 5, 5, (0, 0, 0))]

        c = self.cam
        # Position camera at first torus...
        (c.x, c.y), c.z = self.world.tori[0], 0
        c.z -= 10 # ... well, 10 units away...
        self.cam.yaw = 180 # ... and face the torus.

        print "Loaded in %s seconds." % (clock() - l)

    def set_exclusive_mouse(self, exclusive):
        super(Applet, self).set_exclusive_mouse(exclusive) # Pass to parent
        self.exclusive = exclusive # Toggle flag

    def on_mouse_press(self, x, y, button, modifiers):
        if not self.exclusive:
            self.set_exclusive_mouse(True)

    def on_mouse_motion(self, x, y, dx, dy):
        if self.exclusive: # Only handle camera movement if mouse is grabbed
            self.cam.mouse_move(dx * MOUSE_SENSITIVITY, dy * MOUSE_SENSITIVITY)

    def on_key_press(self, symbol, modifiers):
        if self.exclusive: # Only handle keyboard input if mouse is grabbed
            if symbol == key.ESCAPE:
                pyglet.app.exit()
            elif symbol == key.E:
                self.set_exclusive_mouse(False) # Escape mouse
            elif symbol == key.F:
                self.set_fullscreen(not self.fullscreen)
            elif symbol == key.NUM_ADD:
                self.speed += 1
            elif symbol == key.NUM_SUBTRACT:
                self.speed -= 1
            elif symbol == key.NUM_MULTIPLY:
                self.speed += 10
            elif symbol == key.NUM_DIVIDE:
                self.speed -= 10
            elif symbol == key.PAGEUP:
                self.speed += 100
            elif symbol == key.PAGEDOWN:
                self.speed -= 100
            elif symbol == key.I:
                self.info = not self.info
            elif symbol == key.D:
                self.debug = not self.debug
            elif symbol == key.Q:
                c = self.cam
                dx, dy, dz = c.direction()
                speed = max(1, abs(self.speed) * 0.6)
                dx *= speed
                dy *= speed
                dz *= speed
                self.world.tracker.append(
                    Asteroid(random.choice(self.asteroid_ids), (c.x, c.y - 3, c.z + 5), direction=(dx, dy, dz)))
            else:
                self.keys.append(symbol)

    def on_key_release(self, symbol, modifiers):
        if symbol in self.keys:
            self.keys.remove(symbol)

    def on_resize(self, width, height):
        height = max(height, 1) # Prevent / by 0
        self.label.y = height - 20
        glViewport(0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        # A field of view of 45
        gluPerspective(45.0, width / float(height), 0.1, 50000000.0)
        glMatrixMode(GL_MODELVIEW)

    def on_draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()

        c = self.cam
        x, y, z = c.x, c.y, c.z
        glRotatef(c.pitch, 1, 0, 0)
        glRotatef(c.yaw, 0, 1, 0)
        glRotatef(c.roll, 0, 0, 1)
        glTranslatef(-x, -y, -z)

        if self.world.waypoints and self.debug:
            glDisable(GL_LIGHTING)
            glPushAttrib(GL_LINE_BIT | GL_CURRENT_BIT)
            glColor3f(0, 1, 0)
            glLineWidth(3)
            glBegin(GL_LINE_STRIP)
            for waypoint in self.world.waypoints:
                glVertex3f(*waypoint)
            glEnd()
            glPopAttrib()

        glEnable(GL_LIGHTING)
        glEnable(GL_BLEND)
        world = self.world
        if x != world.x or y != world.y or z != world.z:
            world.tracker.sort(key=entity_distance(x, y, z), reverse=True)
            world.tracker.sort(key=attrgetter('background'), reverse=True)
            world.x, world.y, world.z = x, y, z

        flipped = c.pitch > 90 or c.pitch < -90
        zi = int(z) / 10 * 10
        if (not flipped and 90 <= c.yaw < 270) or (flipped and (c.yaw < 90 or c.yaw >= 270)):
            zi += 10
            range = xrange(max(0, zi - 10), min(zi + VIEW_DISTANCE * 10, len(world.tori) * 10), 10)
        else:
            zi += 10
            range = xrange(max(0, zi - VIEW_DISTANCE * 10), min(zi + 10, len(world.tori) * 10), 10)
        for z in range:
            torus = z / 10
            x, y = world.tori[torus]
            id = self.cl_torus_id if z == zi else self.torus_id
            glPushMatrix()
            glTranslatef(x, y, z)
            glPushAttrib(GL_TRANSFORM_BIT | GL_CURRENT_BIT)
            glCallList(id)
            glPopAttrib()
            glPopMatrix()

        for entity in world.tracker:
            x, y, z = entity.location
            pitch, yaw, roll = entity.rotation

            glPushMatrix()
            glTranslatef(x, y, z)
            glRotatef(pitch, 1, 0, 0)
            glRotatef(yaw, 0, 1, 0)
            glRotatef(roll, 0, 0, 1)
            glPushAttrib(GL_CURRENT_BIT)
            glCallList(entity.id)
            if self.debug:
                glPushMatrix()
                glLineWidth(0.25)
                glPolygonOffset(1, 1)
                glDisable(GL_LIGHTING)
                glDisable(GL_TEXTURE_2D)
                glColor3f(0, 1, 0)
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
                glCallList(entity.id)
                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
                glEnable(GL_LIGHTING)
                glEnable(GL_TEXTURE_2D)
                glPopMatrix()
            glPopAttrib()
            glPopMatrix()

            if hasattr(entity, 'atmosphere') and entity.atmosphere:
                glPushMatrix()
                x0, y0, z0 = entity.location
                dx, dy, dz = x - x0, y - y0, z - z0

                distance = sqrt(dz * dz + dx * dx)
                pitch = (360 - degrees(atan2(dy, distance)))
                yaw = degrees(atan2(dx, dz))

                glTranslatef(x0, y0, z0)
                glRotatef(pitch, 1, 0, 0)
                glRotatef(yaw, 0, 1, 0)
                glCallList(entity.atmosphere)
                glPopMatrix()

        glColor4f(1, 1, 1, 1)
        glDisable(GL_TEXTURE_2D)

        width, height = self.get_size()

        if self.info:
            ortho(width, height)

            for pointer, err in dict(self.overlays).iteritems():
                err = pointer(err)
                if not err:
                    self.overlays.pop(pointer, None)
                else:
                    self.overlays[pointer] = err
            progress_bar(5, 5, 10, 2, min(self.progress / len(self.world.tori), 1) * 100,
                         type=VERTICAL)

            self.label.text = ('%d FPS @ (x=%.2f, y=%.2f, z=%.2f) # %s: %s points\n'
                               'Direction(pitch=%.2f, yaw=%.2f, roll=%.2f)') % (
                self.fps, c.x, c.y, c.z, self.speed, self.score, c.pitch, c.yaw, c.roll)
            self.label.draw()

            glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT)

            glLineWidth(2)

            cx, cy = width / 2, height / 2

            glColor3f(0, 0, 1)
            crosshair(15, (cx, cy))
            glColor4f(0, 1, 0, 1)
            circle(20, 30, (cx, cy))
            glPopAttrib()

            frustrum()
Beispiel #2
0
class PycraftApplet(pyglet.window.Window):             
    def load_textures(self):
        print 'Loading textures...'      
        # Simply loading the texture binds it to the current OpenGL context
        PycraftApplet.ATLAS_ID = load_texture('assets/terrain.png')

    def update(self, dt):
        for symbol in self.keys:
            if self.keys[symbol]:
                x, y, z = self.cam.x, self.cam.y, self.cam.z
                self.cam.keyboard(128, self.speed, self.speed, self.speed, symbol)
                dx, dy, dz = self.cam.x, self.cam.y, self.cam.z

                bdx, bdy, bdz = int(dx / 2), int(dy / 2), int(dz / 2)
                bx, by, bz = int(x / 2), int(y / 2), int(z / 2)
                
                _x, _y, _z = dx, dy, dz

                height = 2
                
                for i in xrange(-height, height):
                    if self.world.get_block((bdx, bdy - height, bdz)):
                        _y = y
                        break
                if self.world.get_block((x, _y, bdz + 1)):
                    _z = z
             
                self.cam.x, self.cam.y, self.cam.z = _x, _y, _z
                chunk = (bdx / 8, bdz / 8)
                if chunk not in self.queued:
                    self.world.generate_chunk(chunk, async=True)
                    self.queued.append(chunk)
                        

    def __init__(self, *args, **kwargs):
        super(PycraftApplet, self).__init__(*args, **kwargs)
        self.queued = []
        self.world = World("overworld", OverworldChunkProvider(random.randint(1, 20))) # That seed.
        self.speed = 2
        self.world_renderer = WorldRenderer(self.world)
        self.keys = {}
        self.label = pyglet.text.Label('', font_name='Consolas', font_size = 13, x = 10, y = self.height - 20, color = (0, 0, 0, 255))
        # Resize is called on window start anyways, so we can start with 0 values.
        self.cam = Camera(0, 0, 60, 0, 0, 0, 0, 0, 0)

        self.exclusive = False
        TPS = 40 # Update 40 times a second
        pyglet.clock.schedule_interval(self.update, 1.0 / TPS)

        glEnable(GL_TEXTURE_2D)

        glClearColor(0.78, 0.86, 1.0, 1)
        glClearDepth(1.0)

        glDepthFunc(GL_LESS)
        glEnable(GL_DEPTH_TEST)
        glShadeModel(GL_SMOOTH)

        glEnable(GL_POLYGON_OFFSET_FILL) # Stops z-buffer fighting

        # Comment if PyCraft lags
        glEnable(GL_FOG)
        glFogfv(GL_FOG_COLOR, (GLfloat * 4)(0.78, 0.86, 1.0, 1))
        glHint(GL_FOG_HINT, GL_NICEST)
        glFogi(GL_FOG_MODE, GL_LINEAR)
        # Specify how close fog should start to the camera
        glFogf(GL_FOG_START, 100.0)
        glFogf(GL_FOG_END, 200.0)
        self.cam.apply_perspective()
        glMatrixMode(GL_MODELVIEW)
        self.load_textures()

    def set_exclusive_mouse(self, exclusive):
        super(PycraftApplet, self).set_exclusive_mouse(exclusive) # Pass to parent
        self.exclusive = exclusive # Toggle flag
 
    def selected_block(self):
        '''Write-only code to determine which block the player is looking at.
            If this stops working, abandon all hope.
            And cry.'''
        c = self.cam
        (dx, dy, dz) = c.direction()

        # Multiply the direction vector by 0..64 and check if a block exists there
        for m in xrange(64):
            # pos is always in world units; / 2 to get array index
            (x, y, z) = int(dx * m + c.x), int(dy * m + c.y), int(dz * m + c.z)
            chunk_pos = (x / 8 / 2, z / 8 / 2) # / by 8 to get chunk, and / 2 to get it in world coords
            '''if self.world.get_block((pos[0] / 2 & ~1, pos[1] / 2 & ~1, pos[2] / 2 & ~1)):
                print "yes."
                return (pos[0] & ~1, pos[1] & ~1, pos[2] & ~1)'''
            
            if chunk_pos in self.world.chunks: # Chunk is generated and exists
                ch_x = x / 2 % 8 # the block chosen in a chunk is the block % 8, as each chunk is 8x8
                ch_z = z / 2 % 8

                if (ch_x, y / 2, ch_z) in self.world.chunks[chunk_pos].data: # Check if our chunk does exist
                    return (ch_x * 2 + chunk_pos[0] * 8 * 2, y & ~1, ch_z * 2 + chunk_pos[1] * 8 * 2)
        return None # Player is not looking at a block, or is too far from a block

    def on_mouse_press(self, x, y, button, modifiers):
        if self.exclusive:
            block = self.selected_block()
            if block:
                chunk = (int(block[0] / 8 / 2), int(block[2] / 8 / 2))
                self.world.chunks[chunk].data.pop((block[0] / 2 % 8, block[1] / 2, block[2] / 2 % 8), None) # Remove the block from the world
                self.world_renderer.mark_chunk_dirty(chunk)
        else:
            self.set_exclusive_mouse(True)

    def on_mouse_motion(self, x, y, dx, dy):
        if self.exclusive: # Only handle camera movement if mouse is grabbed
            self.cam.mouse_move(dx, dy)

    def on_key_press(self, symbol, modifiers):
        if self.exclusive: # Only handle keyboard input if mouse is grabbed
            if symbol == key.ESCAPE:
                sys.exit() # Quit game
            if symbol == key.E:
                self.set_exclusive_mouse(False) # Escape mouse
            elif symbol == key.F:
                self.set_fullscreen(not self.fullscreen)
            elif symbol == key.NUM_ADD:
                self.speed += 3
            elif symbol == key.NUM_SUBTRACT:
                self.speed -= 3
            else:
                self.keys[symbol] = True

    def on_key_release(self, symbol, modifiers):
        self.keys[symbol] = False

    def on_resize(self, width, height):
        height = max(height, 1) # Prevent / by 0
        self.label.y = height - 20
        glViewport(0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        # A field of view of 45
        gluPerspective(45.0, width / float(height), 0.1, 1000.0)
        glMatrixMode(GL_MODELVIEW)

    def on_draw(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        self.cam.translate()
        self.world_renderer.draw_chunks((int(self.cam.x / 8 / 2), int(self.cam.z / 8 / 2)), 3)

        # Draw focused block frame
        block = self.selected_block()
        if block:      
            glPolygonOffset(1, 1)
            # Disable textures; we don't want our focus to be textured!
            glDisable(GL_TEXTURE_2D)
            glPushAttrib(GL_CURRENT_BIT)
            # Black cursor colour
            glColor3f(0, 0, 0)
            # Will have a thickness of 2
            glLineWidth(2)
            # Start drawing in wireframe mode
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
            '''Draw with a quad. The current polygon mode will only draw the edges, so if we
                were to use triangles, then there would be an edge cutting through the the 
                selected block's faces.'''
            glBegin(GL_QUADS)
            # Trick tesselator into drawing without texture by passing null block
            draw_face(None, block[0], block[1], block[2], ALL)
            glEnd()
            # Exit wireframe; start filling
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
            glPopAttrib()
            glEnable(GL_TEXTURE_2D)

        width, height = self.get_size()
        glDisable(GL_DEPTH_TEST)
        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        glOrtho(0, width, 0, height, -1, 1)
        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity(); 

        x, y, z = self.cam.x, self.cam.y, self.cam.z
        self.label.text = '%d FPS\n@ (x=%.2f, y=%.2f, z=%.2f, cx=%s, cy=%s)\n%s chunks loaded.' % (pyglet.clock.get_fps(), x, y, z, int(self.cam.x / 8 / 2), int(self.cam.z / 8 / 2), len(self.world.chunks))
        self.label.draw()
        
        glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT)
        glColor3f(0, 0, 0)
        glLineWidth(3)
        glBegin(GL_LINES)
        CROSSHAIR_SIZE = 15
        glVertex2f(width / 2 - CROSSHAIR_SIZE, height / 2)
        glVertex2f(width / 2 + CROSSHAIR_SIZE, height / 2)
        glVertex2f(width / 2, height / 2 - CROSSHAIR_SIZE)
        glVertex2f(width / 2, height / 2 + CROSSHAIR_SIZE)
        glEnd()
        glPopAttrib()

        glMatrixMode(GL_PROJECTION)
        glPopMatrix()
        glMatrixMode(GL_MODELVIEW)
        glPopMatrix()
        glEnable(GL_DEPTH_TEST)
        glEnable(GL_TEXTURE_2D)