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. """
71 "blue": (0, 255, 255),
72 "yellow": (255, 255, 0),
73 "white": (255, 255, 255),
76 def __init__(self, colour, position):
78 self.body = pymunk.Body(0, 0, pymunk.body.Body.STATIC)
80 self.position = position
83 def load(cls, config):
85 light_type = kw.pop("type")
87 c for c in cls.__subclasses__()
88 if c.__name__.lower() == light_type]
89 return light_class(**kw)
92 if self.body.space is not None:
93 space.remove(self.body, *self.body.shapes)
94 shapes = self.shapes_for_ray_polys(
95 calculate_ray_polys(space, self.body, self.position))
97 shape.filter = LIGHT_FILTER
98 space.add(self.body, *shapes)
100 def shapes_for_ray_polys(self, ray_polys):
104 self.on = not self.on
106 def render_light(self, surface):
109 subsurface = surface.copy()
110 light_colour = self.COLOURS[self.colour]
111 for shape in self.body.shapes:
113 pymunk.pygame_util.to_pygame(v, surface) for v in
114 shape.get_vertices()]
116 subsurface, light_colour, pygame_poly, 0)
118 subsurface, light_colour, True, pygame_poly, 1)
119 subsurface.set_alpha(50)
120 surface.blit(subsurface, (0, 0), None)
122 def render_fittings(self, surface):
124 surface, (255, 255, 0),
125 pymunk.pygame_util.to_pygame(self.position, surface), 5)
128 class SpotLight(BaseLight):
130 self, colour="white", position=None, direction=90.0, spread=45.0):
131 super(SpotLight, self).__init__(colour, position)
132 self.direction = direction
137 class Lamp(BaseLight):
138 def __init__(self, colour="white", position=None, radius=100.0):
139 super(Lamp, self).__init__(colour, position)