コード例 #1
0
 def draw_lasers(self):
     batch = Batch()
     inner_colors = (0, 200, 255, 0, 200, 255)
     radius = 3 * SpaceWindow.BULLET_RADIUS_PERCENT * self.width
     for bullet in self.model.bullets:
         # self.draw_illumination(self.to_screen_x(bullet[0]), self.to_screen_y(bullet[1]), radius, inner_colors[:3])
         batch.add(2, GL_LINES, None,
                   ('v2f', [self.to_screen_x(bullet[0]),
                            self.to_screen_y(bullet[1]),
                            self.to_screen_x(bullet[0]),
                            self.to_screen_y(bullet[1] + int(self.BULLET_HEIGHT_PERCENT * self.main_height))]),
                   ('c3B', inner_colors))
     radius = SpaceWindow.BULLET_RADIUS_PERCENT * self.width
     purple = [255, 0, 255]
     for x, y in self.model.alien_bullets:
         self.draw_illumination(self.to_screen_x(x), self.to_screen_y(y), 6 * radius, purple)
         circ_pts = [self.to_screen_x(x), self.to_screen_y(y) + radius]
         for theta in np.linspace(0, 2 * math.pi, 8):
             error = random.randint(-1 * radius // 4, radius // 4)
             circ_pts.extend([circ_pts[0] + (radius + error) * math.sin(theta),
                              circ_pts[1] + (radius + error) * math.cos(theta)])
         num_of_vert = (len(circ_pts) // 2)
         colors = [255, 255, 255]
         colors.extend((num_of_vert - 1) * purple)
         graphics.draw(num_of_vert, GL_TRIANGLE_FAN,
                       ('v2f', circ_pts),
                       ('c3B', colors))
     batch.draw()
コード例 #2
0
class Model:
    def get_texture(self, file):
        texture = load_img(file).texture
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        return TextureGroup(texture)

    def __init__(self):
        self.batch = Batch()

        self.top = self.get_texture('./resources/grass_top.png')
        self.side = self.get_texture('./resources/grass_side.png')
        self.bottom = self.get_texture('./resources/dirt.png')

        x, y, z = 0, 0, -1
        X, Y, Z = x + 1, y + 1, z + 1

        texture_coords = ('t2f', (0, 0, 1, 0, 1, 1, 0, 1))

        self.batch.add(4, GL_QUADS, self.side,
                       ('v3f', (x, y, z, X, y, z, X, Y, z, x, Y, z)),
                       texture_coords)

    def draw(self):
        self.batch.draw()
コード例 #3
0
def cif_power_strip(x, y, z, width=1, height=1, depth=1):
	batch = Batch()

	outlet = True
	for i in range(width):
		for j in range(height):
			for k in range(depth):
				if outlet:
					strip_texture = texture.textures['cif_power_strip']
				else:
					strip_texture = texture.textures['cif_power_outlet']

				outlet = not outlet

				tile = cube_tile.CubeTile((x+i, y+j, z+k), textures={
					'top':    texture.textures['cif_power_strip']['master_coordinates'],
					'right':  strip_texture['master_coordinates'],
					'bottom': texture.textures['cif_power_strip']['master_coordinates'],
					'left':   strip_texture['master_coordinates'],
					'front':  strip_texture['master_coordinates'],
					'back':   strip_texture['master_coordinates'],
				})
				vertex_list = tile.get_vertex_list()
				texture_list = tile.get_texture_list()
				vertices = len(vertex_list) / 3

				batch.add(vertices, GL_QUADS, texture.textures['master']['group'], ('v3f/static', vertex_list), ('t2f/static', texture_list))

	return batch
コード例 #4
0
ファイル: shapes.py プロジェクト: msarch/py
class Body(object):
    "A list of primitives. Creates a single batch to draw these primitives."
    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "'items' may contain primitives and/or bodys"
        for item in items:
            if isinstance(item, Body):
                for prim in item.primitives:
                    self.primitives.append(prim)
            else:
                self.primitives.append(item)

    def batch_draw(self):
        if self.batch is None:
            self.batch = Batch()
            for primitive in self.primitives:
                batchVerts = \
                    [primitive.verts[0], primitive.verts[1]] + \
                    primitive.verts + \
                    [primitive.verts[-2], primitive.verts[-1]]
                numverts = len(batchVerts) / 2
                self.batch.add(
                        numverts,
                    primitive.primtype,
                    None, # draw order group to be implemented later
                    ('v2f/static', batchVerts),
                    ('c3B/static', primitive.color * numverts),
                    )
        self.batch.draw()
コード例 #5
0
ファイル: pyglet_batch_test.py プロジェクト: msarch/py
class Shape(object):
    "A list of primitives. Creates a single batch to draw these primitives."

    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "'items' may contain primitives and/or shapes"
        for item in items:
            if isinstance(item, Shape):
                for prim in item.primitives:
                    self.primitives.append(prim)
            else:
                self.primitives.append(item)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for primitive in self.primitives:
                batchVerts = \
                    [primitive.verts[0], primitive.verts[1]] + \
                    primitive.verts + \
                    [primitive.verts[-2], primitive.verts[-1]]
                numverts = len(batchVerts) / 2
                self.batch.add(
                    numverts,
                    primitive.primtype,
                    None,  # group
                    ('v2f/static', batchVerts),
                    ('c3B/static', primitive.color * numverts),
                )
        return self.batch
コード例 #6
0
class Body(object):
    "A list of primitives. Creates a single batch to draw these primitives."

    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "'items' may contain primitives and/or bodys"
        for item in items:
            if isinstance(item, Body):
                for prim in item.primitives:
                    self.primitives.append(prim)
            else:
                self.primitives.append(item)

    def batch_draw(self):
        if self.batch is None:
            self.batch = Batch()
            for primitive in self.primitives:
                batchVerts = \
                    [primitive.verts[0], primitive.verts[1]] + \
                    primitive.verts + \
                    [primitive.verts[-2], primitive.verts[-1]]
                numverts = len(batchVerts) / 2
                self.batch.add(
                    numverts,
                    primitive.primtype,
                    None,  # draw order group to be implemented later
                    ('v2f/static', batchVerts),
                    ('c3B/static', primitive.color * numverts),
                )
        self.batch.draw()
コード例 #7
0
ファイル: shape.py プロジェクト: msarch/py
class Shape(object):
    "A list of primitives"

    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "Add a list containing primitives and shapes"
        for item in items:
            if isinstance(item, Shape):
                for prim in item.primitives:
                    self.primitives.append(prim)
            else:
                self.primitives.append(item)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for primitive in self.primitives:
                flatverts = primitive.get_flat_verts()
                numverts = len(flatverts) / 2
                self.batch.add(numverts, primitive.primtype, None,
                               ('v2f/static', flatverts),
                               ('c3B/static', primitive.color * numverts))
        return self.batch

    def offset(self, dx, dy):
        newprims = []
        for prim in self.primitives:
            newprims.append(prim.offset(dx, dy))
        return Shape(newprims)
コード例 #8
0
 def draw(self, current_view):
     batch_to_draw = Batch()
     for c in self.graphic_components:
         if c.current_view == current_view:
             options = c.get_draw_options()
             batch_to_draw.add(*options)
     batch_to_draw.draw()
コード例 #9
0
class Shape(object):
    "A list of primitives"

    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "Add a list of primitives and shapes"
        for item in items:
            if isinstance(item, Shape):
                self.add_shape(item)
            else:
                self.primitives.append(item)

    def add_shape(self, other):
        "Add the primitives from a given shape"
        for prim in other.primitives:
            self.primitives.append(prim)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for primitive in self.primitives:
                flatverts = primitive.get_flat_verts()
                numverts = len(flatverts) / 2
                self.batch.add(numverts, primitive.primtype, None,
                               ('v2f/static', flatverts),
                               ('c3B/static', primitive.color * numverts))
        return self.batch
コード例 #10
0
def addTriangleUnit(batch: Batch, origin: Vec2, ux, uy, tri: Triangle,
                    colors: List[Vec3]):
    batch.add(3, GL_TRIANGLES, None, ('v2f', [
        tri.p0.x * ux + origin.x * ux, tri.p0.y * uy + origin.y * uy,
        tri.p1.x * ux + origin.x * ux, tri.p1.y * uy + origin.y * uy,
        tri.p2.x * ux + origin.x * ux, tri.p2.y * uy + origin.y * uy
    ]), ('c3f', reduce(operator.concat, map(lambda x: x.to_list(), colors))))
コード例 #11
0
ファイル: shapes.py プロジェクト: msarch/py
class Shape(object):
    '''
    A list of primitives
    '''
    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "Add a list of primitives and shapes"
        for item in items:
            if isinstance(item, Shape):
                self.add_shape(item)
            else:
                self.primitives.append(item)

    def add_shape(self, other):
        "Add the primitives from a given shape"
        for prim in other.primitives:
            self.primitives.append(prim)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for prim in self.primitives:
                flatverts = prim.get_flat_verts()
                numverts = len(flatverts) / 2
                self.batch.add(
                    numverts,
                    prim.primtype,
                    None,
                    ('v2f/static', flatverts),
                    ('c3B/static', prim.color * numverts)
                )
        return self.batch

    def transform(self,M):
        """ applies matrix M to all self primitives
        """
        for prim in self.primitives:
            prim.transform(M)

    def get_aabb(self):
        aabb = namedtuple('AABB',['xmin','xmax','ymin','ymax'])
        _allx=[]
        _ally=[]
        for prim in self.primitives:
            for v in prim.verts:
                _allx.append(v[0])
                _ally.append(v[1])
        minx=min(_allx)
        miny=min(_ally)
        maxx=max(_allx)
        maxy=max(_ally)
        box = (minx,miny,maxx,maxy)
        return (box)
コード例 #12
0
ファイル: body.py プロジェクト: JamesLinus/solarsystem
class OrbitingBody(Body, metaclass=ABCMeta):
    """
    An orbiting body in the solarsystem
    """

    def __init__(self, parent, name, texturename, color, radius, orbit, axial_tilt, sidereal_rotation_period, mass, renderer=OrbitingBodyRenderer()):
        """
        Creates a new body with the given parameters

        :param parent: Parent body in the system
        :type parent: :class:`Body`, None
        :param name: Name of the body
        :type name: str
        :param texturename: Name of the texture
        :type texturename: str
        :param color: Dictionary with r, g and b values
        :type color: dict
        :param radius: Radius of the body
        :type radius: float
        :param orbit: Orbit of the body
        :type orbit: :class:`solarsystem.orbit.Orbit`
        :param axial_tilt: Axial Tilt in degrees
        :type axial_tilt: float
        :param sidereal_rotation_period: Rotation period (siderial) around its own axis
        :type sidereal_rotation_period: float
        """

        super().__init__(parent, name, texturename, color, radius, axial_tilt, sidereal_rotation_period, mass, renderer=renderer)
        self.orbit = orbit
        self.orbit.body = self
        self.orbit_line_batch = Batch()

    def post_init(self):
        self.orbit.post_init()

        # Plot the orbit to a pyglet batch for faster drawing
        orbit_line = []
        for pos in self.orbit.plot(plot_steps):
            orbit_line.append(pos.x)
            orbit_line.append(pos.y)
            orbit_line.append(pos.z)
        self.orbit_line_batch.add(int(len(orbit_line) / 3), GL_LINE_LOOP, None, ('v3f', tuple(orbit_line)))

    def update(self, time):
        """
        Update the body (Calculate current orbit position)

        :param time: Delta Time
        :type time: float
        """

        super().update(time)
        self.xyz = self.orbit.calculate(time)
        if self.parent:
            self.xyz += self.parent.xyz
コード例 #13
0
class Body(object):
    "A list of shapes. Creates a single batch to draw these shapes."
    __metaclass__ = IterRegistry
    _registry = []
    def __init__(self,items=None,anchor=[0,0],angle=0,drawable=True):
        self.shapes = []
        self._registry.append(self)
        self.body=body
        self.anchor=anchor
        self.angle=angle
        self.drawable=drawable
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "'items' may contain shapes and/or bodies"
        for item in items:
            if isinstance(item, Body):
                for shp in item.shapes:
                    self.shapes.append(shp)
            else:
                self.shapes.append(item)

    def batch_draw(self):
        if self.batch is None:
            self.batch = Batch()
            for shape in self.shapes:
                batchVerts = \
                    [shape.verts[0], shape.verts[1]] + \
                    shape.verts + \
                    [shape.verts[-2], shape.verts[-1]]
                numverts = len(batchVerts) / 2
                self.batch.add(
                        numverts,
                    shape.primtype,
                    None, # draw order group to be implemented later
                    ('v2f/static', batchVerts),
                    ('c3B/static', shape.color * numverts),
                    )
        self.batch.draw()



    def paint_all():
        for z in Zulu:
            glPushMatrix()
            glTranslatef(z.anchor[0],z.anchor[1],0)   # Move bac
            glRotatef(z.angle, 0, 0, 1)
            z.body.batch_draw()
            glPopMatrix()
コード例 #14
0
class OrbitalObject(AstronomicalObject):
    """
    An astronomical Object which moves around another
    """

    def __init__(self, parent, name, texture_name, radius, axial_tilt, sidereal_rotation_period, mass, orbit,
                 renderer=AOOrbitingRenderer()):
        """
        Create a new orbiting astronomical Object

        :param parent: The objects parent (i.e. Sun for Earth)
        :param name: Name of the object (Earth, Saturn, Pluto, ...)
        :param texture_name: Name of the texture in the `res` directory
        :param radius: Radius of object
        :param axial_tilt: In astronomy, axial tilt is the angle between a planet's rotational axis at
        its north pole and a line perpendicular to the orbital plane of the planet - given in degrees.
        :param sidereal_rotation_period: The time required (in days) for a body within the solar system to complete
        one revolution with respect to the fixed stars—i.e., as observed from some fixed point outside the system.
        :param mass: Mass of the object in kilograms
        :param orbit: Orbit Class of this body
        """

        super().__init__(parent, name, texture_name, radius, axial_tilt, sidereal_rotation_period, mass,
                         renderer=renderer)
        self.orbit = orbit
        self.orbit.body = self
        self.orbit_line_batch = Batch()

    def config(self):
        """
        Configure the Object
        """

        self.orbit.config()
        orbit_line = []
        for pos in self.orbit.pos(1024):
            orbit_line.append(pos.x)
            orbit_line.append(pos.y)
            orbit_line.append(pos.z)
        self.orbit_line_batch.add(int(len(orbit_line) / 3), GL_LINE_LOOP, None, ('v3f', tuple(orbit_line)))

    def update(self, time):
        """
        Update the time in the solar system and
        position the object on its right coordinates

        :param time: Current solar time
        """

        super().update(time)
        self.xyz = self.orbit.calculate(time)
コード例 #15
0
 def draw_pixel_spills(self):
     pxl_batch = Batch()
     for px in self.pixel_spills:
         px.update(self.tick)
     self.pixel_spills[:] = [val for val in self.pixel_spills if not val.is_vanished]
     num_of = 0
     px_vertices = []
     colours = []
     for px in self.pixel_spills:
         num_of += 4
         px_vertices.extend((px.x, px.y, px.x, px.y + px.size,
                             px.x + px.size, px.y + px.size, px.x + px.size, px.y))
         colours.extend(px.colour)
     pxl_batch.add(num_of, GL_QUADS, None, ('v2f', px_vertices), ('c3B', colours))
     pxl_batch.draw()
コード例 #16
0
 def draw_falling_parts(self):
     pxl_batch = Batch()
     for bl in self.falling_parts:
         bl.update(self.tick)
     self.falling_parts[:] = [val for val in self.falling_parts if not val.is_vanished]
     num_of = 0
     px_vertices = []
     colours = []
     px: FallingBlock
     for px in self.falling_parts:
         num_of += 4
         px_vertices.extend((px.x, px.y, px.x, px.y + px.size,
                             px.x + px.size, px.y + px.size, px.x + px.size, px.y))
         colours.extend(px.colour)
     pxl_batch.add(num_of, GL_QUADS, None, ('v2f', px_vertices), ('c3B', colours))
     pxl_batch.draw()
コード例 #17
0
def floor(floor_texture, x, y, z, width=1, height=1, depth=1):
	batch = Batch()

	for i in range(width):
		for j in range(height):
			for k in range(depth):

				tile = plane_tile.PlaneTile((x+i, y+j, z+k), side='top', textures={
					'top': floor_texture,
				})
				vertex_list = tile.get_vertex_list()
				texture_list = tile.get_texture_list()
				vertices = len(vertex_list) / 3

				batch.add(vertices, GL_QUADS, texture.textures['master']['group'], ('v3f/static', vertex_list), ('t2f/static', texture_list))

	return batch
コード例 #18
0
    def draw_flame(self, x, y, width):
        flame_height = (self.main_height + self.main_width) // 90
        rocket_width = 8 * width // 64
        flame_width_reduct = 0
        offset = 15 * width // 64
        padding = 29 * width // 65

        if random.random() < 0.2:
            self.reset_flame_colours()

        flame_batch = Batch()
        srcs = [[x + offset + i * padding, x + offset + rocket_width + i * padding] for i in range(0, 2)]
        for i, [src_x1, src_x2] in enumerate(srcs):
            flame_batch.add(4, GL_QUADS, None,
                            ('v2f', [src_x1, y, src_x1 + flame_width_reduct, y - flame_height,
                                     src_x2 - flame_width_reduct, y - flame_height, src_x2, y]),
                            ('c4B', self.flame_colours[i]))
        flame_batch.draw()
コード例 #19
0
class CloudRenderer(CloudChunk):
	def __init__(self, X, Generator):
		super(CloudRenderer, self).__init__(X, Generator)

		self.Batch = Batch()


	def GenerateFinshed(self):
		super(CloudRenderer, self).GenerateFinshed()

		self.Batch.add(self.Length, GL_POINTS, None,
			('v2i/static', self.Points),
			('c4f/static', self.Colours)
		)

	def Draw(self, X):
		super(CloudRenderer, self).Draw(X)
		self.Batch.draw()
コード例 #20
0
ファイル: transparent.py プロジェクト: hoonga/2016graphics
class Surface:
    def __init__(self, poses, material=None):
        self.poses = poses
        self.N = (poses[1] - poses[0]).cross(poses[2] - poses[0]).normalize()
        self.batch = Batch()
        norms = list(self.N.arr) * len(poses)
        verts = reduce(lambda x, y: list(x) + list(y), poses)
        self.batch.add(len(poses), GL_TRIANGLE_FAN, None, ('v3f', verts),
                       ('n3f', norms))
        self.material = material

    def draw(self):
        if self.material is not None:
            self.material.set()
        self.batch.draw()

    def d(self, p):
        return self.N.dot(self.poses[0] - p)
コード例 #21
0
ファイル: geometry.py プロジェクト: msarch/py
class Shape(object):
    '''
    A list of primitives
    '''
    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "Add a list of primitives and shapes"
        for item in items:
            if isinstance(item, Shape):
                self.add_shape(item)
            else:
                self.primitives.append(item)

    def add_shape(self, other):
        "Add the primitives from a given shape"
        for prim in other.primitives:
            self.primitives.append(prim)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for prim in self.primitives:
                flatverts = prim.get_flat_verts()
                numverts = len(flatverts) / 2
                self.batch.add(
                    numverts,
                    prim.primtype,
                    None,
                    ('v2f/static', flatverts),
                    ('c3B/static', prim.color * numverts)
                )
        return self.batch

    def transform(self,M):
        """ applies matrix M to all self primitives
        """
        for prim in self.primitives:
            prim.transform(M)
コード例 #22
0
class Map(object):
	LAYERS = {
		'soil': OrderedGroup(0),
		'ground': OrderedGroup(1),
		'bodies': OrderedGroup(2),
		'trees': OrderedGroup(3),
		'berries': OrderedGroup(4)
	}

	def __init__(self, width, height):
		self.width = width
		self.height = height
		self._map = Batch()
		self._create()
		self._add_hero()
		self._add_lost()


	def _create(self):
		for x in range(0, self.width, Soil.size()[0]):
			for y in range(0, self.height, Soil.size()[1]):
				soil = Soil(x, y)
				self.add(soil)
				try:
					soil.grow(self, x, y)
				except NotFertileError as e:
					logger.debug(str(e))

	def add(self, thing):
		thing.vertex_list = self._map.add(
			len(thing.vertices) // 2,
			GL_QUADS,
			self.LAYERS[thing.LAYER],
			('v2i/dynamic', thing.vertices),
			('c4B/static', thing.colors)
		)
		return thing.vertex_list

	def _add_body(self, body_name, kind):
		body = getattr(things, body_name)(*START_POS[kind])
		setattr(self, kind, body)
		self.add(body)
		return body

	@info("Adding {}".format(BODY_HERO))
	def _add_hero(self):
		self._add_body(BODY_HERO, 'hero')

	@info("Hiding {}".format(BODY_LOST))
	def _add_lost(self):
		self._add_body(BODY_LOST, 'lost') # keep a list of every tree to hide him

	def draw(self):
		self._map.draw()
コード例 #23
0
def cif_old_mac(x, y, z, rotate=0):
	batch = Batch()

	bottom_side = texture.textures['old_mac_bottom_side']['master_coordinates']
	top_side = texture.textures['old_mac_top_side']['master_coordinates']
	bottom_front = texture.textures['old_mac_bottom_front']['master_coordinates']
	top_front = texture.textures['old_mac_top_front']['master_coordinates']

	if rotate == 0:
		sides = ['right', 'back', 'front']
	elif rotate == 1:
		sides = ['back', 'left', 'right']
	elif rotate == 2:
		sides = ['left', 'back', 'front']
	elif rotate == 3:
		sides = ['front', 'left', 'right']

	front_x = 1 if rotate == 0 else -1 if rotate == 2 else 0
	front_z = 1 if rotate == 3 else -1 if rotate == 1 else 0
	tiles = [
		# Front side
		plane_tile.PlaneTile((x-front_x, y, z-front_z), side=sides[0], textures={sides[0]: bottom_front}),
		plane_tile.PlaneTile((x-front_x, y+1, z-front_z), side=sides[0], textures={sides[0]: top_front}),
		# Left side
		plane_tile.PlaneTile((x, y, z), side=sides[1], textures={sides[1]: bottom_side}),
		plane_tile.PlaneTile((x, y+1, z), side=sides[1], textures={sides[1]: top_side}),
		# Right side
		plane_tile.PlaneTile((x, y, z), side=sides[2], textures={sides[2]: bottom_side}),
		plane_tile.PlaneTile((x, y+1, z), side=sides[2], textures={sides[2]: top_side}),
		# Top side
		plane_tile.PlaneTile((x, y+1, z), side='top', textures={'top': top_side}),
	]

	for tile in tiles:
		vertex_list = tile.get_vertex_list()
		texture_list = tile.get_texture_list()
		vertices = len(vertex_list) / 3

		batch.add(vertices, GL_QUADS, texture.textures['master']['group'], ('v3f/static', vertex_list), ('t2f/static', texture_list))

	return batch
コード例 #24
0
def cif_red_shelf(x, y, z):
	batch = Batch()

	side = texture.textures['cif_red_shelf_side']['master_coordinates']
	front = texture.textures['cif_red_shelf_front']['master_coordinates']

	tiles = [
		# Left side
		plane_tile.PlaneTile((x, y, z), side='back', textures={'back': side}),
		plane_tile.PlaneTile((x, y+1, z), side='back', textures={'back': side}),
		plane_tile.PlaneTile((x, y+2, z), side='back', textures={'back': side}),
		plane_tile.PlaneTile((x, y+3, z), side='back', textures={'back': side}),
		plane_tile.PlaneTile((x, y+4, z), side='back', textures={'back': side}),
		# Right side
		plane_tile.PlaneTile((x, y, z), side='front', textures={'front': side}),
		plane_tile.PlaneTile((x, y+1, z), side='front', textures={'front': side}),
		plane_tile.PlaneTile((x, y+2, z), side='front', textures={'front': side}),
		plane_tile.PlaneTile((x, y+3, z), side='front', textures={'front': side}),
		plane_tile.PlaneTile((x, y+4, z), side='front', textures={'front': side}),
		# Shelves
		plane_tile.PlaneTile((x, y, z), side='top', textures={'top': side}),
		plane_tile.PlaneTile((x, y+1, z), side='top', textures={'top': side}),
		plane_tile.PlaneTile((x, y+2, z), side='top', textures={'top': side}),
		plane_tile.PlaneTile((x, y+3, z), side='top', textures={'top': side}),
		plane_tile.PlaneTile((x, y+4, z), side='top', textures={'top': side}),
		# Front side
		plane_tile.PlaneTile((x, y, z), side='right', textures={'right': front}),
		plane_tile.PlaneTile((x, y+1, z), side='right', textures={'right': front}),
		plane_tile.PlaneTile((x, y+2, z), side='right', textures={'right': front}),
		plane_tile.PlaneTile((x, y+3, z), side='right', textures={'right': front}),
		plane_tile.PlaneTile((x, y+4, z), side='right', textures={'right': front}),
	]

	for tile in tiles:
		vertex_list = tile.get_vertex_list()
		texture_list = tile.get_texture_list()
		vertices = len(vertex_list) / 3

		batch.add(vertices, GL_QUADS, texture.textures['master']['group'], ('v3f/static', vertex_list), ('t2f/static', texture_list))

	return batch
コード例 #25
0
ファイル: shape.py プロジェクト: msarch/py
class Shape(object):
    "A list of primitives. Creates a single batch to draw these primitives."

    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "'items' may contain primitives and/or shapes"
        for item in items:
            if isinstance(item, Shape):
                for prim in item.primitives:
                    self.primitives.append(prim)
            else:
                self.primitives.append(item)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for primitive in self.primitives:
                batchVerts = \
                    [primitive.verts[0], primitive.verts[1]] + \
                    primitive.verts + \
                    [primitive.verts[-2], primitive.verts[-1]]
                numverts = len(batchVerts) / 2
                self.batch.add(
                    numverts,
                    primitive.primtype,
                    None, # group
                    ('v2f/static', batchVerts),
                    ('c3B/static', primitive.color * numverts),
                )
        return self.batch

    def offset(self, dx, dy):
        newprims = []
        for prim in self.primitives:
            newprims.append(prim.offset(dx, dy))
        return Shape(newprims)
コード例 #26
0
def cif_table(x, y, z, rotate=False):
	batch = Batch()
	table = texture.textures['cif_red_shelf_side']['master_coordinates']
	leg = texture.textures['cif_cabinet_base']['master_coordinates']

	table_size = (3, .5, 6) if rotate else (6, .5, 3)

	leg_size = (.5, 2, .5)
	leg_texture = {
		'top':    leg,
		'right':  leg,
		'bottom': leg,
		'left':   leg,
		'front':  leg,
		'back':   leg,
	}

	top = cube_tile.CubeTile((x, y, z), table_size, textures={
		'top':    table,
		'right':  table,
		'bottom': table,
		'left':   table,
		'front':  table,
		'back':   table,
	})
	leg_x = table_size[0] / 2.0 - leg_size[0]
	leg_z = table_size[2] / 2.0 - leg_size[2]
	front_left_leg = cube_tile.CubeTile((x-leg_x, y-1, z+leg_z), leg_size, textures=leg_texture)
	front_right_leg = cube_tile.CubeTile((x+leg_x, y-1, z+leg_z), leg_size, textures=leg_texture)
	back_left_leg = cube_tile.CubeTile((x-leg_x, y-1, z-leg_z), leg_size, textures=leg_texture)
	back_right_leg = cube_tile.CubeTile((x+leg_x, y-1, z-leg_z), leg_size, textures=leg_texture)

	for tile in [top, front_left_leg, front_right_leg, back_left_leg, back_right_leg]:
		vertex_list = tile.get_vertex_list()
		texture_list = tile.get_texture_list()
		vertices = len(vertex_list) / 3

		batch.add(vertices, GL_QUADS, texture.textures['master']['group'], ('v3f/static', vertex_list), ('t2f/static', texture_list))

	return batch
コード例 #27
0
 def draw_header(self):
     complement = 255 - self.alpha
     header_batch = Batch()
     colors = (0, 0, 0, complement,
               13, 22, 48, complement,
               13, 22, 48, complement,
               0, 0, 0, complement)
     header_batch.add(4, GL_QUADS, None, ('v2f', [0, self.main_height,
                                                  0, self.main_height + self.header_height,
                                                  self.main_width, self.main_height + self.header_height,
                                                  self.main_width, self.main_height]), ('c4B', colors))
     header_batch.add(2, GL_LINES, None, ('v2f', [0, self.main_height,
                                                  self.main_width, self.main_height]),
                      ('c4B', 2 * (255, 255, 255, complement)))
     header_batch.draw()
     self.enemies_lbl = pyglet.text.Label("Enemies Remaining: " + ("" if not self.model else str(self.model.aliens)),
                                          font_name='8Bit Wonder',
                                          font_size=self.main_width // 65,
                                          width=self.main_width, height=self.header_height,
                                          x=self.main_width // 40, y=self.main_height + 0.9 * self.header_height,
                                          anchor_x='left', anchor_y='top',
                                          color=(255, 255, 255, complement))
     self.enemies_lbl.draw()
     self.score_lbl = pyglet.text.Label("Score: " + ("" if not self.model else str(self.model.points)),
                                        font_name='8Bit Wonder',
                                        font_size=self.main_width // 65,
                                        width=self.main_width, height=self.header_height,
                                        x=18 * self.main_width // 40, y=self.main_height + 0.9 * self.header_height,
                                        anchor_x='left', anchor_y='top',
                                        color=(255, 255, 255, complement))
     self.score_lbl.draw()
     self.high_score_lbl = pyglet.text.Label("Highscore: " + ("" if not self.model else str(self.model.highscore)),
                                             font_name='8Bit Wonder',
                                             font_size=self.main_width // 65,
                                             width=self.main_width, height=self.header_height,
                                             x=28 * self.main_width // 40,
                                             y=self.main_height + 0.9 * self.header_height,
                                             anchor_x='left', anchor_y='top',
                                             color=(255, 255, 255, complement))
     self.high_score_lbl.draw()
コード例 #28
0
ファイル: shape.py プロジェクト: msarch/py
class Shape(object):
    "A list of primitives"

    def __init__(self, items=None):
        self.primitives = []
        if items:
            self.add_items(items)
        self.batch = None

    def add_items(self, items):
        "Add a list containing primitives and shapes"
        for item in items:
            if isinstance(item, Shape):
                for prim in item.primitives:
                    self.primitives.append(prim)
            else:
                self.primitives.append(item)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for primitive in self.primitives:
                flatverts = primitive.get_flat_verts()
                numverts = len(flatverts) / 2
                self.batch.add(
                    numverts,
                    primitive.primtype,
                    None,
                    ('v2f/static', flatverts),
                    ('c3B/static', primitive.color * numverts)
                )
        return self.batch

    def offset(self, dx, dy):
        newprims = []
        for prim in self.primitives:
            newprims.append(prim.offset(dx, dy))
        return Shape(newprims)
コード例 #29
0
ファイル: world.py プロジェクト: njgrisafi/pycraft
class World:
    def __init__(self):
        # A Batch is a collection of vertex lists for batched rendering.
        self.batch = Batch()
        # A TextureGroup manages an OpenGL texture.
        self.texture_group = {}
        # A mapping from position to the texture of the block at that position.
        # This defines all the blocks that are currently in the world.
        self.objects = {}
        # Same mapping as `world` but only contains blocks that are shown.
        self.shown = {}
        # Mapping from position to a pyglet `VertextList` for all shown blocks.
        self._shown = {}
        # Which sector the player is currently in.
        self.sector = None
        # Mapping from sector to a list of positions inside that sector.
        self.sectors = {}

        self.shader = None
        self.show_hide_queue = OrderedDict()
        PycraftOpenGL()

        self.init_shader()

    def hit_test(self, position, vector, max_distance=8):
        """Line of sight search from current position. If a block is
        intersected it is returned, along with the block previously in the line
        of sight. If no block is found, return None, None.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position to check visibility from.
        vector : tuple of len 3
            The line of sight vector.
        max_distance : int
            How many blocks away to search for a hit.
        """
        m = 8
        x, y, z = position
        dx, dy, dz = vector
        previous = None
        for _ in range(max_distance * m):
            key = normalize((x, y, z))
            if key != previous and key in self.objects:
                return key, previous
            previous = key
            x, y, z = x + dx / m, y + dy / m, z + dz / m
        return None, None

    def exposed(self, position):
        """Returns False is given `position` is surrounded on all 6 sides by
        blocks, True otherwise.
        """
        x, y, z = position
        for dx, dy, dz in FACES:
            if (x + dx, y + dy, z + dz) not in self.objects:
                return True
        return False

    def add_block(self, position, texture, immediate=True):
        """Add a block with the given `texture` and `position` to the world.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to add.
        texture : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        immediate : bool
            Whether or not to draw the block immediately.
        """
        if position in self.objects:
            self.remove_block(position, immediate)
        self.objects[position] = texture
        self.sectors.setdefault(sectorize(position), []).append(position)
        if immediate:
            if self.exposed(position):
                self.show_block(position)
            self.check_neighbors(position)

    def remove_block(self, position, immediate=True):
        """Remove the block at the given `position`.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to remove.
        immediate : bool
            Whether or not to immediately remove block from canvas.
        """
        del self.objects[position]
        self.sectors[sectorize(position)].remove(position)
        if immediate:
            if position in self.shown:
                self.hide_block(position)
            self.check_neighbors(position)

    def check_neighbors(self, position):
        """Check all blocks surrounding `position` and ensure their visual
        state is current. This means hiding blocks that are not exposed and
        ensuring that all exposed blocks are shown. Usually used after a block
        is added or removed.
        """
        x, y, z = position
        for dx, dy, dz in FACES:
            key = (x + dx, y + dy, z + dz)
            if key not in self.objects:
                continue
            if self.exposed(key):
                if key not in self.shown:
                    self.show_block(key)
            else:
                if key in self.shown:
                    self.hide_block(key)

    def show_block(self, position, immediate=True):
        """Show the block at the given `position`. This method assumes the
        block has already been added with add_block()

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to show.
        immediate : bool
            Whether or not to show the block immediately.
        """
        texture = self.objects[position]
        self.shown[position] = texture
        if immediate:
            self._show_block(position, texture)
        else:
            self.show_hide_queue[position] = True

    def _show_block(self, position, block):
        """Private implementation of the `show_block()` method.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to show.
        texture : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        """
        x, y, z = position
        vertex_data = cube_vertices(x, y, z, 0.5)
        shade_data = cube_shade(1, 1, 1, 1)
        texture_data = block.texture
        if block.identifier not in self.texture_group:
            self.texture_group[block.identifier] = TextureGroup(image.load(block.texture_path).get_texture())
        self._shown[position] = self.batch.add(
            24, GL_QUADS, self.texture_group[block.identifier],
            ('v3f/static', vertex_data),
            ('c3f/static', shade_data),
            ('t2f/static', texture_data))

    def hide_block(self, position, immediate=True):
        """Hide the block at the given `position`. Hiding does not remove the
        block from the world.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to hide.
        immediate : bool
            Whether or not to immediately remove the block from the canvas.
        """
        self.shown.pop(position)
        if immediate:
            self._hide_block(position)
        else:
            self.show_hide_queue[position] = False

    def _hide_block(self, position):
        """Private implementation of the 'hide_block()` method."""
        self._shown.pop(position).delete()

    def show_sector(self, sector):
        """Ensure all blocks in the given sector that should be shown are drawn
        to the canvas.
        """
        positions = self.sectors.get(sector, [])
        if positions:
            for position in positions:
                if position not in self.shown and self.exposed(position):
                    self.show_block(position, False)
        else:
            self.generate_sector(sector)
            self.show_sector(sector)

    def generate_sector(self, sector):
        """Generate blocks within sector using simplex_noise2
        """
        for column in reverse_sectorize(sector):
            x, z = column
            y_max = int((simplex_noise2(x / 30, z / 30) + 1) * 3)
            for y_lvl in range(0 - 2, y_max):
                self.add_block((x, y_lvl, z), Sand(), immediate=False)
            else:
                self.add_block((x, y_lvl, z), Grass(), immediate=False)
            # add the safety stone floor.
            # don't want anyone falling into the ether.
            self.add_block((x, 0 - 3, z), Stone(), immediate=False)

    def hide_sector(self, sector):
        """Ensure all blocks in the given sector that should be hidden are
        removed from the canvas.
        """
        for position in self.sectors.get(sector, []):
            if position in self.shown:
                self.hide_block(position, False)

    def change_sectors(self, before, after):
        """Move from sector `before` to sector `after`. A sector is a
        contiguous x, y sub-region of world. Sectors are used to speed up
        world rendering.
        """
        before_set = set()
        after_set = set()
        pad = 4
        for dx in range(-pad, pad + 1):
            for dy in [0]:  # range(-pad, pad + 1):
                for dz in range(-pad, pad + 1):
                    if dx ** 2 + dy ** 2 + dz ** 2 > (pad + 1) ** 2:
                        continue
                    if before:
                        x, y, z = before
                        before_set.add((x + dx, y + dy, z + dz))
                    if after:
                        x, y, z = after
                        after_set.add((x + dx, y + dy, z + dz))
        show = after_set - before_set
        hide = before_set - after_set
        for sector in show:
            self.show_sector(sector)
        for sector in hide:
            self.hide_sector(sector)

    def _dequeue(self):
        """Pop the top function from the internal queue and call it."""
        position, show = self.show_hide_queue.popitem(last=False)
        shown = position in self._shown
        if show and not shown:
            self._show_block(position, self.objects[position])
        elif shown and not show:
            self._hide_block(position)

    def process_queue(self, ticks_per_sec):
        """Process the entire queue while taking periodic breaks. This allows
        the game loop to run smoothly. The queue contains calls to
        _show_block() and _hide_block() so this method should be called if
        add_block() or remove_block() was called with immediate=False
        """
        start = time.clock()
        while self.show_hide_queue and time.clock() - start < 1.0 / ticks_per_sec:
            self._dequeue()

    def process_entire_queue(self):
        """Process the entire queue with no breaks."""
        while self.show_hide_queue:
            self._dequeue()

    def init_shader(self):
        vertex_shader = ""
        fragment_shader = ""

        with open("pycraft/shaders/world.vert") as handle:
            vertex_shader = handle.read()

        with open("pycraft/shaders/world.frag") as handle:
            fragment_shader = handle.read()

        self.shader = Shader([vertex_shader], [fragment_shader])

    def start_shader(self):
        self.shader.bind()

    def stop_shader(self):
        self.shader.unbind()
コード例 #30
0
ファイル: shapes.py プロジェクト: msarch/py
class Shape(object):
    '''
    Shapes have Vertices, a single color, and a single OpenGL primitive
    '''
    _instances = set()

    def __init__(self, **kwargs):
        for key in kwargs:
            setattr(self,key,kwargs[key])
        if not hasattr(self,'peg'):  # peg must be tuple (x, y, a)
            self.peg = DOCKED
        if not hasattr(self,'vel'):  # peg must be tuple (vx, vy, av)
            self.vel = IDLE
        self.build()
        self.flat_verts = None
        self.batch=None
        self._instances.add(weakref.ref(self))
        print "::"
        print ":: new shape ::::::::::::::::::::::::::::::::::::::::::::::::::"
        print "::"
        dumpObj(self)

    @classmethod
    def get_instances(cls):
        dead = set()
        for ref in cls._instances:
            obj = ref()
            if obj is not None:
                yield obj
            else:
                dead.add(ref)
        cls._instances -= dead

    def offset(self, dx, dy):
        newverts = [(v[0] + dx, v[1] + dy) for v in self.verts]
        self.verts=newverts

    def copy(self):
        ssh=Shape(verts=self.verts, color=self.color,\
                primtype=self.primtype, peg=self.peg, vel=self.vel)
        return(ssh)

    def center(self):
        pass

    def transform(self,M):
        '''
        applies matrix M transformation to all self vertexes
        '''
        newverts = [ (M[0]*v[0]+M[1]*v[1]+M[2],
                M[3]*v[0]+M[4]*v[1]+M[5]) for v in self.verts]
        self.verts=newverts


    def get_aabb(self):
        _allx=[]
        _ally=[]
        for v in self.verts:
            _allx.append(v[0])
            _ally.append(v[1])
        lox=min(_allx)
        loy=min(_ally)
        hix=max(_allx)
        hiy=max(_ally)
        return (AABB(lox,loy,hix,hiy))

    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            flatverts = self.get_flat_verts()
            numverts = len(flatverts) / 2
            self.batch.add(
                numverts,
                self.primtype,
                None,
                ('v2f/static', flatverts),
                ('c4B/static', self.color * numverts)
                )
        return self.batch

    def paint(self):
        batch = self.get_batch()
        glPushMatrix()
        glTranslatef(self.peg.x, self.peg.y, 0)
        glRotatef(self.peg.angle, 0, 0, 1)
        batch.draw()
        glPopMatrix()

    def build(self):
        pass
コード例 #31
0
ファイル: world.py プロジェクト: Hispar/pycraft
class World:
    def __init__(self):
        # A Batch is a collection of vertex lists for batched rendering.
        self.batch = Batch()
        # A TextureGroup manages an OpenGL texture.
        self.texture_group = {}
        # Mapping from position to a pyglet `VertextList` for all shown blocks.
        self._shown = {}
        self.show_hide_queue = OrderedDict()
        # Which sector the player is currently in.
        self.sector = None

        # Mapping from sector to a list of positions inside that sector.
        self.sectors = {}
        # Same mapping as `world` but only contains blocks that are shown.
        self.shown = {}

        self.shader = None
        PycraftOpenGL()

        self.init_shader()

        # A mapping from position to the texture of the block at that position.
        # This defines all the blocks that are currently in the world.
        self.area = Area()

    def add_block(self, coords, block, immediate=True):
        """Add a block with the given `texture` and `position` to the world.

        Parameters
        ----------
        coords : tuple of len 3
            The (x, y, z) position of the block to add.
        block : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        immediate : bool
            Whether or not to draw the block immediately.
        """
        self.area.add_block(coords, block)
        # self.sectors.setdefault(sectorize(position), []).append(position)
        if immediate:
            if self.area.exposed(coords):
                self.show_block(coords, block, immediate)
                neighbors = self.area.get_neighbors(coords)
                for element in neighbors['hide']:
                    self.hide_block(element['coords'])
                for element in neighbors['show']:
                    self.show_block(element['coords'], element['block'])

    def remove_block(self, coords):
        """
        Remove a block from the world. And shows the neighbors
        :param coords:
        :return:
        """
        self.area.remove_block(coords)
        self.hide_block(coords)
        neighbors = self.area.get_neighbors(coords)
        for element in neighbors['hide']:
            self.hide_block(element['coords'])
        for element in neighbors['show']:
            self.show_block(element['coords'], element['block'])

    def show_block(self, coords, block, immediate=False):
        """Ensure all blocks that should be shown are drawn
        to the canvas.

        Parameters
        ----------
        coords : tuple of len 3
            The (x, y, z) position of the block to show.
        block : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        immediate : bool
            Whether or not to immediately remove the block from the canvas.
        """

        if coords in self.shown:
            return
        self.shown[coords] = block
        if not immediate:
            self.show_hide_queue[coords] = True
            return
        self._show_block(coords, block)

    def _show_block(self, coords, block):
        """Private implementation of the `show_block()` method.

        Parameters
        ----------
        coords : tuple of len 3
            The (x, y, z) position of the block to show.
        block : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        """
        x, y, z = coords
        vertex_data = cube_vertices(x, y, z, 0.5)
        shade_data = cube_shade(1, 1, 1, 1)
        texture_data = block.texture
        if block.identifier not in self.texture_group:
            self.texture_group[block.identifier] = TextureGroup(image.load(block.texture_path).get_texture())
        self._shown[coords] = self.batch.add(
            24, GL_QUADS, self.texture_group[block.identifier],
            ('v3f/static', vertex_data),
            ('c3f/static', shade_data),
            ('t2f/static', texture_data))

    def hide_block(self, coords, immediate=True):
        """Ensure all blocks that should be hidden are hide
        from the canvas."""
        if coords not in self.shown:
            return

        self.shown.pop(coords)
        if not immediate:
            self.show_hide_queue[coords] = False

        self._hide_block(coords)

    def _hide_block(self, coords):
        """Private implementation of the 'hide_block()` method."""
        if coords not in self._shown:
            return
        self._shown.pop(coords).delete()

    def _dequeue(self):
        """Pop the top function from the internal queue and call it."""
        coords, show = self.show_hide_queue.popitem(last=False)
        shown = coords in self._shown
        if show and not shown:
            self._show_block(coords, self.area.get_block(coords))
        elif shown and not show:
            self._hide_block(coords)

    def process_queue(self, ticks_per_sec):
        """Process the entire queue while taking periodic breaks. This allows
        the game loop to run smoothly. The queue contains calls to
        _show_block() and _hide_block() so this method should be called if
        add_block() or remove_block() was called with immediate=False
        """
        start = time.clock()
        while self.show_hide_queue and time.clock() - start < 1.0 / ticks_per_sec:
            self._dequeue()

    def process_entire_queue(self):
        """Process the entire queue with no breaks."""
        while self.show_hide_queue:
            self._dequeue()

    def init_shader(self):
        vertex_shader = ""
        fragment_shader = ""

        with open("pycraft/shaders/world.vert") as handle:
            vertex_shader = handle.read()

        with open("pycraft/shaders/world.frag") as handle:
            fragment_shader = handle.read()

        self.shader = Shader([vertex_shader], [fragment_shader])

    def start_shader(self):
        self.shader.bind()

    def stop_shader(self):
        self.shader.unbind()

    def add_sector(self, sector, coords):
        self.sector = coords
        self.sectors[coords] = sector
        # self.sectors.setdefault(coords, []).append(sector)

    def show_sector(self, coords, immediate=True):
        """Ensure all blocks in the given sector that should be shown are drawn
        to the canvas.
        """
        sector = self.sectors.get(coords)
        if sector:
            for position in sector.blocks:
                if position not in self.shown and self.area.exposed(position):
                    self.show_block(position, immediate)
        else:
            sector = Sector(coords, self.area)
            self.add_sector(sector, coords)
            self.show_sector(coords)

    def hide_sector(self, coords):
        """Ensure all blocks in the given sector that should be hidden are
        removed from the canvas.
        """
        sector = self.sectors.get(coords)
        for position in sector.blocks:
            if position in self.shown:
                self.hide_block(position, False)

    def change_sectors(self, before, after):
        """Move from sector `before` to sector `after`. A sector is a
        contiguous x, y sub-region of world. Sectors are used to speed up
        world rendering.
        """
        before_set = set()
        after_set = set()
        pad = 4
        if not before:
            self.initial_sector(after)
        for dx in range(-pad, pad + 1):
            for dy in [0]:  # range(-pad, pad + 1):
                for dz in range(-pad, pad + 1):
                    if dx ** 2 + dy ** 2 + dz ** 2 > (pad + 1) ** 2:
                        continue
                    if before:
                        x, y, z = before
                        before_set.add((x + dx, y + dy, z + dz))
                    if after:
                        x, y, z = after
                        after_set.add((x + dx, y + dy, z + dz))
        show = after_set - before_set
        hide = before_set - after_set
        for coords in hide:
            self.hide_sector(coords)
        for coords in show:
            self.show_sector(coords)

    def initial_sector(self, coords):
        """
        Creates initial sectors in spiral, to speed up rendering in front of the player
        :param coords:
        :return:
        """
        x, y = 0, 0
        dx, dy = 0, -1
        X = coords[0] + 4
        Y = coords[2] + 4
        for i in range(max(X, Y) ** 2):
            if (-X / 2 < x <= X / 2) and (-Y / 2 < y <= Y / 2):
                self.show_sector((x, coords[1], y))
            if x == y or (x < 0 and x == -y) or (x > 0 and x == 1 - y):
                dx, dy = -dy, dx  # Corner change direction
            x, y = x + dx, y + dy
コード例 #32
0
ファイル: world.py プロジェクト: MartijnBraam/pycraft
class World:

    def __init__(self):
        # A Batch is a collection of vertex lists for batched rendering.
        self.batch = Batch()
        # A TextureGroup manages an OpenGL texture.
        self.group = TextureGroup(image.load(TEXTURE_PATH).get_texture())
        # A mapping from position to the texture of the block at that position.
        # This defines all the blocks that are currently in the world.
        self.objects = {}
        # Same mapping as `world` but only contains blocks that are shown.
        self.shown = {}
        # Mapping from position to a pyglet `VertextList` for all shown blocks.
        self._shown = {}
        # Which sector the player is currently in.
        self.sector = None
        # Mapping from sector to a list of positions inside that sector.
        self.sectors = {}

        self.shader = None
        # Simple function queue implementation. The queue is populated with
        # _show_block() and _hide_block() calls
        self.queue = deque()
        self.init_gl()
        self._initialize()
        self.init_shader()

    def init_gl(self):
        """Basic OpenGL configuration."""
        # Set the color of "clear", i.e. the sky, in rgba.
        glClearColor(0.5, 0.69, 1.0, 1)
        # Enable culling (not rendering) of back-facing facets -- facets that aren't
        # visible to you.
        glEnable(GL_CULL_FACE)
        # Set the texture minification/magnification function to GL_NEAREST (nearest
        # in Manhattan distance) to the specified texture coordinates. GL_NEAREST
        # "is generally faster than GL_LINEAR, but it can produce textured images
        # with sharper edges because the transition between texture elements is not
        # as smooth."
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        self.init_gl_fog()

    def init_gl_fog(self):
        """Configure the OpenGL fog properties."""
        # Enable fog. Fog "blends a fog color with each rasterized pixel fragment's
        # post-texturing color."
        glEnable(GL_FOG)
        # Set the fog color.
        glFogfv(GL_FOG_COLOR, (GLfloat * 4)(0.5, 0.69, 1.0, 1))
        # Say we have no preference between rendering speed and quality.
        glHint(GL_FOG_HINT, GL_DONT_CARE)
        # Specify the equation used to compute the blending factor.
        glFogi(GL_FOG_MODE, GL_LINEAR)
        # How close and far away fog starts and ends. The closer the start and end,
        # the denser the fog in the fog range.
        glFogf(GL_FOG_START, 20.0)
        glFogf(GL_FOG_END, 60.0)

    def _initialize(self):
        """Initialize the world by placing all the blocks."""
        n = 80  # 1/2 width and height of world
        s = 1  # step size
        y = 0  # initial y height
        for x in range(-n, n + 1, s):
            for z in range(-n, n + 1, s):
                # create a layer stone an grass everywhere.
                self.add_block((x, y - 3, z), stone, immediate=False)
                if x in (-n, n) or z in (-n, n):
                    # create outer walls.
                    for dy in range(-2, 3):
                        self.add_block((x, y + dy, z), stone, immediate=False)
                else:
                    y_max = int((simplex_noise2(x/30, z/30) + 1) * 3)
                    for y_lvl in range(y - 2, y_max):
                        if y_lvl < (y_max-1):
                            block = brick
                        else:
                            block = grass
                        self.add_block((x, y_lvl, z), block, immediate=False)

    def hit_test(self, position, vector, max_distance=8):
        """Line of sight search from current position. If a block is
        intersected it is returned, along with the block previously in the line
        of sight. If no block is found, return None, None.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position to check visibility from.
        vector : tuple of len 3
            The line of sight vector.
        max_distance : int
            How many blocks away to search for a hit.
        """
        m = 8
        x, y, z = position
        dx, dy, dz = vector
        previous = None
        for _ in range(max_distance * m):
            key = normalize((x, y, z))
            if key != previous and key in self.objects:
                return key, previous
            previous = key
            x, y, z = x + dx / m, y + dy / m, z + dz / m
        return None, None

    def exposed(self, position):
        """Returns False is given `position` is surrounded on all 6 sides by
        blocks, True otherwise.
        """
        x, y, z = position
        for dx, dy, dz in FACES:
            if (x + dx, y + dy, z + dz) not in self.objects:
                return True
        return False

    def add_block(self, position, texture, immediate=True):
        """Add a block with the given `texture` and `position` to the world.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to add.
        texture : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        immediate : bool
            Whether or not to draw the block immediately.
        """
        if position in self.objects:
            self.remove_block(position, immediate)
        self.objects[position] = texture
        self.sectors.setdefault(sectorize(position), []).append(position)
        if immediate:
            if self.exposed(position):
                self.show_block(position)
            self.check_neighbors(position)

    def remove_block(self, position, immediate=True):
        """Remove the block at the given `position`.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to remove.
        immediate : bool
            Whether or not to immediately remove block from canvas.
        """
        del self.objects[position]
        self.sectors[sectorize(position)].remove(position)
        if immediate:
            if position in self.shown:
                self.hide_block(position)
            self.check_neighbors(position)

    def check_neighbors(self, position):
        """Check all blocks surrounding `position` and ensure their visual
        state is current. This means hiding blocks that are not exposed and
        ensuring that all exposed blocks are shown. Usually used after a block
        is added or removed.
        """
        x, y, z = position
        for dx, dy, dz in FACES:
            key = (x + dx, y + dy, z + dz)
            if key not in self.objects:
                continue
            if self.exposed(key):
                if key not in self.shown:
                    self.show_block(key)
            else:
                if key in self.shown:
                    self.hide_block(key)

    def show_block(self, position, immediate=True):
        """Show the block at the given `position`. This method assumes the
        block has already been added with add_block()

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to show.
        immediate : bool
            Whether or not to show the block immediately.
        """
        texture = self.objects[position]
        self.shown[position] = texture
        if immediate:
            self._show_block(position, texture)
        else:
            self._enqueue(self._show_block, position, texture)

    def _show_block(self, position, block):
        """Private implementation of the `show_block()` method.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to show.
        texture : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        """
        x, y, z = position
        vertex_data = cube_vertices(x, y, z, 0.5)
        shade_data = cube_shade(1, 1, 1, 1)
        texture_data = block.texture
        self._shown[position] = self.batch.add(
            24, GL_QUADS, self.group,
            ('v3f/static', vertex_data),
            ('c3f/static', shade_data),
            ('t2f/static', texture_data))

    def hide_block(self, position, immediate=True):
        """Hide the block at the given `position`. Hiding does not remove the
        block from the world.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to hide.
        immediate : bool
            Whether or not to immediately remove the block from the canvas.
        """
        self.shown.pop(position)
        if immediate:
            self._hide_block(position)
        else:
            self._enqueue(self._hide_block, position)

    def _hide_block(self, position):
        """Private implementation of the 'hide_block()` method."""
        self._shown.pop(position).delete()

    def show_sector(self, sector):
        """Ensure all blocks in the given sector that should be shown are drawn
        to the canvas.
        """
        for position in self.sectors.get(sector, []):
            if position not in self.shown and self.exposed(position):
                self.show_block(position, False)

    def hide_sector(self, sector):
        """Ensure all blocks in the given sector that should be hidden are
        removed from the canvas.
        """
        for position in self.sectors.get(sector, []):
            if position in self.shown:
                self.hide_block(position, False)

    def change_sectors(self, before, after):
        """Move from sector `before` to sector `after`. A sector is a
        contiguous x, y sub-region of world. Sectors are used to speed up
        world rendering.
        """
        before_set = set()
        after_set = set()
        pad = 4
        for dx in range(-pad, pad + 1):
            for dy in [0]:  # range(-pad, pad + 1):
                for dz in range(-pad, pad + 1):
                    if dx ** 2 + dy ** 2 + dz ** 2 > (pad + 1) ** 2:
                        continue
                    if before:
                        x, y, z = before
                        before_set.add((x + dx, y + dy, z + dz))
                    if after:
                        x, y, z = after
                        after_set.add((x + dx, y + dy, z + dz))
        show = after_set - before_set
        hide = before_set - after_set
        for sector in show:
            self.show_sector(sector)
        for sector in hide:
            self.hide_sector(sector)

    def _enqueue(self, func, *args):
        """Add `func` to the internal queue."""
        self.queue.append((func, args))

    def _dequeue(self):
        """Pop the top function from the internal queue and call it."""
        func, args = self.queue.popleft()
        func(*args)

    def process_queue(self, ticks_per_sec):
        """Process the entire queue while taking periodic breaks. This allows
        the game loop to run smoothly. The queue contains calls to
        _show_block() and _hide_block() so this method should be called if
        add_block() or remove_block() was called with immediate=False
        """
        start = time.clock()
        while self.queue and time.clock() - start < 1.0 / ticks_per_sec:
            self._dequeue()

    def process_entire_queue(self):
        """Process the entire queue with no breaks."""
        while self.queue:
            self._dequeue()

    def init_shader(self):
        vertex_shader = ""
        fragment_shader = ""

        with open("pycraft/shaders/world.vert") as handle:
            vertex_shader = handle.read()

        with open("pycraft/shaders/world.frag") as handle:
            fragment_shader = handle.read()

        self.shader = Shader([vertex_shader], [fragment_shader])

    def start_shader(self):
        self.shader.bind()

    def stop_shader(self):
        self.shader.unbind()
コード例 #33
0
class UIElement:

    width = 100
    height = 100
    line_width = 2

    def __init__(self, x, y, window_height, batch=None):
        self.x = x
        self.y = y
        self.batch = Batch() if batch is None else batch
        self.click_regions = {}
        self.click_handlers = {}
        self.ui_elements = []
        self.box_vx = []
        self.box_modes = []
        self.window_height = window_height
        self.groupNumber = 100
        if len(self.box_vx) == 0:
            self.init_box()

    def init_box(self):
        w = self.width
        h = self.height
        pos = self.x, self.y

        bgvx = fix_origin((
            pos[0], pos[1],
            pos[0], pos[1] + h,
            pos[0] + w, pos[1] + h,
            pos[0] + w, pos[1]
            ), self.window_height)
        bgvx2 = (
            bgvx[0] + 2, bgvx[1] - 2,
            bgvx[2] + 2, bgvx[3] + 2,
            bgvx[4] - 2, bgvx[5] + 2,
            bgvx[6] - 2, bgvx[7] - 2
            )
        self.box_vx.append(self.batch.add(4,
            GL_QUADS,
            OrderedGroup(self.groupNumber),
            ('v2i', bgvx),
            ('c3B', (0, 0, 0) * 4)
            ))

        self.box_vx.append(self.batch.add(4,
            GL_QUADS,
            OrderedGroup(self.groupNumber),
            ('v2i', bgvx2),
            ('c3B', (255, 255, 255) * 4)
            ))

    def handle_region(self, name, handler, x, y, w, h):
        self.click_regions[name] = (x, y, w, h)
        self.click_handlers[name] = handler

    def hover(self, pos):
        return True

    def in_region(self, x, y, rx, ry, rw, rh):
        return x >= rx and x <= rx + rw and \
            y >= ry and y <= ry + rh

    def check_mouse(self, pos, buttons):
        something = False
        if len(buttons) == 0:
            # nothing clicked, hover
            if self.in_region(*pos, self.x, self.y, self.width, self.height):
                something = self.hover(pos)
        else:
            for region in self.click_regions:
                r = self.click_regions[region]
                args = list(pos)
                args.extend(r)
                if self.in_region(*args):
                    self.click_handlers[region](region, *pos, buttons)
                    something = True
        for el in self.ui_elements:
            something = el.check_mouse(pos, buttons) or something
        return something
コード例 #34
0
ファイル: shapes.py プロジェクト: msarch/py
class Shape(object):
    """
    Stores a list of vertices, a single color, and a primitive type
    Intended to be rendered as a single OpenGL primitive
    """

    def __init__(self, name, **kwargs):
        global lmnts
        if name in lmnts:
            raise ValueError('duplicate shape name', name)
            exit(1)
        self.name=name
        lmnts[self.name] = self
        for i in kwargs:
            setattr(self,i,kwargs[i])
        self.build()
        self.aabb = self.get_aabb()
        self.flat_verts = None
        self.batch = None

    def offset(self, vx, vy):
        newverts = [(v[0] + vx, v[1] + vy) for v in self.verts]
        self.verts=newverts

    def transform(self,M):
        """ applies matrix M transformation to all self vertexes
        """
        newverts = [ (M[0]*v[0]+M[1]*v[1]+M[2],
                M[3]*v[0]+M[4]*v[1]+M[5]) for v in self.verts]
        return Shape(newverts, self.color, primtype=self.primtype)              #TODO replace shape verts only

    def get_aabb(self):
        _allx=[]
        _ally=[]
        for v in self.verts:
            _allx.append(v[0])
            _ally.append(v[1])
        lox=min(_allx)
        loy=min(_ally)
        hix=max(_allx)
        hiy=max(_ally)
        return (AABB(lox,loy,hix,hiy))

    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            flatverts = self.get_flat_verts()
            numverts = len(flatverts) / 2
            self.batch.add(
                numverts,
                self.primtype,
                None,
                ('v2f/static', flatverts),
                ('c4B/static', self.color * numverts)
                )
        return self.batch

    def paint(self, peg):
        print 'painting', self, '@', peg
        batch = self.get_batch()
        glPushMatrix()
        glTranslatef(peg.x, peg.y, 0)
        glRotatef(peg.angle, 0, 0, 1)
        batch.draw()
        glPopMatrix()
コード例 #35
0
def initialise():
    """Initialises the cube render objects.
    """
    global batch
    batch = Batch()

    batch.add(
        24,
        GL_QUADS,
        None,
        (
            "v3f",
            (
                1.0,
                1.0,
                -1.0,
                -1.0,
                1.0,
                -1.0,
                -1.0,
                1.0,
                1.0,
                1.0,
                1.0,
                1.0,
                1.0,
                -1.0,
                1.0,
                -1.0,
                -1.0,
                1.0,
                -1.0,
                -1.0,
                -1.0,
                1.0,
                -1.0,
                -1.0,
                1.0,
                1.0,
                1.0,
                -1.0,
                1.0,
                1.0,
                -1.0,
                -1.0,
                1.0,
                1.0,
                -1.0,
                1.0,
                1.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
                1.0,
                -1.0,
                1.0,
                1.0,
                -1.0,
                -1.0,
                1.0,
                1.0,
                -1.0,
                1.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
                -1.0,
                1.0,
                1.0,
                1.0,
                -1.0,
                1.0,
                1.0,
                1.0,
                1.0,
                -1.0,
                1.0,
                1.0,
                -1.0,
                -1.0,
            ),
        ),
        (
            "c3f",
            (
                # green
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                # orange
                1.0,
                0.5,
                0.0,
                1.0,
                0.5,
                0.0,
                1.0,
                0.5,
                0.0,
                1.0,
                0.5,
                0.0,
                # blue
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                # violet
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                # yellow
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                # red
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
            ),
        ),
    )
コード例 #36
0
 def draw_stars(self):
     star_batch = Batch()
     for i in self.star_pts:
         star_batch.add(4, GL_QUADS, None, ('v2f', i))
     star_batch.draw()
コード例 #37
0
class World:
    def __init__(self):
        # A Batch is a collection of vertex lists for batched rendering.
        self.batch = Batch()
        # A TextureGroup manages an OpenGL texture.
        self.texture_group = {}
        # Mapping from position to a pyglet `VertextList` for all shown blocks.
        self._shown = {}
        self.show_hide_queue = OrderedDict()
        # Which sector the player is currently in.
        self.sector = None

        # Mapping from sector to a list of positions inside that sector.
        self.sectors = {}
        # Same mapping as `world` but only contains blocks that are shown.
        self.shown = {}

        self.shader = None
        PycraftOpenGL()

        self.init_shader()

        # A mapping from position to the texture of the block at that position.
        # This defines all the blocks that are currently in the world.
        self.area = Area()

    def add_block(self, coords, block, immediate=True):
        """Add a block with the given `texture` and `position` to the world.

        Parameters
        ----------
        coords : tuple of len 3
            The (x, y, z) position of the block to add.
        block : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        immediate : bool
            Whether or not to draw the block immediately.
        """
        self.area.add_block(coords, block)
        # self.sectors.setdefault(sectorize(position), []).append(position)
        if immediate:
            if self.area.exposed(coords):
                self.show_block(coords, block, immediate)
                neighbors = self.area.get_neighbors(coords)
                for element in neighbors['hide']:
                    self.hide_block(element['coords'])
                for element in neighbors['show']:
                    self.show_block(element['coords'], element['block'])

    def remove_block(self, coords):
        """
        Remove a block from the world. And shows the neighbors
        :param coords:
        :return:
        """
        self.area.remove_block(coords)
        self.hide_block(coords)
        neighbors = self.area.get_neighbors(coords)
        for element in neighbors['hide']:
            self.hide_block(element['coords'])
        for element in neighbors['show']:
            self.show_block(element['coords'], element['block'])

    def show_block(self, coords, block, immediate=False):
        """Ensure all blocks that should be shown are drawn
        to the canvas.

        Parameters
        ----------
        coords : tuple of len 3
            The (x, y, z) position of the block to show.
        block : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        immediate : bool
            Whether or not to immediately remove the block from the canvas.
        """

        if coords in self.shown:
            return
        self.shown[coords] = block
        if not immediate:
            self.show_hide_queue[coords] = True
            return
        self._show_block(coords, block)

    def _show_block(self, coords, block):
        """Private implementation of the `show_block()` method.

        Parameters
        ----------
        coords : tuple of len 3
            The (x, y, z) position of the block to show.
        block : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        """
        x, y, z = coords
        vertex_data = cube_vertices(x, y, z, 0.5)
        shade_data = cube_shade(1, 1, 1, 1)
        texture_data = block.texture
        if block.identifier not in self.texture_group:
            self.texture_group[block.identifier] = TextureGroup(
                image.load(block.texture_path).get_texture())
        self._shown[coords] = self.batch.add(
            24, GL_QUADS, self.texture_group[block.identifier],
            ('v3f/static', vertex_data), ('c3f/static', shade_data),
            ('t2f/static', texture_data))

    def hide_block(self, coords, immediate=True):
        """Ensure all blocks that should be hidden are hide
        from the canvas."""
        if coords not in self.shown:
            return

        self.shown.pop(coords)
        if not immediate:
            self.show_hide_queue[coords] = False

        self._hide_block(coords)

    def _hide_block(self, coords):
        """Private implementation of the 'hide_block()` method."""
        if coords not in self._shown:
            return
        self._shown.pop(coords).delete()

    def _dequeue(self):
        """Pop the top function from the internal queue and call it."""
        coords, show = self.show_hide_queue.popitem(last=False)
        shown = coords in self._shown
        if show and not shown:
            self._show_block(coords, self.area.get_block(coords))
        elif shown and not show:
            self._hide_block(coords)

    def process_queue(self, ticks_per_sec):
        """Process the entire queue while taking periodic breaks. This allows
        the game loop to run smoothly. The queue contains calls to
        _show_block() and _hide_block() so this method should be called if
        add_block() or remove_block() was called with immediate=False
        """
        start = time.clock()
        while self.show_hide_queue and time.clock(
        ) - start < 1.0 / ticks_per_sec:
            self._dequeue()

    def process_entire_queue(self):
        """Process the entire queue with no breaks."""
        while self.show_hide_queue:
            self._dequeue()

    def init_shader(self):
        vertex_shader = ""
        fragment_shader = ""

        with open("pycraft/shaders/world.vert") as handle:
            vertex_shader = handle.read()

        with open("pycraft/shaders/world.frag") as handle:
            fragment_shader = handle.read()

        self.shader = Shader([vertex_shader], [fragment_shader])

    def start_shader(self):
        self.shader.bind()

    def stop_shader(self):
        self.shader.unbind()

    def add_sector(self, sector, coords):
        self.sector = coords
        self.sectors[coords] = sector
        # self.sectors.setdefault(coords, []).append(sector)

    def show_sector(self, coords, immediate=True):
        """Ensure all blocks in the given sector that should be shown are drawn
        to the canvas.
        """
        sector = self.sectors.get(coords)
        if sector:
            for position in sector.blocks:
                if position not in self.shown and self.area.exposed(position):
                    self.show_block(position, immediate)
        else:
            sector = Sector(coords, self.area)
            self.add_sector(sector, coords)
            self.show_sector(coords)

    def hide_sector(self, coords):
        """Ensure all blocks in the given sector that should be hidden are
        removed from the canvas.
        """
        sector = self.sectors.get(coords)
        for position in sector.blocks:
            if position in self.shown:
                self.hide_block(position, False)

    def change_sectors(self, before, after):
        """Move from sector `before` to sector `after`. A sector is a
        contiguous x, y sub-region of world. Sectors are used to speed up
        world rendering.
        """
        before_set = set()
        after_set = set()
        pad = 4
        if not before:
            self.initial_sector(after)
        for dx in range(-pad, pad + 1):
            for dy in [0]:  # range(-pad, pad + 1):
                for dz in range(-pad, pad + 1):
                    if dx**2 + dy**2 + dz**2 > (pad + 1)**2:
                        continue
                    if before:
                        x, y, z = before
                        before_set.add((x + dx, y + dy, z + dz))
                    if after:
                        x, y, z = after
                        after_set.add((x + dx, y + dy, z + dz))
        show = after_set - before_set
        hide = before_set - after_set
        for coords in hide:
            self.hide_sector(coords)
        for coords in show:
            self.show_sector(coords)

    def initial_sector(self, coords):
        """
        Creates initial sectors in spiral, to speed up rendering in front of the player
        :param coords:
        :return:
        """
        x, y = 0, 0
        dx, dy = 0, -1
        X = coords[0] + 4
        Y = coords[2] + 4
        for i in range(max(X, Y)**2):
            if (-X / 2 < x <= X / 2) and (-Y / 2 < y <= Y / 2):
                self.show_sector((x, coords[1], y))
            if x == y or (x < 0 and x == -y) or (x > 0 and x == 1 - y):
                dx, dy = -dy, dx  # Corner change direction
            x, y = x + dx, y + dy
コード例 #38
0
ファイル: genetic.py プロジェクト: samphippen/genetic
class Drawing:
    def __init__(self, width, height, fbo, background=[255,255,255]):
        self.width = width
        self.height = height
        self.triangles = []
        self.batch = Batch()
        self.bg_colour = background
        self.fb = fbo
        self.bg = self.batch.add( 6,
                        gl.GL_TRIANGLES,None,
                        ("v2i/static", (0,0,0,height,width,height,width,height,width,0,0,0)),
                        ("c3B/static",background*6)
                      )


    def clone(self):
        global group
        d = Drawing(self.width, self.height, self.fb, self.bg_colour)
        bufferlength = len(self.triangles)
        d.vertex_list = d.batch.add(
            bufferlength*3, gl.GL_TRIANGLES, group,
            ("v2i/stream", [0]*bufferlength*6),
            ("c4B/stream", [0]*bufferlength*12)
        )

        d.triangles = [t.clone() for t in self.triangles]
        d.refresh_batch()
        return d

    def mutate(self, num_mutations):
        triangles = self.triangles
        for i in xrange(0, num_mutations):
            e = randint(0,2)
            if e == 0:
                choice = randint(0, len(triangles)-1)
                triangles[choice].recolor_self_delta(5)
                self.update_index(choice)
            elif e == 1:
                choice = randint(0, len(triangles)-1)
                triangles[choice].reshape_delta(self.width, self.height, 25)
                self.update_index(choice)
            elif e == 2:
                c1 = randint(0, len(triangles)-1)
                c2 = clamp(c1 + randint(-5,5), 0, len(triangles)-1)
                triangles[c1],triangles[c2] = triangles[c2],triangles[c1]
                self.update_index(c1)
                self.update_index(c2)

    def update_index(self, i):
        vl = self.vertex_list
        t = self.triangles[i]
        i1 = i*6
        vl.vertices[i1:i1+6] = t.serialize_points()
        i1 *= 2
        vl.colors[i1:i1+12] = t.serialize_color()*3

    def draw(self):
        gl.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, self.fb)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT)
        self.batch.draw()

    def refresh_batch(self):
        for i in xrange(0, len(self.triangles)):
            self.update_index(i)

    def generate(self, number_triangles):
        vertices = []
        colors = []
        for i in xrange(0, number_triangles):
            t = Triangle()
            t.generate(self.width, self.height)
            self.triangles.append(t)

            vertices.extend(t.serialize_points())
            colors.extend(t.serialize_color()*3)
        self.vertex_list = self.batch.add(
            number_triangles*3, gl.GL_TRIANGLES, None,
            ("v2i/stream", vertices),
            ("c4B/stream", colors)
        )

        self.refresh_batch()

    def svg_import(self, svg_file):
        """
        Import the drawing from an SVG file.
        """
        xml = open(svg_file).read()
        soup = BeautifulStoneSoup(xml).svg

        # Width and Height
        w = int(soup['width'].replace('px', ''))
        h = int(soup['height'].replace('px', ''))

        if w != self.width or h != self.height:
            raise Exception("Image dimensions don't match.")
        # two clockwise round triangles make a square
        self.bg.vertices = [ 0,0,
                             0,h,
                             w,h,
                             w,h,
                             w,0,
                             0,0]

        # Background colours
        try:
            name,value = soup.rect['style'].split(':')
        except ValueError:
            pass

        if name == 'fill':
            self.bg_colour[0] = int(value[1:3], 16)
            self.bg_colour[1] = int(value[3:5], 16)
            self.bg_colour[2] = int(value[5:7], 16)

        self.bg.colors = self.bg_colour*6

        # Polygons
        polygons = soup.findAll('polygon')

        vertices = []
        colors = []
        for p in polygons:
            T = Triangle()
            T.svg_soup_import(p, self.height)
            self.triangles.append(T)

            vertices.extend(T.serialize_points())
            colors.extend(T.serialize_color()*3)
        self.vertex_list = self.batch.add(
            len(polygons)*3, gl.GL_TRIANGLES, XTranslationGroup(self.width * 2, 1),
            ("v2i/stream", vertices),
            ("c4B/stream", colors)
        )

        self.refresh_batch()

    def svg_export(self, image_file, svg_file):
        """
        Export the drawing to an SVG file.
        """

        f = open(svg_file,"w")
        f.write('''<?xml version="1.0" standalone="no"?>
        <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

        <svg width="%dpx" height="%dpx" viewport="0 0 %d %d" version="1.1"
        xmlns="http://www.w3.org/2000/svg">''' % (self.width,self.height,self.width,self.height))

        f.write('\n\t<rect width="100%%" height="100%%" style="fill:#%02x%02x%02x;" />' %
                ( self.bg_colour[0],self.bg_colour[1],self.bg_colour[2] )
            )
        for t in self.triangles:
            f.write('''\n\t<polygon points="%d,%d %d,%d %d,%d" style="fill:#%02x%02x%02x; fill-opacity:%f;" />''' % (
                t.points[0][0],
                self.height - t.points[0][1],
                t.points[1][0],
                self.height - t.points[1][1],
                t.points[2][0],
                self.height - t.points[2][1],
                t.color[0],t.color[1],t.color[2],t.color[3]/255.0
            ))

        f.write("\n</svg>")
        f.close()
