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):
77 self.body = pymunk.Body(0, 0, pymunk.body.Body.STATIC)
79 self.position = position
82 if self.body.space is not None:
83 space.remove(self.body, *self.body.shapes)
84 shapes = self.shapes_for_ray_polys(
85 calculate_ray_polys(space, self.body, self.position))
87 shape.filter = LIGHT_FILTER
88 space.add(self.body, *shapes)
90 def shapes_for_ray_polys(self, space):
91 raise NotImplementedError(
92 "Lights should implement .determine_ray_polys.")
95 def load(cls, config):
97 light_type = kw.pop("type")
99 c for c in cls.__subclasses__()
100 if c.__name__.lower() == light_type]
101 return light_class(**kw)
104 class SpotLight(BaseLight):
106 self, colour="white", position=None, direction=90.0, spread=45.0):
107 super(SpotLight, self).__init__(colour, position)
108 self.direction = direction
112 def shapes_for_ray_polys(self, ray_polys):
115 def render(self, surface):
117 surface, (255, 255, 0),
118 pymunk.pygame_util.to_pygame(self.position, surface), 5)
120 def render_light(self, surface):
121 subsurface = surface.copy()
122 light_colour = self.COLOURS[self.colour]
123 for shape in self.body.shapes:
125 pymunk.pygame_util.to_pygame(v, surface) for v in
126 shape.get_vertices()]
128 subsurface, light_colour, pygame_poly, 0)
130 subsurface, light_colour, True, pygame_poly, 1)
131 subsurface.set_alpha(50)
132 surface.blit(subsurface, (0, 0), None)
135 class Lamp(BaseLight):
136 def __init__(self, colour="white", position=None, radius=100.0):
137 super(Lamp, self).__init__(colour, position)