1 """ May it be a light for you in dark places, when all other lights go out.
5 import pymunk.pygame_util
8 from .constants import SCREEN_SIZE, LIGHT_CATEGORY
9 from .utils import debug_timer
11 LIGHT_FILTER = pymunk.ShapeFilter(
12 mask=pymunk.ShapeFilter.ALL_MASKS ^ LIGHT_CATEGORY,
13 categories=LIGHT_CATEGORY)
17 """ An iterable that returns ordered rays from pos to the edge of the
18 screen, starting with the edge point (0, 0) and continuing clockwise
19 in pymunk coordinates.
22 left, right, bottom, top = 0, w, 0, h
24 for y in range(0, h, step):
25 yield pymunk.Vec2d(left, y)
26 for x in range(0, w, step):
27 yield pymunk.Vec2d(x, top)
28 for y in range(top, -1, -step):
29 yield pymunk.Vec2d(right, y)
30 for x in range(right, -1, -step):
31 yield pymunk.Vec2d(x, bottom)
34 @debug_timer("lights.calculate_ray_polys")
35 def calculate_ray_polys(space, body, position):
36 position = pymunk.Vec2d(position)
39 for ray in screen_rays(position):
40 info = space.segment_query_first(position, ray, 1, LIGHT_FILTER)
41 point = ray if info is None else info.point
42 vertices.append(point)
44 trial_poly = pymunk.Poly(None, vertices)
45 trial_poly.update(pymunk.Transform.identity())
46 query_prev = trial_poly.point_query(vertices[-2])
47 query_pos = trial_poly.point_query(position)
48 if query_prev.distance < -0.01 or query_pos.distance < -0.01:
49 new_poly = pymunk.Poly(body, vertices[:-1])
50 vertices = [position, vertices[-1]]
51 ray_polys.append(new_poly)
53 vertices = trial_poly.get_vertices() + [point]
55 ray_polys.append(pymunk.Poly(body, vertices))
59 class BaseLight(object):
60 """ Common light functionality. """
65 "blue": (0, 255, 255),
66 "yellow": (255, 255, 0),
67 "white": (255, 255, 255),
70 def __init__(self, colour, position):
72 self.body = pymunk.Body(0, 0, pymunk.body.Body.STATIC)
74 self.position = position
77 def load(cls, config):
79 light_type = kw.pop("type")
81 c for c in cls.__subclasses__()
82 if c.__name__.lower() == light_type]
83 return light_class(**kw)
86 if self.body.space is not None:
87 space.remove(self.body, *self.body.shapes)
88 shapes = self.shapes_for_ray_polys(
89 calculate_ray_polys(space, self.body, self.position))
91 shape.filter = LIGHT_FILTER
92 space.add(self.body, *shapes)
94 def shapes_for_ray_polys(self, ray_polys):
100 def render_light(self, surface):
103 subsurface = surface.copy()
104 light_colour = self.COLOURS[self.colour]
105 for shape in self.body.shapes:
107 pymunk.pygame_util.to_pygame(v, surface) for v in
108 shape.get_vertices()]
110 subsurface, light_colour, pygame_poly, 0)
112 subsurface, light_colour, True, pygame_poly, 1)
113 subsurface.set_alpha(50)
114 surface.blit(subsurface, (0, 0), None)
116 def render_fittings(self, surface):
118 surface, (255, 255, 0),
119 pymunk.pygame_util.to_pygame(self.position, surface), 5)
122 class SpotLight(BaseLight):
124 self, colour="white", position=None, direction=90.0, spread=45.0):
125 super(SpotLight, self).__init__(colour, position)
126 self.direction = direction
131 class Lamp(BaseLight):
132 def __init__(self, colour="white", position=None, radius=100.0):
133 super(Lamp, self).__init__(colour, position)