コード例 #39
0
ファイル: model.py プロジェクト: sammyers/PythonCraft
class Model(object):
    """
    Stores world and player data, with methods to modify blocks.
    """
    def __init__(self, world=None):
        # Batch of pyglet VertexLists; everything loaded into the batch is drawn
        self.batch = Batch()

        # TextureGroup for managing OpenGL textures.
        self.group = TextureGroup(image.load(TEXTURE_PATH).get_texture())

        # All of the blocks in the world; key is a tuple of (x, y, z) position
        if world is None:
            self.world = {}
        else:
            self.world = world

        # Just the blocks that are visible, i.e. exposed on at least one side
        self.visible = {}

        # Mapping from position to a pyglet VertexList (only for visible blocks)
        self.vertices = {}

        # Mapping from chunks to block locations within those chunks.
        self.chunks = {}

        # The chunk in which the player is currently located.
        self.chunk = None

        # The player's position in the world, initially at the origin.
        self.position = (0, 2, 0)

        # The rotation of the player's view. 
        # First element is in the xz plane, second in some rotation of the yz plane.
        # Up-down rotation is constrained to between -90 and 90 (straight up and down)
        self.rotation = (0, 0)

        # Initialize player motion in the xz plane.
        # For the first element, -1 and 1 are left and right.
        # For the second, -1 and 1 are down and up.
        # For the third, backwards and forwards.
        self.motion = [0, 0, 0]

        # A queue for function calls; this allows blocks to be added and removed
        # in a way that doesn't slow down the game loop
        self.queue = deque()

        # Place blocks in the world
        self._initialize()

    def _initialize(self):
        """
        Generate terrain to initialize the world.
        """
        for location in self.world:
            self.add_block(location, self.world[location])

    def initial_render(self):
        """
        Make all blocks visually current by emptying the queue without breaks.
        This method is called once, when the world is first loaded.
        """
        while self.queue:
            self.dequeue()

    def get_nearby_chunks(self, location):
        """
        Return a set containing the chunk locations within range of a given chunk.
        """
        x, z = location
        x_range = range(-CHUNK_DISTANCE, CHUNK_DISTANCE + 1)
        z_range = range(-CHUNK_DISTANCE, CHUNK_DISTANCE + 1)
        chunks = set()
        for dx in x_range:
            for dz in z_range:
                # Only include chunks within a certain Euclidean distance
                if math.sqrt(dx ** 2 + dz ** 2) > CHUNK_DISTANCE:
                    continue
                chunks.add((x + dx, z + dz))
        return chunks

    def update_chunk_location(self, before, after):
        """
        Ensure that the proper adjacent chunks are visible.
        """
        # Show all chunks in range when none are currently loaded.
        # This happens once when the program starts.
        if before is None:
            chunks = self.get_nearby_chunks(after)
            for chunk in chunks:
                self.show_chunk(chunk)
            return

        current = self.get_nearby_chunks(before)
        updated = self.get_nearby_chunks(after)

        shown = updated - current
        hidden = current - updated

        for chunk in shown:
            self.show_chunk(chunk)
        for chunk in hidden:
            self.hide_chunk(chunk)

    def show_chunk(self, chunk_location):
        """
        Show all blocks contained within a given chunk.
        """
        for position in self.chunks.get(chunk_location, []):
            if position not in self.visible and self.check_exposed(position):
                self.enqueue(self.show_block, position)

    def hide_chunk(self, chunk_location):
        """
        Hide all blocks contained within a given chunk.
        """
        for position in self.chunks.get(chunk_location, []):
            if position in self.visible:
                self.visible.pop(position)
                self.enqueue(self.hide_block, position)

    def add_block(self, position, block_id):
        """
        Place a block at a given set of coordinates.
        """
        # Place the block in the world
        self.world[position] = block_id
        # Register the block in the proper chunk
        self.chunks.setdefault(get_chunk(position, CHUNK_SIZE), []).append(position)

    def delete_block(self, position):
        """
        Remove a block from a given set of coordinates.
        """
        pass

    def show_block(self, position):
        """
        Add a block to the batch to be rendered by OpenGL.
        The block will continue being rendered until it's hidden or deleted.
        """
        # Add to record of visible blocks
        self.visible[position] = self.world[position]
        # Find the texture coordinates for the block
        texture_location = BLOCKS[self.world[position]]['texture']

        # Convert cube coordinates and texture position to OpenGl vertices
        vertex_data = cube_vertices(position, 1)
        texture_data = texture_map(*texture_location)

        # Add the cube to the batch, mapping texture vertices to cube vertices.
        self.vertices[position] = self.batch.add(24, GL_QUADS, self.group,
            ('v3f/static', vertex_data),
            ('t2f/static', texture_data))

    def hide_block(self, position):
        """
        Stop a block from being rendered.
        """
        # Remove from the batch by deleting the vertex list
        self.vertices.pop(position).delete()

    def check_exposed(self, position):
        """
        Return true if any of the faces of a block are exposed, otherwise false.
        """
        x, y, z = position
        for dx, dy, dz in DIRECTIONS:
            if (x + dx, y + dy, z + dz) not in self.world:
                return True
        return False

    def enqueue(self, func, *args):
        """
        Add a function to the queue to be called in the program's update loop.
        """
        self.queue.append((func, args))

    def dequeue(self):
        """
        Call the function at the top of the queue.
        """
        func, args = self.queue.popleft()
        func(*args)

    def process_queue(self):
        """
        Call as many functions in the queue as possible within one tick of the game loop.
        """
        start_time = time.clock()
        while self.queue and time.clock() - start_time < 1.0 / TICKS:
            self.dequeue()
