21 FEB 2026

rahulmnavneeth

light system

homedocs

Location

include/mop/light.h   — Public types and API
src/core/light.c      — Light management and visual indicators

Overview

The light system supports up to MOP_MAX_LIGHTS (8) simultaneous lights per viewport. Each light is described by a MopLight struct that specifies type, position, direction, color, intensity, and attenuation parameters. Light slot 0 defaults to a directional light matching the legacy mop_viewport_set_light_dir() / set_ambient() behavior.

Types

MopLightType

typedef enum MopLightType {
    MOP_LIGHT_DIRECTIONAL = 0,
    MOP_LIGHT_POINT       = 1,
    MOP_LIGHT_SPOT        = 2,
} MopLightType;

MopLight

typedef struct MopLight {
    MopLightType type;
    MopVec3      position;       /* world space (point/spot) */
    MopVec3      direction;      /* normalized (directional/spot) */
    MopColor     color;          /* linear RGB */
    float        intensity;      /* multiplier */
    float        range;          /* attenuation cutoff (point/spot) */
    float        spot_inner_cos; /* cos(inner_cone_angle) */
    float        spot_outer_cos; /* cos(outer_cone_angle) */
    bool         active;
    bool         cast_shadows;   /* reserved for future use */
} MopLight;

Light Type Field Usage

Not all fields are meaningful for every light type. The table below shows which fields each type uses.

FieldDirectionalPointSpot
positionxx
directionxx
colorxxx
intensityxxx
rangexx
spot_inner_cosx
spot_outer_cosx

Functions

mop_viewport_add_light

MopLight *mop_viewport_add_light(MopViewport *vp, const MopLight *desc);

Add a light to the viewport by copying the provided descriptor into the first available slot. Returns a pointer to the internal light slot, or NULL if all MOP_MAX_LIGHTS slots are occupied. The returned pointer can be passed to the per-light setter functions.

mop_viewport_remove_light

void mop_viewport_remove_light(MopViewport *vp, MopLight *light);

Remove a light by setting its active flag to false. The slot becomes available for reuse by a subsequent mop_viewport_add_light call. Any associated light indicator mesh is destroyed on the next frame update.

mop_light_set_position

void mop_light_set_position(MopLight *l, MopVec3 pos);

Set the world-space position of a point or spot light. Has no visual effect on directional lights (which use only direction).

mop_light_set_direction

void mop_light_set_direction(MopLight *l, MopVec3 dir);

Set the normalized direction vector for a directional or spot light. The caller is responsible for providing a normalized vector.

mop_light_set_color

void mop_light_set_color(MopLight *l, MopColor color);

Set the linear RGB color of the light. Color is expected in linear space, not sRGB.

mop_light_set_intensity

void mop_light_set_intensity(MopLight *l, float intensity);

Set the intensity multiplier for the light. Final contribution is color * intensity.

mop_viewport_light_count

uint32_t mop_viewport_light_count(const MopViewport *vp);

Return the number of currently active lights in the viewport. This walks all MOP_MAX_LIGHTS slots and counts those with active == true.

Light Indicators

Each active light automatically creates a small visual indicator mesh in the viewport. These indicators are managed internally by mop_light_update_indicators(), which is called every frame.

Object ID Range

Light indicators use object IDs in the range 0xFFFE0000 to 0xFFFEFFFF. The object ID for light at slot index i is 0xFFFE0000 + i. This range sits between scene meshes (0x1--0xFFFDFFFF) and gizmo handles (0xFFFF0000--0xFFFFFFFF).

Indicator Geometry

Light TypeShapeDescription
DirectionalArrowCylinder + cone pointing along the light direction
PointOctahedronSmall octahedron at the light's world position
SpotConeOpen cone at the light's position, oriented along direction

Screen-Space Scaling

Indicators use the same screen-space scaling technique as gizmo handles. The scale factor is distance_to_camera * 0.12 (slightly smaller than gizmo handles at 0.18), clamped to a minimum of 0.03. This keeps indicators at a constant visual size regardless of camera distance.

Interaction

Light indicators are selectable via the picking system. Clicking an indicator selects it and shows a translate-only gizmo. Dragging the gizmo moves the light:

Transform changes emit a MOP_EVENT_LIGHT_CHANGED event with object_id set to 0xFFFE0000 + light_index. Rotate and scale modes are suppressed for light indicators.

Usage

/* Add a point light */
MopLight desc = {
    .type      = MOP_LIGHT_POINT,
    .position  = {2.0f, 3.0f, 1.0f},
    .color     = {1.0f, 0.9f, 0.8f, 1.0f},
    .intensity = 1.5f,
    .range     = 10.0f,
};
MopLight *light = mop_viewport_add_light(viewport, &desc);

/* Update at runtime */
mop_light_set_position(light, (MopVec3){4.0f, 3.0f, 1.0f});
mop_light_set_intensity(light, 2.0f);

/* Query active count */
uint32_t n = mop_viewport_light_count(viewport);

/* Remove when done */
mop_viewport_remove_light(viewport, light);