A hackable template for creating small and fast browser games.
1/**
2 * # Light
3 *
4 * The `Light` component allows an entity to emit light.
5 */
6
7import {Vec3} from "../../lib/math.js";
8import {Entity} from "../../lib/world.js";
9import {LightKind} from "../../materials/light.js";
10import {Game} from "../game.js";
11import {Has} from "../world.js";
12
13export type Light = LightAmbient | LightDirectional | LightPoint;
14
15export interface LightAmbient {
16 Kind: LightKind.Ambient;
17 Color: Vec3;
18 Intensity: number;
19}
20
21/**
22 * Add `LightAmbient` component to an entity.
23 *
24 * Ambient lights are only supported in
25 * [`sys_render_deferred`](sys_render_deferred.html). The entity's transform is
26 * ignored during shading.
27 *
28 * @param color The color of the light.
29 * @param intensity The intensity of the light, multiplied by the color.
30 */
31export function light_ambient(color: Vec3 = [1, 1, 1], intensity: number = 0.2) {
32 return (game: Game, entity: Entity) => {
33 game.World.Signature[entity] |= Has.Light;
34 game.World.Light[entity] = {
35 Kind: LightKind.Ambient,
36 Color: color,
37 Intensity: intensity,
38 };
39 };
40}
41
42export interface LightDirectional {
43 Kind: LightKind.Directional;
44 Color: Vec3;
45 Intensity: number;
46}
47
48/**
49 * Add `LightDirectional` to an entity.
50 *
51 * The position of directional lights is ignored during shading. The direction
52 * in which the light shines is _the opposite_ of the forward vector of the
53 * entity's transform. In other words, directional lights shine backwards. This
54 * is done for consistency with the way cameras look at the scene. Add a depth
55 * camera components to the directional light to make it a shadow source.
56 *
57 * @param color The color of the light.
58 * @param intensity The intensity of the light, multiplied by the color.
59 */
60export function light_directional(color: Vec3 = [1, 1, 1], intensity: number = 1) {
61 return (game: Game, entity: Entity) => {
62 game.World.Signature[entity] |= Has.Light;
63 game.World.Light[entity] = {
64 Kind: LightKind.Directional,
65 Color: color,
66 Intensity: intensity,
67 };
68 };
69}
70
71export interface LightPoint {
72 Kind: LightKind.Point;
73 Color: Vec3;
74 Intensity: number;
75}
76
77/**
78 * Add `LightPoint` to an entity.
79 *
80 * The position of the entity is used as the position of the light during shading.
81 *
82 * @param color The color of the light.
83 * @param intensity The intensity of the light at 1 world unit away. The
84 * intensity of 1 results in 100% of the object's color being visible, adjusted for
85 * the angle. The intensity is attenuated exponentially.
86 */
87export function light_point(color: Vec3 = [1, 1, 1], intensity: number = 1) {
88 return (game: Game, entity: Entity) => {
89 game.World.Signature[entity] |= Has.Light;
90 game.World.Light[entity] = {
91 Kind: LightKind.Point,
92 Color: color,
93 Intensity: intensity,
94 };
95 };
96}
97
98/**
99 * Compute the radius of a light given the minimum desired intensity.
100 *
101 * @param base_intensity The base intensity of the light.
102 * @param min_intensity The minimum desired intensity at the computed radius.
103 */
104export function light_radius(base_intensity: number, min_intensity: number = 0.005) {
105 return (base_intensity / min_intensity) ** 0.5;
106}