コード例 #40
0
def cif_cabinet(x, y, z):
	batch = Batch()

	bottom_left = texture.textures['cif_cabinet_lower_left']['master_coordinates']
	bottom = texture.textures['cif_cabinet_bottom']['master_coordinates']
	bottom_right = texture.textures['cif_cabinet_lower_right']['master_coordinates']
	left = texture.textures['cif_cabinet_left']['master_coordinates']
	right = texture.textures['cif_cabinet_right']['master_coordinates']
	top_left = texture.textures['cif_cabinet_upper_left']['master_coordinates']
	top = texture.textures['cif_cabinet_top']['master_coordinates']
	top_right = texture.textures['cif_cabinet_upper_right']['master_coordinates']
	base = texture.textures['cif_cabinet_base']['master_coordinates']
	line = texture.textures['cif_cabinet_line']['master_coordinates']
	handles = texture.textures['cif_cabinet_handles']['master_coordinates']

	tiles = [
		# Front side
		plane_tile.PlaneTile((x, y, z), side='right', textures={'right': bottom_left}),
		plane_tile.PlaneTile((x, y, z+1), side='right', textures={'right': bottom}),
		plane_tile.PlaneTile((x, y, z+2), side='right', textures={'right': bottom_right}),
		plane_tile.PlaneTile((x, y+1, z), side='right', textures={'right': left}),
		plane_tile.PlaneTile((x, y+1, z+1), side='right', textures={'right': line}),
		plane_tile.PlaneTile((x, y+1, z+2), side='right', textures={'right': right}),
		plane_tile.PlaneTile((x, y+2, z), side='right', textures={'right': left}),
		plane_tile.PlaneTile((x, y+2, z+1), side='right', textures={'right': handles}),
		plane_tile.PlaneTile((x, y+2, z+2), side='right', textures={'right': right}),
		plane_tile.PlaneTile((x, y+3, z), side='right', textures={'right': left}),
		plane_tile.PlaneTile((x, y+3, z+1), side='right', textures={'right': line}),
		plane_tile.PlaneTile((x, y+3, z+2), side='right', textures={'right': right}),
		plane_tile.PlaneTile((x, y+4, z), side='right', textures={'right': top_left}),
		plane_tile.PlaneTile((x, y+4, z+1), side='right', textures={'right': top}),
		plane_tile.PlaneTile((x, y+4, z+2), side='right', textures={'right': top_right}),
		# Left side
		plane_tile.PlaneTile((x+1, y, z), side='back', textures={'back': bottom_left}),
		plane_tile.PlaneTile((x+1, y+1, z), side='back', textures={'back': left}),
		plane_tile.PlaneTile((x+1, y+2, z), side='back', textures={'back': left}),
		plane_tile.PlaneTile((x+1, y+3, z), side='back', textures={'back': left}),
		plane_tile.PlaneTile((x+1, y+4, z), side='back', textures={'back': top_left}),
		plane_tile.PlaneTile((x+2, y, z), side='back', textures={'back': bottom_right}),
		plane_tile.PlaneTile((x+2, y+1, z), side='back', textures={'back': right}),
		plane_tile.PlaneTile((x+2, y+2, z), side='back', textures={'back': right}),
		plane_tile.PlaneTile((x+2, y+3, z), side='back', textures={'back': right}),
		plane_tile.PlaneTile((x+2, y+4, z), side='back', textures={'back': top_right}),
		# Right side
		plane_tile.PlaneTile((x+1, y, z+2), side='front', textures={'front': bottom_right}),
		plane_tile.PlaneTile((x+1, y+1, z+2), side='front', textures={'front': right}),
		plane_tile.PlaneTile((x+1, y+2, z+2), side='front', textures={'front': right}),
		plane_tile.PlaneTile((x+1, y+3, z+2), side='front', textures={'front': right}),
		plane_tile.PlaneTile((x+1, y+4, z+2), side='front', textures={'front': top_right}),
		plane_tile.PlaneTile((x+2, y, z+2), side='front', textures={'front': bottom_left}),
		plane_tile.PlaneTile((x+2, y+1, z+2), side='front', textures={'front': left}),
		plane_tile.PlaneTile((x+2, y+2, z+2), side='front', textures={'front': left}),
		plane_tile.PlaneTile((x+2, y+3, z+2), side='front', textures={'front': left}),
		plane_tile.PlaneTile((x+2, y+4, z+2), side='front', textures={'front': top_left}),
	]

	for tile in tiles:
		vertex_list = tile.get_vertex_list()
		texture_list = tile.get_texture_list()
		vertices = len(vertex_list) / 3

		batch.add(vertices, GL_QUADS, texture.textures['master']['group'], ('v3f/static', vertex_list), ('t2f/static', texture_list))

	return batch
