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 vertices = trial_poly.get_vertices() + [point]
56 ray_polys.append(pymunk.Poly(body, vertices))
57 end_time = time.time()
60 "calculate_ray_polys: %d polys, %g seconds" %
61 (len(ray_polys), end_time - start_time))
65 class BaseLight(object):
66 """ Common light functionality. """
68 def __init__(self, colour, position):
69 self.body = pymunk.Body(0, 0, pymunk.body.Body.STATIC)
71 self.position = position
74 if self.body.space is not None:
75 space.remove(self.body, *self.body.shapes)
76 shapes = self.shapes_for_ray_polys(
77 calculate_ray_polys(space, self.body, self.position))
79 shape.filter = LIGHT_FILTER
80 space.add(self.body, *shapes)
82 def shapes_for_ray_polys(self, space):
83 raise NotImplementedError(
84 "Lights should implement .determine_ray_polys.")
87 def load(cls, config):
89 light_type = kw.pop("type")
91 c for c in cls.__subclasses__()
92 if c.__name__.lower() == light_type]
93 return light_class(**kw)
96 class SpotLight(BaseLight):
98 self, colour="white", position=None, direction=90.0, spread=45.0):
99 super(SpotLight, self).__init__(colour, position)
100 self.direction = direction
104 def shapes_for_ray_polys(self, ray_polys):
107 def render(self, surface):
108 subsurface = surface.copy()
110 surface, (255, 255, 0),
111 pymunk.pygame_util.to_pygame(self.position, surface), 5)
112 for shape in self.body.shapes:
114 pymunk.pygame_util.to_pygame(v, surface) for v in
115 shape.get_vertices()]
117 subsurface, (200, 200, 200), pygame_poly, 0)
119 subsurface, (200, 200, 200), True, pygame_poly, 1)
120 subsurface.set_alpha(200)
121 surface.blit(subsurface, (0, 0), None)
124 class Lamp(BaseLight):
125 def __init__(self, colour="white", position=None, radius=100.0):
126 super(Lamp, self).__init__(colour, position)