1 """ May it be a light for you in dark places, when all other lights go out.
7 import pymunk.pygame_util
10 from .constants import SCREEN_SIZE, LIGHT_CATEGORY, DEBUG
12 LIGHT_FILTER = pymunk.ShapeFilter(
13 mask=pymunk.ShapeFilter.ALL_MASKS ^ LIGHT_CATEGORY,
14 categories=LIGHT_CATEGORY)
18 """ An iterable that returns ordered rays from pos to the edge of the
19 screen, starting with the edge point (0, 0) and continuing clockwise
20 in pymunk coordinates.
23 left, right, bottom, top = 0, w, 0, h
25 for y in range(0, h, step):
26 yield pymunk.Vec2d(left, y)
27 for x in range(0, w, step):
28 yield pymunk.Vec2d(x, top)
29 for y in range(top, -1, -step):
30 yield pymunk.Vec2d(right, y)
31 for x in range(right, -1, -step):
32 yield pymunk.Vec2d(x, bottom)
35 def calculate_ray_polys(space, body, position):
36 start_time = time.time()
37 position = pymunk.Vec2d(position)
40 for ray in screen_rays(position):
41 info = space.segment_query_first(position, ray, 1, LIGHT_FILTER)
42 point = ray if info is None else info.point
43 vertices.append(point)
45 trial_poly = pymunk.Poly(None, vertices)
46 trial_poly.update(pymunk.Transform.identity())
47 query_prev = trial_poly.point_query(vertices[-2])
48 query_pos = trial_poly.point_query(position)
49 if query_prev.distance < -0.01 or query_pos.distance < -0.01:
50 new_poly = pymunk.Poly(body, vertices[:-1])
51 vertices = [position, vertices[-1]]
52 ray_polys.append(new_poly)
54 ray_polys.append(pymunk.Poly(body, vertices))
55 end_time = time.time()
58 "calculate_ray_polys: %d polys, %g seconds" %
59 (len(ray_polys), end_time - start_time))
63 class BaseLight(object):
64 """ Common light functionality. """
66 def __init__(self, colour, position):
67 self.body = pymunk.Body(0, 0, pymunk.body.Body.STATIC)
69 self.position = position
72 if self.body.space is not None:
73 space.remove(self.body, *self.body.shapes)
74 shapes = self.shapes_for_ray_polys(
75 calculate_ray_polys(space, self.body, self.position))
77 shape.filter = LIGHT_FILTER
78 space.add(self.body, *shapes)
80 def shapes_for_ray_polys(self, space):
81 raise NotImplementedError(
82 "Lights should implement .determine_ray_polys.")
85 def load(cls, config):
87 light_type = kw.pop("type")
89 c for c in cls.__subclasses__()
90 if c.__name__.lower() == light_type]
91 return light_class(**kw)
94 class SpotLight(BaseLight):
96 self, colour="white", position=None, direction=90.0, spread=45.0):
97 super(SpotLight, self).__init__(colour, position)
98 self.direction = direction
102 def shapes_for_ray_polys(self, ray_polys):
105 def render(self, surface):
106 subsurface = surface.copy()
108 surface, (255, 255, 0),
109 pymunk.pygame_util.to_pygame(self.position, surface), 5)
110 for shape in self.body.shapes:
112 pymunk.pygame_util.to_pygame(v, surface) for v in
113 shape.get_vertices()]
115 subsurface, (200, 200, 200), pygame_poly, 0)
117 subsurface, (200, 200, 200), True, pygame_poly, 1)
118 subsurface.set_alpha(200)
119 surface.blit(subsurface, (0, 0), None)
122 class Lamp(BaseLight):
123 def __init__(self, colour="white", position=None, radius=100.0):
124 super(Lamp, self).__init__(colour, position)