コード例 #41
0
def initialise():
    """Initialises the cube render objects.
    """
    global batch
    batch = Batch()

    batch.add(
        24,
        GL_QUADS,
        None,
        ('v3f',
         (1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
          -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
          1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0,
          -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
          1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0,
          -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0)),
        (
            'c3f',
            (
                # green
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                # orange
                1.0,
                0.5,
                0.0,
                1.0,
                0.5,
                0.0,
                1.0,
                0.5,
                0.0,
                1.0,
                0.5,
                0.0,
                # blue
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                # violet
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                # yellow
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                1.0,
                1.0,
                0.0,
                # red
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
                1.0,
                0.0,
                0.0,
            )))
コード例 #42
0
 def allocate_verts(cls,
                    count: int,
                    batch: Batch,
                    group: Optional[Group] = None) -> VertexList:
     return batch.add(count * cls.vert_count, cls.gl_mode.gl_mode, group,
                      "v2f/stream", "c4B/stream")
コード例 #43
0
ファイル: shape.py プロジェクト: msarch/py
class Shape(object):
    '''
    Shape is a mixed list of:
    - other Shapes
    - base elements
        - list of vertices
        - RGBA color
        - single OpenGL prim: TRIANGLE_STRIP, LINE_STRIP, LINE , POINT
    '''

    new_id = count().next

    def __init__(self, **kwargs):
        self._id = Shape.new_id()
        for key in kwargs:
            setattr(self,key,kwargs[key])
        self.verts=[]
        self.shapes=[]
        self.build()
        if not hasattr(self,'color'):
            self.color = red
        if not hasattr(self,'peg'):  # peg must be tuple (x, y, a)
            self.peg = DOCKED
        if not hasattr(self,'vel'):  # peg must be tuple (vx, vy, av)
            self.vel = IDLE
        if not hasattr (self,'pivot'):
            self.pivot=(0,0)  #  or pivot at AABB center ??                   # TODO
        self.sort()
        self.aabb=self.get_aabb()
        self.flat_verts = None
        self.batch=None
        print "::"
        print ":: new shape ::::::::::::::::::::::::::::::::::::::::::::::::::"
        print "::"
        dumpObj(self)

    def build(self):
        '''
        if this method isn't overridden the new element is either
            - a list of existing shapes
            - epmty
        '''
        pass


    def get_aabb(self): #                         POSSIBLE OPTIMIZATION       # TODO
        _allx=[0]
        _ally=[0]
        for v in self.verts:
            _allx.append(v[0])
            _ally.append(v[1])
        lox=min(_allx)
        loy=min(_ally)
        hix=max(_allx)
        hiy=max(_ally)
        return (AABB(lox,loy,hix,hiy))

    def copy(self):
        ssh=Shape(verts=self.verts, color=self.color,\
                primtype=self.primtype, peg=self.peg, vel=self.vel)
        return(ssh)

    def add(self,*args):
        '''
        Add items to the group list
        '''
        for sh in args:
            self.shapes.append(sh)  #add items
        print "::"
        print "GROUPED SHAPES"
        print "::"
        self.sort()

    def sort(self):
        if not self.shapes ==[]:
            print 'REORDERING ACTORS'
            for s in self.shapes:
                print s._id,
            print
            self.shapes = sorted(self.shapes, key=lambda sh: sh.peg.z, reverse=True)
            print 'NEW ORDER'
            for s in self.shapes:
                print s._id,

    def get_instances(self,root):
        if root.shapes==[]:
            yield root
        else:
            glPushMatrix()
            glTranslatef(root.peg.x, root.peg.y, 0)
            glRotatef(root.peg.angle, 0, 0, 1)
            for element in root.shapes:
                for e in self.get_instances(element):
                    yield e
            glPopMatrix()

    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        self.batch = Batch()
        flatverts = self.get_flat_verts()
        numverts = len(flatverts) / 2
        self.batch.add(
            numverts,
            self.primtype,
            None,
            ('v2f/static', flatverts),
            ('c4B/static', self.color * numverts)
            )

    def paint(self):
        print
        print 'paint',
        for sh in self.get_instances(self):
            if sh.batch is None:
                sh.get_batch()
            glPushMatrix()
            glTranslatef(sh.peg.x, sh.peg.y, 0)
            glRotatef(sh.peg.angle, 0, 0, 1)
            sh.batch.draw()
            glPopMatrix()
            print sh._id,
コード例 #44
0
ファイル: shape.py プロジェクト: msarch/py
class Shape(object):
    '''
    Shape is a mixed list of:
    - other Shapes
    - base elements
        - list of vertices
        - RGBA color
        - single OpenGL prim: TRIANGLE_STRIP, LINE_STRIP, LINE , POINT
    '''
    shapes=[]
    
    def __init__(self, **kwargs):
        for key in kwargs:
            setattr(self,key,kwargs[key])
        if not hasattr(self,'visible'):
            self.visible=True
        if not hasattr(self,'color'):
            self.color = red
        if not hasattr(self,'peg'):  # peg must be tuple (x, y, a)
            self.peg = DOCKED
        if not hasattr(self,'vel'):  # peg must be tuple (vx, vy, av)
            self.vel = IDLE
        if not hasattr (self,'pivot'):
            self.pivot=(0,0)  #  or pivot at AABB center ?? 
        if not hasattr (self,'shapes'):
            self.shapes=[]
        if not hasattr (self,'verts'):
            self.verts=[]  
        self.sort()
        self.flat_verts = None
        self.batch=None
        print ":: new shape", self.id
        Shape.shapes.append(self)

        dumpObj(self)

    def group(self,*args):
        '''
        Group items to  group list
        '''
        for sh in args:
            self.shapes.append(sh)  #add items
        print ":: GROUPED SHAPES"
        self.sort()

    def sort(self):
        if not self.shapes==[]:
            for s in self.shapes:
                print s.id,
            print
            self.shapes = sorted(self.shapes, key=lambda sh: sh.peg.z, reverse=True)
            print 'NEW ORDER',
            for s in self.shapes:
                print s.id,
            
    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        self.batch = Batch()
        flatverts = self.get_flat_verts()
        numverts = len(flatverts) / 2
        self.batch.add(
            numverts,
            self.primtype,
            None,
            ('v2f/static', flatverts),
            ('c4B/static', self.color * numverts)
            )

    def yeld_simple_shapes(self,root):
        if root.verts==[]:  #root is a set of shapes
            glPushMatrix()
            glTranslatef(root.peg.x, root.peg.y, 0)
            glRotatef(root.peg.angle, 0, 0, 1)
            for element in root.shapes:
                for e in self.yeld_simple_shapes(element):
                    yield e
            glPopMatrix()
        else:  #root is a shape itself
            yield root
            
    def yeld_verts(self):
        for sh in self.yeld_simple_shapes(self):
            for v in sh.verts:
                yield v
                
    def offset(self, dx, dy):
        '''
        offset will change the value of all the shapes vertexes
        '''
        newverts = [(v[0] + dx, v[1] + dy) for v in self.yeld_verts()]
        self.verts=newverts
        
    def gl_output(self):
        for sh in self.yeld_simple_shapes(self):
            if sh.batch is None:
                sh.get_batch()
            glPushMatrix()
            glTranslatef(sh.peg.x, sh.peg.y, 0)
            glRotatef(sh.peg.angle, 0, 0, 1)
            sh.batch.draw()
            print ('.'),
            glPopMatrix()

    @classmethod
    def draw(cls):
        visible_shapes = ifilter(lambda s: s.visible, cls.shapes)
        for sh in visible_shapes:
            cls.gl_output(sh)
コード例 #45
0
class Drawing:
    def __init__(self, width, height, background=[255, 255, 255]):
        self.width = width
        self.height = height
        self.triangles = []
        self.batch = Batch()
        self.bg_colour = background
        has_fbo = gl.gl_info.have_extension('GL_EXT_framebuffer_object')

        #setup a framebuffer
        self.fb = gl.GLuint()
        gl.glGenFramebuffersEXT(1, ctypes.byref(self.fb))
        gl.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, self.fb)

        #allocate a texture for the fb to render to
        tex = image.Texture.create_for_size(gl.GL_TEXTURE_2D, width, height,
                                            gl.GL_RGBA)
        gl.glBindTexture(gl.GL_TEXTURE_2D, tex.id)
        gl.glFramebufferTexture2DEXT(gl.GL_FRAMEBUFFER_EXT,
                                     gl.GL_COLOR_ATTACHMENT0_EXT,
                                     gl.GL_TEXTURE_2D, tex.id, 0)

        status = gl.glCheckFramebufferStatusEXT(gl.GL_FRAMEBUFFER_EXT)
        assert status == gl.GL_FRAMEBUFFER_COMPLETE_EXT

        gl.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, 0)

        self.bg = self.batch.add(
            6, gl.GL_TRIANGLES, None,
            ("v2i/static",
             (0, 0, 0, height, width, height, width, height, width, 0, 0, 0)),
            ("c3B/static", background * 6))

    def clone(self):
        global group
        d = Drawing(self.width, self.height, self.bg_colour)
        bufferlength = len(self.triangles)
        d.vertex_list = d.batch.add(bufferlength * 3, gl.GL_TRIANGLES, group,
                                    ("v2i/stream", [0] * bufferlength * 6),
                                    ("c4B/stream", [0] * bufferlength * 12))

        d.triangles = [t.clone() for t in self.triangles]
        d.refresh_batch()
        return d

    def mutate(self, num_mutations):
        triangles = self.triangles
        for i in xrange(0, num_mutations):
            e = randint(0, 2)
            if e == 0:
                choice = randint(0, len(triangles) - 1)
                triangles[choice].recolor_self_delta(5)
                self.update_index(choice)
            elif e == 1:
                choice = randint(0, len(triangles) - 1)
                triangles[choice].reshape_delta(self.width, self.height, 25)
                self.update_index(choice)
            elif e == 2:
                c1 = randint(0, len(triangles) - 1)
                c2 = clamp(c1 + randint(-5, 5), 0, len(triangles) - 1)
                triangles[c1], triangles[c2] = triangles[c2], triangles[c1]
                self.update_index(c1)
                self.update_index(c2)

    def update_index(self, i):
        vl = self.vertex_list
        t = self.triangles[i]
        i1 = i * 6
        vl.vertices[i1:i1 + 6] = t.serialize_points()
        i1 *= 2
        vl.colors[i1:i1 + 12] = t.serialize_color() * 3

    def draw(self):
        gl.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, self.fb)
        self.batch.draw()
        gl.glBindFramebufferEXT(gl.GL_FRAMEBUFFER_EXT, 0)

    def refresh_batch(self):
        for i in xrange(0, len(self.triangles)):
            self.update_index(i)

    def generate(self, number_triangles):
        vertices = []
        colors = []
        for i in xrange(0, number_triangles):
            t = Triangle()
            t.generate(self.width, self.height)
            self.triangles.append(t)

            vertices.extend(t.serialize_points())
            colors.extend(t.serialize_color() * 3)
        self.vertex_list = self.batch.add(number_triangles * 3,
                                          gl.GL_TRIANGLES, None,
                                          ("v2i/stream", vertices),
                                          ("c4B/stream", colors))

        self.refresh_batch()

    def svg_import(self, svg_file):
        """
        Import the drawing from an SVG file.
        """
        xml = open(svg_file).read()
        soup = BeautifulStoneSoup(xml).svg

        # Width and Height
        w = int(soup['width'].replace('px', ''))
        h = int(soup['height'].replace('px', ''))

        if w != self.width or h != self.height:
            raise Exception("Image dimensions don't match.")
        # two clockwise round triangles make a square
        self.bg.vertices = [0, 0, 0, h, w, h, w, h, w, 0, 0, 0]

        # Background colours
        try:
            name, value = soup.rect['style'].split(':')
        except ValueError:
            pass

        if name == 'fill':
            self.bg_colour[0] = int(value[1:3], 16)
            self.bg_colour[1] = int(value[3:5], 16)
            self.bg_colour[2] = int(value[5:7], 16)

        self.bg.colors = self.bg_colour * 6

        # Polygons
        polygons = soup.findAll('polygon')

        vertices = []
        colors = []
        for p in polygons:
            T = Triangle()
            T.svg_soup_import(p, self.height)
            self.triangles.append(T)

            vertices.extend(T.serialize_points())
            colors.extend(T.serialize_color() * 3)
        self.vertex_list = self.batch.add(
            len(polygons) * 3, gl.GL_TRIANGLES,
            XTranslationGroup(self.width * 2, 1), ("v2i/stream", vertices),
            ("c4B/stream", colors))

        self.refresh_batch()

    def svg_export(self, image_file, svg_file):
        """
        Export the drawing to an SVG file.
        """

        f = open(svg_file, "w")
        f.write('''<?xml version="1.0" standalone="no"?>
        <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

        <svg width="%dpx" height="%dpx" viewport="0 0 %d %d" version="1.1"
        xmlns="http://www.w3.org/2000/svg">''' %
                (self.width, self.height, self.width, self.height))

        f.write(
            '\n\t<rect width="100%%" height="100%%" style="fill:#%02x%02x%02x;" />'
            % (self.bg_colour[0], self.bg_colour[1], self.bg_colour[2]))
        for t in self.triangles:
            f.write(
                '''\n\t<polygon points="%d,%d %d,%d %d,%d" style="fill:#%02x%02x%02x; fill-opacity:%f;" />'''
                % (t.points[0][0], self.height - t.points[0][1],
                   t.points[1][0], self.height - t.points[1][1],
                   t.points[2][0], self.height - t.points[2][1], t.color[0],
                   t.color[1], t.color[2], t.color[3] / 255.0))

        f.write("\n</svg>")
        f.close()
コード例 #46
0
ファイル: shapes.py プロジェクト: msarch/py
class Composite(object):
    '''
    a list of shapes _ Composites have shapes and a peg"
    '''
    _instances = set()

    def __init__(self, *args, **kwargs):
        self.shapes = []
        self.batch = None
        if args:
            self.add_items(args)
        for i in kwargs:
            setattr(self,i,kwargs[i])
        if not hasattr(self,'peg'):  # peg must be tuple (x, y, a)
            self.peg = DOCKED
        if not hasattr(self,'vel'):  # peg must be tuple (vx, vy, av)
            self.vel = IDLE
        self._instances.add(weakref.ref(self))

        print "::"
        print ":: new C shape ::::::::::::::::::::::::::::::::::::::::::::::::"
        print "::"
        dumpObj(self)

    @classmethod
    def get_instances(cls):
        dead = set()
        for ref in cls._instances:
            obj = ref()
            if obj is not None:
                yield obj
            else:
                dead.add(ref)
        cls._instances -= dead

    def add_items(self, items):
        '''
        Add a list containing shapes and shapes
        '''
        for item in items:
            if isinstance(item, Composite):  #item is a C-shape
                for ssh in item.shapes:  #decompose item into shapes
                    ssh=ssh.copy() #mke a copy move it at new pos
                    ssh.verts = offset(ssh.verts, item.peg.x+ssh.peg.x, \
                            item.peg.y+ssh.peg.y)
                    self.shapes.append(ssh)  #add it
                    ssh.peg = DOCKED
                    ssh.vel = IDLE
            elif isinstance(item, Shape):
                ssh=item.copy()
                print ssh.verts,  ssh.peg.x, ssh.peg.y
                ssh.verts = offset(ssh.verts, ssh.peg.x, ssh.peg.y)
                print ssh.verts
                self.shapes.append(ssh)  # item is a shape, add a copy of it
                ssh.peg = DOCKED
                ssh.vel = IDLE

            else:
                pass

    def get_batch(self):
        print ':: getting C-Shape batch'
        print ':: self batch is :', self.batch
        if self.batch is None:
            self.batch = Batch()
            print ':: new batch :'
            for ssh in self.shapes:
                print ':: shape :', ssh
                flatverts = ssh.get_flat_verts()
                numverts = len(flatverts) / 2
                self.batch.add(
                    numverts,
                    ssh.primtype,
                    None,
                    ('v2f/static', flatverts),
                    ('c4B/static', ssh.color * numverts)
                )
        return self.batch

    def paint(self):
        print ':: displaying C-Shape :', self
        batch = self.get_batch()
        glPushMatrix()
        glTranslatef(self.peg.x, self.peg.y, 0)
        glRotatef(self.peg.angle, 0, 0, 1)
        batch.draw()
        # OPTIMISATION : cs.batch.draw() directement avec batch déjà à jour TODO
        glPopMatrix()
        print ''
コード例 #47
0
class Shape(object):
    '''
    Shape is a mixed list of:
    - other Shapes
    - base elements
        - list of vertices
        - RGBA color
        - single OpenGL prim: TRIANGLE_STRIP, LINE_STRIP, LINE , POINT
    '''
    shapes = []

    def __init__(self, **kwargs):
        for key in kwargs:
            setattr(self, key, kwargs[key])
        if not hasattr(self, 'visible'):
            self.visible = True
        if not hasattr(self, 'color'):
            self.color = red
        if not hasattr(self, 'peg'):  # peg must be tuple (x, y, a)
            self.peg = DOCKED
        if not hasattr(self, 'vel'):  # peg must be tuple (vx, vy, av)
            self.vel = IDLE
        if not hasattr(self, 'pivot'):
            self.pivot = (0, 0)  #  or pivot at AABB center ??
        if not hasattr(self, 'shapes'):
            self.shapes = []
        if not hasattr(self, 'verts'):
            self.verts = []
        self.sort()
        self.flat_verts = None
        self.batch = None
        print ":: new shape", self.id
        Shape.shapes.append(self)

        dumpObj(self)

    def group(self, *args):
        '''
        Group items to  group list
        '''
        for sh in args:
            self.shapes.append(sh)  #add items
        print ":: GROUPED SHAPES"
        self.sort()

    def sort(self):
        if not self.shapes == []:
            for s in self.shapes:
                print s.id,
            print
            self.shapes = sorted(self.shapes,
                                 key=lambda sh: sh.peg.z,
                                 reverse=True)
            print 'NEW ORDER',
            for s in self.shapes:
                print s.id,

    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        self.batch = Batch()
        flatverts = self.get_flat_verts()
        numverts = len(flatverts) / 2
        self.batch.add(numverts, self.primtype, None,
                       ('v2f/static', flatverts),
                       ('c4B/static', self.color * numverts))

    def yeld_simple_shapes(self, root):
        if root.verts == []:  #root is a set of shapes
            glPushMatrix()
            glTranslatef(root.peg.x, root.peg.y, 0)
            glRotatef(root.peg.angle, 0, 0, 1)
            for element in root.shapes:
                for e in self.yeld_simple_shapes(element):
                    yield e
            glPopMatrix()
        else:  #root is a shape itself
            yield root

    def yeld_verts(self):
        for sh in self.yeld_simple_shapes(self):
            for v in sh.verts:
                yield v

    def offset(self, dx, dy):
        '''
        offset will change the value of all the shapes vertexes
        '''
        newverts = [(v[0] + dx, v[1] + dy) for v in self.yeld_verts()]
        self.verts = newverts

    def gl_output(self):
        for sh in self.yeld_simple_shapes(self):
            if sh.batch is None:
                sh.get_batch()
            glPushMatrix()
            glTranslatef(sh.peg.x, sh.peg.y, 0)
            glRotatef(sh.peg.angle, 0, 0, 1)
            sh.batch.draw()
            print('.'),
            glPopMatrix()

    @classmethod
    def draw(cls):
        visible_shapes = ifilter(lambda s: s.visible, cls.shapes)
        for sh in visible_shapes:
            cls.gl_output(sh)
コード例 #48
0
ファイル: shapes.py プロジェクト: msarch/py
class Shape(object):
    '''
    Shapes have Vertices, a single color, and a single OpenGL primitive
    '''
    _instances = set()

    def __init__(self, **kwargs):
        for key in kwargs:
            setattr(self,key,kwargs[key])
        if not hasattr(self,'peg'):  # peg must be tuple (x, y, a)
            self.peg = DOCKED
        if not hasattr(self,'vel'):  # peg must be tuple (vx, vy, av)
            self.vel = IDLE
        self.build()
        self.aabb=get_aabb(self.verts)
        self.flat_verts = None
        self.batch=None
        self._instances.add(weakref.ref(self))
        print "::"
        print ":: new shape ::::::::::::::::::::::::::::::::::::::::::::::::::"
        print "::"
        dumpObj(self)

    @classmethod
    def get_instances(cls):
        dead = set()
        for ref in cls._instances:
            obj = ref()
            if obj is not None:
                yield obj
            else:
                dead.add(ref)
        cls._instances -= dead

    def copy(self):
        ssh=Shape(verts=self.verts, color=self.color,\
                primtype=self.primtype, peg=self.peg, vel=self.vel)
        return(ssh)

    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            flatverts = self.get_flat_verts()
            numverts = len(flatverts) / 2
            self.batch.add(
                numverts,
                self.primtype,
                None,
                ('v2f/static', flatverts),
                ('c4B/static', self.color * numverts)
                )
        return self.batch

    def paint(self):
        batch = self.get_batch()
        glPushMatrix()
        glTranslatef(self.peg.x, self.peg.y, 0)
        glRotatef(self.peg.angle, 0, 0, 1)
        batch.draw()
        glPopMatrix()

    def build(self):
        pass
コード例 #49
0
ファイル: shapes.py プロジェクト: msarch/py
class Shape(object):
    '''
    A list of primitives
    '''

    def __init__(self,
            items=None,
            posx=0.0,
            posy=0.0,
            angle=0.0,
            vx=0.0,
            vy=0.0,
            va=0.0,
            drawable=True):

        self.primitives = []
        self.posx = posx*1.0
        self.posy = posy*1.0
        self.angle = angle*1.0
        self.vx=vx*1.0
        self.vy=vy*1.0
        self.va=va*1.0  # angular velocity
        self.drawable=drawable
        self.batch = None
        Field.display_list.append(self)

        if items:
            self.add_items(items)
            (self.minx,self.miny,self.maxx,self.maxy) = self.get_aabb()
        else:
            self.minx.self.maxx,self.miny,self.maxy = 0,0,0,0
            self.drawable = False

    def add_items(self, items):
        "Add a list of primitives and shapes"
        for item in items:
            if isinstance(item, Shape):
                self.add_shape(item)
            else:
                self.primitives.append(item)

    def add_shape(self, other):
        "Add the primitives from a given shape"
        for prim in other.primitives:
            self.primitives.append(prim)

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            for prim in self.primitives:
                flatverts = prim.get_flat_verts()
                numverts = len(flatverts) / 2
                self.batch.add(
                    numverts,
                    prim.primtype,
                    None,
                    ('v2f/static', flatverts),
                    ('c3B/static', prim.color * numverts)
                )
        return self.batch

    def transform(self,M):
        """ applies matrix M to all self primitives
        """
        for prim in self.primitives:
            prim.transform(M)

    def get_aabb(self):
        aabb = namedtuple('AABB',['xmin','xmax','ymin','ymax'])
        _allx=[]
        _ally=[]
        for prim in self.primitives:
            for v in prim.verts:
                _allx.append(v[0])
                _ally.append(v[1])
        minx=min(_allx)
        miny=min(_ally)
        maxx=max(_allx)
        maxy=max(_ally)
        box = (minx,miny,maxx,maxy)
        return (box)

    def paint(self):
        if self.drawable:
            glPushMatrix()
            glTranslatef(self.posx, self.posy, 0)
            glRotatef(self.angle, 0, 0, 1)
            batch = self.get_batch()
            batch.draw()
            glPopMatrix()
        else:
            print 'cell', self, 'is not drawable'
コード例 #50
0
ファイル: spline.py プロジェクト: hoonga/2016graphics
class Swept:
    def __init__(self, data, slices, rings):
        self.type = data.type
        self.sections = data.sections
        self.scales = CMSpline(data.scales, None, False)
        self.translates = CMSpline(data.translates, None, False)
        self.orients = CMSpline(data.orients, Quaternion, False)
        self.curves = []
        self.slices = slices
        self.rings = rings
        self.positions = []
        # loops
        for i in range(len(self.scales.pieces)):
            self.curves.insert(i, self.type(data.curves[i],None, True))
        # positions
        print "making positions"
        for i in range(len(self.scales.pieces)):
            scale = n.dot(BezBase, self.scales.pieces[i])
            translate = n.dot(BezBase, self.translates.pieces[i])
            rotate = self.orients.pieces[i]
            for j in n.linspace(0, 1, self.rings, endpoint=False):
                mono = n.array([j**3, j**2, j, 1], dtype=GLfloat).reshape((1,4))
                scale_ = n.dot(mono, scale)
                translate_ = n.dot(mono, translate)
                s0 = Quaternion.slerp(j, rotate[0], rotate[1])
                s1 = Quaternion.slerp(j, rotate[1], rotate[2])
                s2 = Quaternion.slerp(j, rotate[2], rotate[3])
                s3 = Quaternion.slerp(j, s0, s1)
                s4 = Quaternion.slerp(j, s1, s2)
                rotate_ = Quaternion.slerp(j, s3, s4)
                poses = []
                for l in self.curves[i].pieces:
                    for k in n.linspace(0, 1, self.slices, endpoint=False):
                        mono_ = n.array([k**3, k**2, k, 1], dtype=GLfloat)
                        pos = n.dot(n.dot(mono_, self.type.base), l)
                        pos = scale_[0]*pos
                        pos = (rotate_*Quaternion(0, *pos)*rotate_.inv()).arr
                        pos = pos + translate_
                        poses.append(*pos)
                self.positions.append(poses)
        # normals
        print "making normals"
        self.normals = []
        norms = []
        l = len(self.positions[0])
        center = sum(self.positions[0])/l
        for i in range(l):
            v1 = self.positions[0][(i+1)%l] - self.positions[0][i]
            v2 = self.positions[1][i] - self.positions[0][i]
            v3 = self.positions[0][i-1] - self.positions[0][i]
            n1 = Vec3(*n.cross(v1, v2)).normalized()
            n2 = Vec3(*n.cross(v2, v3)).normalized()
            norm = (n1+n2).normalized().arr
            if n.dot(self.positions[0][i] - center, norm) < 0:
                norm = -norm
            norms.append(norm)
        self.normals.append(norms)
        for i in range(1, len(self.positions) - 1):
            norms = []
            center = sum(self.positions[i])/l
            for j in range(l):
                v1 = self.positions[i][(j+1)%l] - self.positions[i][j]
                v2 = self.positions[i+1][j] - self.positions[i][j]
                v3 = self.positions[i][j-1] - self.positions[i][j]
                v4 = self.positions[i-1][j] - self.positions[i][j]
                n1 = Vec3(*n.cross(v1, v2)).normalized()
                n2 = Vec3(*n.cross(v2, v3)).normalized()
                n3 = Vec3(*n.cross(v3, v4)).normalized()
                n4 = Vec3(*n.cross(v4, v1)).normalized()
                norm = (n1+n2+n3+n4).normalized().arr
                if n.dot(self.positions[i][j] - center, norm) < 0:
                    norm = -norm
                norms.append(norm)
            self.normals.append(norms)
        norms = []
        center = sum(self.positions[-1])/l
        for i in range(l):
            v1 = self.positions[-1][i-1] - self.positions[-1][i]
            v2 = self.positions[-2][i] - self.positions[-1][i]
            v3 = self.positions[-1][(i+1)%l] - self.positions[-1][i]
            n1 = Vec3(*n.cross(v1, v2)).normalized()
            n2 = Vec3(*n.cross(v2, v3)).normalized()
            norm = (n1+n2).normalized().arr
            if n.dot(self.positions[-1][i] - center, norm) < 0:
                norm = -norm
            norms.append(norm)
        self.normals.append(norms)

        # making vertexes gl
        print "batching"
        self.batch = Batch()
        for i in range(1, len(self.positions)):
            poses = reduce(lambda x,y:x+y, map(lambda x,y:list(x)+list(y), self.positions[i-1], self.positions[i]))
            poses += poses[0:6]
            norms = reduce(lambda x,y:x+y, map(lambda x,y:list(x)+list(y), self.normals[i-1], self.normals[i]))
            norms += norms[0:6]
            self.batch.add(len(poses)/3, GL_TRIANGLE_STRIP, None, ('v3f/static', poses),('n3f/static', norms))


    def draw(self):
        self.batch.draw()
コード例 #51
0
class Gl_Prim(object):
    """
    Stores a list of vertices, a single color, and a primitive type
    Intended to be rendered as a single OpenGL primitive
    """
    def __init__(self, verts, color, primtype=GL_TRIANGLE_STRIP):
        global setup
        self.verts = verts
        self.color = color
        self.primtype = primtype
        self.vertex_list = None
        self.flat_verts = None
        self.batch = None
        self.peg = dk
        self.aabb = self.get_aabb()
        setup.append(self)

    def offset(self, vx, vy):
        newverts = [(v[0] + vx, v[1] + vy) for v in self.verts]
        return Gl_Prim(newverts, self.color, primtype=self.primtype)

    def transform(self,M):
        """ applies matrix M transformation to all self vertexes
        """
        newverts = [ (M[0]*v[0]+M[1]*v[1]+M[2],
                M[3]*v[0]+M[4]*v[1]+M[5]) for v in self.verts]
        return Gl_Prim(newverts, self.color, primtype=self.primtype)

    def peg_to(self, p):
        self.peg = p

    def get_aabb(self):
        _allx=[]
        _ally=[]
        for v in self.verts:
            _allx.append(v[0])
            _ally.append(v[1])
        lox=min(_allx)
        loy=min(_ally)
        hix=max(_allx)
        hiy=max(_ally)
        return (AABB(lox,loy,hix,hiy))

    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            flatverts = self.get_flat_verts()
            numverts = len(flatverts) / 2
            self.batch.add(
                numverts,
                self.primtype,
                None,
                ('v2f/static', flatverts),
                ('c4B/static', self.color * numverts)
                )
        return self.batch

    def paint(self, peg):
        glPushMatrix()
        glTranslatef(peg.x, peg.y, 0)
        glRotatef(peg.angle, 0, 0, 1)
        batch = self.get_batch()
        batch.draw()
        glPopMatrix()
コード例 #52
0
ファイル: shapes.py プロジェクト: msarch/py
class Shape(object):
    """
    Stores a list of vertices, a single color, and a primitive type
    Intended to be rendered as a single OpenGL primitive
    """
    def __init__(self, name, **kwargs):
        global lmnts
        if name in lmnts:
            raise ValueError('duplicate shape name', name)
            exit(1)
        self.name = name
        lmnts[self.name] = self
        for i in kwargs:
            setattr(self, i, kwargs[i])
        self.build()
        self.aabb = self.get_aabb()
        self.flat_verts = None
        self.batch = None

    def offset(self, vx, vy):
        newverts = [(v[0] + vx, v[1] + vy) for v in self.verts]
        self.verts = newverts

    def transform(self, M):
        """ applies matrix M transformation to all self vertexes
        """
        newverts = [(M[0] * v[0] + M[1] * v[1] + M[2],
                     M[3] * v[0] + M[4] * v[1] + M[5]) for v in self.verts]
        return Shape(newverts, self.color,
                     primtype=self.primtype)  #TODO replace shape verts only

    def get_aabb(self):
        _allx = []
        _ally = []
        for v in self.verts:
            _allx.append(v[0])
            _ally.append(v[1])
        lox = min(_allx)
        loy = min(_ally)
        hix = max(_allx)
        hiy = max(_ally)
        return (AABB(lox, loy, hix, hiy))

    def get_flat_verts(self):
        if self.flat_verts is None:
            self.flat_verts = \
                list(self.verts[0]) + \
                [x for x in chain(*self.verts)] + \
                list(self.verts[-1])
        return self.flat_verts

    def get_batch(self):
        if self.batch is None:
            self.batch = Batch()
            flatverts = self.get_flat_verts()
            numverts = len(flatverts) / 2
            self.batch.add(numverts, self.primtype, None,
                           ('v2f/static', flatverts),
                           ('c4B/static', self.color * numverts))
        return self.batch

    def paint(self, peg):
        print 'painting', self, '@', peg
        batch = self.get_batch()
        glPushMatrix()
        glTranslatef(peg.x, peg.y, 0)
        glRotatef(peg.angle, 0, 0, 1)
        batch.draw()
        glPopMatrix()
コード例 #53
0
class World:
    def __init__(self):
        # A Batch is a collection of vertex lists for batched rendering.
        self.batch = Batch()
        # A TextureGroup manages an OpenGL texture.
        self.group = TextureGroup(image.load(TEXTURE_PATH).get_texture())
        # A mapping from position to the texture of the block at that position.
        # This defines all the blocks that are currently in the world.
        self.objects = {}
        # Same mapping as `world` but only contains blocks that are shown.
        self.shown = {}
        # Mapping from position to a pyglet `VertextList` for all shown blocks.
        self._shown = {}
        # Which sector the player is currently in.
        self.sector = None
        # Mapping from sector to a list of positions inside that sector.
        self.sectors = {}

        self.shader = None
        self.show_hide_queue = OrderedDict()
        self.init_gl()
        #       self._initialize()
        self.init_shader()

    def init_gl(self):
        """Basic OpenGL configuration."""
        # Set the color of "clear", i.e. the sky, in rgba.
        glClearColor(0.5, 0.69, 1.0, 1)
        # Enable culling (not rendering) of back-facing facets -- facets that aren't
        # visible to you.
        glEnable(GL_CULL_FACE)
        # Set the texture minification/magnification function to GL_NEAREST (nearest
        # in Manhattan distance) to the specified texture coordinates. GL_NEAREST
        # "is generally faster than GL_LINEAR, but it can produce textured images
        # with sharper edges because the transition between texture elements is not
        # as smooth."
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        self.init_gl_fog()

    def init_gl_fog(self):
        """Configure the OpenGL fog properties."""
        # Enable fog. Fog "blends a fog color with each rasterized pixel fragment's
        # post-texturing color."
        glEnable(GL_FOG)
        # Set the fog color.
        glFogfv(GL_FOG_COLOR, (GLfloat * 4)(0.5, 0.69, 1.0, 1))
        # Say we have no preference between rendering speed and quality.
        glHint(GL_FOG_HINT, GL_DONT_CARE)
        # Specify the equation used to compute the blending factor.
        glFogi(GL_FOG_MODE, GL_LINEAR)
        # How close and far away fog starts and ends. The closer the start and end,
        # the denser the fog in the fog range.
        glFogf(GL_FOG_START, 20.0)
        glFogf(GL_FOG_END, 60.0)

    def _initialize(self):
        """Initialize the world by placing all the blocks."""
        n = 80  # 1/2 width and height of world
        s = 1  # step size
        y = 0  # initial y height
        for x in range(-n, n + 1, s):
            for z in range(-n, n + 1, s):
                # create a layer stone an grass everywhere.
                self.add_block((x, y - 3, z), stone, immediate=False)
                if x in (-n, n) or z in (-n, n):
                    # create outer walls.
                    for dy in range(-2, 3):
                        self.add_block((x, y + dy, z), stone, immediate=False)
                else:
                    y_max = int((simplex_noise2(x / 30, z / 30) + 1) * 3)
                    for y_lvl in range(y - 2, y_max):
                        if y_lvl < (y_max - 1):
                            block = brick
                        else:
                            block = grass
                        self.add_block((x, y_lvl, z), block, immediate=False)

    def hit_test(self, position, vector, max_distance=8):
        """Line of sight search from current position. If a block is
        intersected it is returned, along with the block previously in the line
        of sight. If no block is found, return None, None.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position to check visibility from.
        vector : tuple of len 3
            The line of sight vector.
        max_distance : int
            How many blocks away to search for a hit.
        """
        m = 8
        x, y, z = position
        dx, dy, dz = vector
        previous = None
        for _ in range(max_distance * m):
            key = normalize((x, y, z))
            if key != previous and key in self.objects:
                return key, previous
            previous = key
            x, y, z = x + dx / m, y + dy / m, z + dz / m
        return None, None

    def exposed(self, position):
        """Returns False is given `position` is surrounded on all 6 sides by
        blocks, True otherwise.
        """
        x, y, z = position
        for dx, dy, dz in FACES:
            if (x + dx, y + dy, z + dz) not in self.objects:
                return True
        return False

    def add_block(self, position, texture, immediate=True):
        """Add a block with the given `texture` and `position` to the world.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to add.
        texture : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        immediate : bool
            Whether or not to draw the block immediately.
        """
        if position in self.objects:
            self.remove_block(position, immediate)
        self.objects[position] = texture
        self.sectors.setdefault(sectorize(position),
                                [[], False])[0].append(position)
        if immediate:
            if self.exposed(position):
                self.show_block(position)
            self.check_neighbors(position)

    def remove_block(self, position, immediate=True):
        """Remove the block at the given `position`.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to remove.
        immediate : bool
            Whether or not to immediately remove block from canvas.
        """
        del self.objects[position]
        # if all the blocks get removed from a sector the sector will stay in
        # sectors as a 'ghost sector' or something. I don't know if this matters.
        self.sectors[sectorize(position)][0].remove(position)
        if immediate:
            if position in self.shown:
                self.hide_block(position)
            self.check_neighbors(position)

    def check_neighbors(self, position):
        """Check all blocks surrounding `position` and ensure their visual
        state is current. This means hiding blocks that are not exposed and
        ensuring that all exposed blocks are shown. Usually used after a block
        is added or removed.
        """
        x, y, z = position
        for dx, dy, dz in FACES:
            key = (x + dx, y + dy, z + dz)
            if key not in self.objects:
                continue
            if self.exposed(key):
                if key not in self.shown:
                    self.show_block(key)
            else:
                if key in self.shown:
                    self.hide_block(key)

    def show_block(self, position):
        """Show the block at the given `position`. This method assumes the
        block has already been added with add_block()

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to show.
        immediate : bool
            Whether or not to show the block immediately.
        """
        texture = self.objects[position]
        self.shown[position] = texture
        self._show_block(position, texture)

    def _show_block(self, position, block):
        """Private implementation of the `show_block()` method.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to show.
        texture : list of len 3
            The coordinates of the texture squares. Use `tex_coords()` to
            generate.
        """
        x, y, z = position
        vertex_data = cube_vertices(x, y, z, 0.5)
        self.__show_block(position, vertex_data, block)

    def __show_block(self, position, vertex_data, block):
        shade_data = cube_shade(1, 1, 1, 1)
        texture_data = block.texture
        self._shown[position] = self.batch.add(24, GL_QUADS, self.group,
                                               ('v3f/static', vertex_data),
                                               ('c3f/static', shade_data),
                                               ('t2f/static', texture_data))

    def hide_block(self, position):
        """Hide the block at the given `position`. Hiding does not remove the
        block from the world.

        Parameters
        ----------
        position : tuple of len 3
            The (x, y, z) position of the block to hide.
        immediate : bool
            Whether or not to immediately remove the block from the canvas.
        """
        self.shown.pop(position)
        self._shown.pop(position).delete()

    def show_sector(self, sector):
        """Ensure all blocks in the given sector that should be shown are drawn
        to the canvas.
        """
        if not sector in self.sectors:
            self.generate_sector(sector)
        self.show_hide_queue[sector] = True

    def generate_sector(self, sector):
        """Generate blocks within sector using simplex_noise2
        """
        for column in reverse_sectorize(sector):
            x, z = column
            y_max = int((simplex_noise2(x / 30, z / 30) + 1) * 3)
            for y_lvl in range(0 - 2, y_max):
                self.add_block((x, y_lvl, z), sand, immediate=False)
            else:
                self.add_block((x, y_lvl, z), grass, immediate=False)
            # add the safety stone floor.
            # don't want anyone falling into the ether.
            self.add_block((x, 0 - 3, z), stone, immediate=False)

    def hide_sector(self, sector):
        """Ensure all blocks in the given sector that should be hidden are
        removed from the canvas.
        """
        self.show_hide_queue[sector] = False

    def change_sectors(self, before, after):
        """Move from sector `before` to sector `after`. A sector is a
        contiguous x, y sub-region of world. Sectors are used to speed up
        world rendering.
        """
        before_set = set()
        after_set = set()
        pad = 4
        for dx in range(-pad, pad + 1):
            for dy in [0]:  # range(-pad, pad + 1):
                for dz in range(-pad, pad + 1):
                    if dx**2 + dy**2 + dz**2 > (pad + 1)**2:
                        continue
                    if before:
                        x, y, z = before
                        before_set.add((x + dx, y + dy, z + dz))
                    if after:
                        x, y, z = after
                        after_set.add((x + dx, y + dy, z + dz))
        show = after_set - before_set
        hide = before_set - after_set
        for sector in show:
            self.show_sector(sector)
        for sector in hide:
            self.hide_sector(sector)

    def _dequeue(self):
        """Pop the top function from the internal queue and call it."""
        sector, show = self.show_hide_queue.popitem(last=False)
        try:
            positions, shown = self.sectors[sector]
        except KeyError:
            self.show_hide_queue[sector] = show
        else:
            print("drawing sector {}".format(str(sector)))
            if show and not shown:
                vertex_datas = batch_cube_vertices(positions)
                for position, vertex_data in zip(positions, vertex_datas):
                    self.__show_block(position, vertex_data,
                                      self.objects[position])
            elif shown and not show:
                for position in positions:
                    self.hide_block(position)

    def process_queue(self, ticks_per_sec):
        """Process the entire queue while taking periodic breaks. This allows
        the game loop to run smoothly. The queue contains calls to
        _show_block() and _hide_block() so this method should be called if
        add_block() or remove_block() was called with immediate=False
        """
        start = time.clock()
        while self.show_hide_queue and time.clock(
        ) - start < 1.0 / ticks_per_sec:
            self._dequeue()

    def process_entire_queue(self):
        """Process the entire queue with no breaks."""
        while self.show_hide_queue:
            self._dequeue()

    def init_shader(self):
        vertex_shader = ""
        fragment_shader = ""

        with open("pycraft/shaders/world.vert") as handle:
            vertex_shader = handle.read()

        with open("pycraft/shaders/world.frag") as handle:
            fragment_shader = handle.read()

        self.shader = Shader([vertex_shader], [fragment_shader])

    def start_shader(self):
        self.shader.bind()

    def stop_shader(self):
        self.shader.unbind()
コード例 #54
0
ファイル: render.py プロジェクト: ym87498510/RLSchool
class Map(object):
    """
    Map is an object to describe the virtual world.

    For `no_collision` task, the `Map` contains a floor and other optional
    obstacle walls. Drone is rendered as 3D model with flighting pose.

    For `velocity_control` task, the `Map` ONLY contains a 3D drone model.
    Moreover, the velocity vector of the drone is shown with an orange arrow;
    the expected velocity vector of the drone is shown with a yellow arrow.

    Args:
        drone_3d_model (str): path to 3D STL model of the drone.
        horizon_view_size (int): number of blocks to show in horizon view.
        init_drone_z (float): the initial height of the drone.
        task (str): name of the task setting. Currently, support
            `no_collision` and `velocity_control`.
    """
    def __init__(self,
                 drone_3d_model,
                 horizon_view_size=8,
                 init_drone_z=5,
                 task='no_collision',
                 debug_mode=False):
        self.task = task
        self.debug_mode = debug_mode

        # When increase this, show more blocks in current view window
        self.horizon_view_size = horizon_view_size

        # A Batch is a collection of vertex lists for batched rendering
        self.batch = Batch()

        # Manages an OpenGL texture
        self.group = TextureGroup(image.load(TEXTURE_PATH).get_texture())

        # A mapping from position to the texture for whole, global map
        self.whole_map = dict()

        # Same as `whole_map` but only contains the positions to show
        self.partial_map = dict()

        # A mapping from position to a pyglet `VertextList` in `partial_map`
        self._partial_map = dict()

        # A mapping from sector to a list of positions (contiguous sub-region)
        # using sectors for fast rendering
        self.sectors = dict()

        # Use deque to populate calling of `_show_block` and `_hide_block`
        self.queue = deque()

        # A graphics batch to draw drone 3D model
        self.drone_batch = pyglet.graphics.Batch()
        # Load drone triangular mesh and scene
        self.drone_name = os.path.basename(drone_3d_model)
        self.drone_mesh = trimesh.load(drone_3d_model)
        self.drone_scene = self.drone_mesh.scene()
        # Drawer stores drone scene geometry as vertex list in its model space
        self.drone_drawer = None
        # Store drone geometry hashes for easy retrival
        self.drone_vertex_list_hash = ''
        # Store drone geometry rendering mode, default gl.GL_TRIANGLES
        self.drone_vertex_list_mode = gl.GL_TRIANGLES
        # Store drone geometry texture
        self.drone_texture = None

        black = np.array([0, 0, 0, 255], dtype=np.uint8)
        red = np.array([255, 0, 0, 255], dtype=np.uint8)
        green = np.array([0, 255, 0, 255], dtype=np.uint8)
        blue = np.array([0, 0, 255, 255], dtype=np.uint8)
        for i, facet in enumerate(self.drone_mesh.facets):
            if i < 30:
                self.drone_mesh.visual.face_colors[facet] = black
            elif i < 42:
                self.drone_mesh.visual.face_colors[facet] = red
            elif i < 54:
                self.drone_mesh.visual.face_colors[facet] = green
            elif i < 66:
                self.drone_mesh.visual.face_colors[facet] = blue
            else:
                self.drone_mesh.visual.face_colors[facet] = black

        # Mark positions of bounding wall and obstacles in the map
        self._initialize(init_drone_z)

    def _initialize(self, init_drone_z):
        if self.task in ['no_collision', 'hovering_control']:
            h = w = 100
            for y in range(0, h):
                for x in range(0, w):
                    # Pave the floor
                    self._add_block((x, y, 0), TILE, immediate=False)
        elif self.task == 'velocity_control':
            h = w = 0

        self.drone_pos = [h // 2, w // 2, init_drone_z]
        self._add_drone()

        if self.task == 'velocity_control':
            self.drone_velocity_drawer = self._add_drone_velocity(
                np.array([0.0, 0.0, 1.0]), color=[255, 95, 63])  # orange
            self.drone_expected_velocity_drawer = self._add_drone_velocity(
                np.array([0.0, 0.0, 1.0]), color=[240, 210, 90])  # yellow

    def _is_exposed(self, position):
        x, y, z = position
        for dx, dy, dz in FACES:
            if (x + dx, y + dy, z + dz) not in self.whole_map:
                # At least one face is not covered by another cube block.
                return True
        return False

    def _add_drone(self):
        """ Add the drone 3D model in its own model space.
        """
        for name, geom in self.drone_scene.geometry.items():
            if geom.is_empty:
                continue
            if geometry_hash(geom) == self.drone_vertex_list_hash:
                continue

            if name == self.drone_name:
                args = rendering.convert_to_vertexlist(geom, smooth=True)
                self.drone_drawer = self.drone_batch.add_indexed(*args)
                self.drone_vertex_list_hash = geometry_hash(geom)
                self.drone_vertex_list_mode = args[1]

                try:
                    assert len(geom.visual.uv) == len(geom.vertices)
                    has_texture = True
                except BaseException:
                    has_texture = False

                if has_texture:
                    self.drone_texture = rendering.material_to_texture(
                        geom.visual.material)

    def _add_drone_velocity(self,
                            init_velocity_vector,
                            radius=0.008,
                            color=[255, 0, 0]):
        """
        Add the drone velocity vector as a cylinder into drone drawer batch.
        """
        translation = np.eye(4)
        translation[:3, 3] = [0, 0, 0.5]

        height = np.linalg.norm(init_velocity_vector)
        transform_z_axis = init_velocity_vector / height
        transform = np.eye(4)
        transform[:3, 2] = transform_z_axis
        transform = np.dot(translation, transform)

        velocity_axis = trimesh.creation.cylinder(radius=radius,
                                                  height=height,
                                                  transform=transform)
        velocity_axis.visual.face_colors = color
        axis_origin = trimesh.creation.uv_sphere(radius=radius * 5,
                                                 count=[10, 10])
        axis_origin.visual.face_colors = color

        merge = trimesh.util.concatenate([axis_origin, velocity_axis])
        args = rendering.convert_to_vertexlist(merge)
        drawer = self.drone_batch.add_indexed(*args)
        return drawer

    def _add_block(self, position, texture, immediate=True):
        """ Add a block with the given `texture` and `position` to the world.

        Note that block is a 1x1x1 cube and its position is its centroid.

        Args:

        position (tuple): The (x, y, z) position of the block to add.
        texture (list): The coordinates of the texture squares, e.g. TILE.
        immediate (bool): Whether or not to draw the block immediately.

        """
        if position in self.whole_map:
            # Not called for current static map
            assert False, 'Duplicated block!'
            self._remove_block(position, immediate)

        self.whole_map[position] = texture
        self.sectors.setdefault(sectorize(position), []).append(position)
        if immediate:
            if self._is_exposed(position):
                self.show_block(position)
            self._check_neighbors(position)

    def _remove_block(self, position, immediate=True):
        """ Remove the block at the given `position`.

        Args:

        position (tuple): The (x, y, z) position of the block to remove.
        immediate (bool): Whether or not to remove the block immediately.

        """
        del self.whole_map[position]
        self.sectors[sectorize(position)].remove(position)
        if immediate:
            if position in self.partial_map:
                self.hide_block(position)
            self._check_neighbors(position)

    def _check_neighbors(self, position):
        x, y, z = position
        for dx, dy, dz in FACES:
            pos = (x + dx, y + dy, z + dz)
            if pos not in self.whole_map:
                continue
            if self._is_exposed(pos):
                if pos not in self.partial_map:
                    self.show_block(pos)
            else:
                if pos in self.partial_map:
                    self.hide_block(pos)

    def _show_block(self, position, texture):
        vertex_data = cube_vertices(position, 0.5)  # 12x6=72
        texture_data = list(texture)  # 8x6=48
        vertex_count = len(vertex_data) // 3  # 24
        attributes = [('v3f/static', vertex_data),
                      ('t2f/static', texture_data)]
        self._partial_map[position] = self.batch.add(vertex_count, gl.GL_QUADS,
                                                     self.group, *attributes)

    def _hide_block(self, position):
        self._partial_map.pop(position).delete()

    def _enqueue(self, func, *args):
        self.queue.append((func, args))

    def _dequeue(self):
        func, args = self.queue.popleft()
        func(*args)

    def _get_velocity_transform(self, velocity, position):
        height = np.linalg.norm(velocity)
        transform = np.eye(4)

        # Translation
        x, z, y = position
        transform[:3, 3] = [x, y, z]

        # Rescale
        transform[2, 2] = height

        # Rotate
        rotation = np.eye(4)
        rotation[:3, 2] = velocity / height

        return np.dot(transform, rotation)

    def show_drone(self, position, rotation):
        """
        Show the drone 3D model with corresponding translation and rotation.
        """
        # Get the transform matrix for drone 3D model
        x, z, y = position
        transform = np.eye(4)
        transform[:3, 3] = [x, y, z]

        # NOTE: change the view size of drone 3D model
        transform[0, 0] = 2.5
        transform[1, 1] = 2.5
        transform[2, 2] = 2.5

        # Match drone model space x-y-z to openGL x-z-y
        # TODO: read the config.json and match the propeller positions
        model_space_transform = rotation_transform_mat(-np.pi / 2, 'roll')
        transform = np.dot(transform, model_space_transform)

        yaw, pitch, roll = rotation
        if self.debug_mode:
            # NOTE: manually set values to debug rotation,
            # it's useful when input act is in form [c, c, c, c].
            yaw = np.pi / 2
            # pitch = np.pi / 2
            # roll = np.pi / 2
        transform = np.dot(transform, rotation_transform_mat(yaw, 'yaw'))
        transform = np.dot(transform, rotation_transform_mat(pitch, 'pitch'))
        transform = np.dot(transform, rotation_transform_mat(roll, 'roll'))

        # Add a new matrix to the model stack to transform the model
        gl.glPushMatrix()
        gl.glMultMatrixf(rendering.matrix_to_gl(transform))

        # Enable the target texture
        if self.drone_texture is not None:
            gl.glEnable(self.drone_texture.target)
            gl.glBindTexture(self.drone_texture.target, self.drone_texture.id)

        # Draw the mesh with its transform applied
        self.drone_drawer.draw(mode=self.drone_vertex_list_mode)
        gl.glPopMatrix()

        # Disable texture after using
        if self.drone_texture is not None:
            gl.glDisable(self.drone_texture.target)

    def show_velocity(self, position, velocity, expected_velocity=None):
        """
        Show velocity vector as a thin cylinder arrow.
        """
        if not hasattr(self, 'drone_velocity_drawer'):
            return

        transform = self._get_velocity_transform(velocity, position)
        gl.glPushMatrix()
        gl.glMultMatrixf(rendering.matrix_to_gl(transform))

        self.drone_velocity_drawer.draw(mode=self.drone_vertex_list_mode)
        gl.glPopMatrix()

        if expected_velocity is not None and \
           hasattr(self, 'drone_expected_velocity_drawer'):
            transform = self._get_velocity_transform(expected_velocity,
                                                     position)
            gl.glPushMatrix()
            gl.glMultMatrixf(rendering.matrix_to_gl(transform))

            self.drone_expected_velocity_drawer.draw(
                mode=self.drone_vertex_list_mode)
            gl.glPopMatrix()

    def show_block(self, position, immediate=True):
        texture = self.whole_map[position]
        self.partial_map[position] = texture
        if immediate:
            self._show_block(position, texture)
        else:
            self._enqueue(self._show_block, position, texture)

    def hide_block(self, position, immediate=True):
        self.partial_map.pop(position)
        if immediate:
            self._hide_block(position)
        else:
            self._enqueue(self._hide_block, position)

    def show_sector(self, sector):
        for position in self.sectors.get(sector, []):
            if position not in self.partial_map and self._is_exposed(position):
                self.show_block(position, immediate=False)

    def hide_sector(self, sector):
        for position in self.sectors.get(sector, []):
            if position in self.partial_map:
                self.hide_block(position, immediate=False)

    def change_sectors(self, before, after):
        """
        Find the changed sectors and trigger show or hide operations
        """
        # TODO: adjust the sector set when add extra view perspective
        # relative to the drone.
        # FIXME: when the drone flies high, the green floor immediately
        # disappear
        before_set, after_set = set(), set()
        pad = self.horizon_view_size // 2
        for dx in range(-pad, pad + 1):
            for dy in range(-pad, pad + 1):
                dz = 0
                if dx**2 + dy**2 + dz**2 > (pad + 1)**2:
                    continue
                if before:
                    x, y, z = before
                    before_set.add((x + dx, y + dy, z + dz))
                if after:
                    x, y, z = after
                    after_set.add((x + dx, y + dy, z + dz))

        show = after_set - before_set
        hide = before_set - after_set
        for sector in show:
            self.show_sector(sector)
        for sector in hide:
            self.hide_sector(sector)

    def process_queue(self):
        # NOTE: no scheduled interval timer, we render by manually calling
        # `RenderWindow.view()`. So we process queue without time contrains.
        # In other words, it's a copy of `process_entire_queue()`
        while self.queue:
            self._dequeue()

    def process_entire_queue(self):
        while self.queue:
            self._dequeue()