Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Adds lighting height control (space color consistency) #215

Merged
merged 1 commit into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#define COMSIG_ATOM_SET_LIGHT_ON "atom_set_light_on"
///Called right after the atom changes the value of light_on to a different one, from base of [/atom/proc/set_light_on]: (old_value)
#define COMSIG_ATOM_UPDATE_LIGHT_ON "atom_update_light_on"
///Called right before the atom changes the value of light_height to a different one, from base [atom/proc/set_light_height]: (new_value)
#define COMSIG_ATOM_SET_LIGHT_HEIGHT "atom_set_light_height"
///Called right after the atom changes the value of light_height to a different one, from base of [/atom/proc/set_light_height]: (old_value)
#define COMSIG_ATOM_UPDATE_LIGHT_HEIGHT "atom_update_light_height"
///Called right before the atom changes the value of light_flags to a different one, from base [atom/proc/set_light_flags]: (new_flags)
#define COMSIG_ATOM_SET_LIGHT_FLAGS "atom_set_light_flags"
///Called right after the atom changes the value of light_flags to a different one, from base of [/atom/proc/set_light_flags]: (old_flags)
Expand Down
4 changes: 4 additions & 0 deletions code/__DEFINES/lighting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#define LIGHTING_FALLOFF 1
/// use lambertian shading for light sources
#define LIGHTING_LAMBERTIAN 0
/// light UNDER the floor. primarily used for starlight, shouldn't fuck with this
#define LIGHTING_HEIGHT_SPACE -0.5
/// light ON the floor
#define LIGHTING_HEIGHT_FLOOR 0
/// height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
#define LIGHTING_HEIGHT 1
/// Value used to round lumcounts, values smaller than 1/129 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
Expand Down
2 changes: 1 addition & 1 deletion code/datums/materials/_material.dm
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ Simple datum which is instanced once per type and is used for every object of sa
if(!starlight_color)
on.RegisterSignal(SSdcs, COMSIG_STARLIGHT_COLOR_CHANGED, TYPE_PROC_REF(/turf, material_starlight_changed))
RegisterSignal(on, COMSIG_QDELETING, PROC_REF(lit_turf_deleted))
on.set_light(2, 0.75, starlight_color || GLOB.starlight_color)
on.set_light(2, 1, starlight_color || GLOB.starlight_color, l_height = LIGHTING_HEIGHT_SPACE)

/turf/proc/material_starlight_changed(datum/source, old_star, new_star)
if(light_color == old_star)
Expand Down
11 changes: 10 additions & 1 deletion code/game/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@
var/light_dir = NORTH
///Boolean variable for toggleable lights. Has no effect without the proper light_system, light_range and light_power values.
var/light_on = TRUE
/// How many tiles "up" this light is. 1 is typical, should only really change this if it's a floor light
var/light_height = LIGHTING_HEIGHT
///Bitflags to determine lighting-related atom properties.
var/light_flags = NONE
///Our light source. Don't fuck with this directly unless you have a good reason!
Expand Down Expand Up @@ -1300,8 +1302,15 @@
if(light_system == STATIC_LIGHT)
set_light(l_dir = var_value)
. = TRUE
if(NAMEOF(src, light_height))
if(light_system == STATIC_LIGHT)
set_light(l_height = var_value)
. = TRUE
if(NAMEOF(src, light_on))
set_light_on(var_value)
if(light_system == STATIC_LIGHT)
set_light(l_on = var_value)
else
set_light_on(var_value)
. = TRUE
if(NAMEOF(src, light_flags))
set_light_flags(var_value)
Expand Down
2 changes: 1 addition & 1 deletion code/game/turfs/open/floor/glass.dm
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
RegisterSignal(SSdcs, COMSIG_STARLIGHT_COLOR_CHANGED, PROC_REF(starlight_changed))
else
UnregisterSignal(SSdcs, COMSIG_STARLIGHT_COLOR_CHANGED)
set_light(2, 0.75, starlight_color || GLOB.starlight_color)
set_light(2, 1, starlight_color || GLOB.starlight_color, l_height = LIGHTING_HEIGHT_SPACE)

/turf/open/floor/glass/proc/starlight_changed(datum/source, old_star, new_star)
if(light_color == old_star)
Expand Down
3 changes: 2 additions & 1 deletion code/game/turfs/open/space/space.dm
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ GLOBAL_LIST_EMPTY(starlight)
run_later = TRUE
plane = PLANE_SPACE
layer = SPACE_LAYER
light_power = 0.75
light_power = 1
light_range = 2
light_color = COLOR_STARLIGHT
light_height = LIGHTING_HEIGHT_SPACE
light_on = FALSE
space_lit = TRUE
bullet_bounce_sound = null
Expand Down
3 changes: 2 additions & 1 deletion code/game/turfs/turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ GLOBAL_LIST_EMPTY(station_turfs)
icon = 'icons/turf/floors.dmi'
vis_flags = VIS_INHERIT_ID // Important for interaction with and visualization of openspace.
luminosity = 1

light_height = LIGHTING_HEIGHT_FLOOR

///what /mob/oranges_ear instance is already assigned to us as there should only ever be one.
///used for guaranteeing there is only one oranges_ear per turf when assigned, speeds up view() iteration
var/mob/oranges_ear/assigned_oranges_ear
Expand Down
17 changes: 16 additions & 1 deletion code/modules/lighting/lighting_atom.dm
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@

// The proc you should always use to set the light of this atom.
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_angle, l_dir, l_on)
/atom/proc/set_light(l_range, l_power, l_color = NONSENSICAL_VALUE, l_angle, l_dir, l_height, l_on)
// We null everything but l_dir, because we don't want to allow for modifications while frozen
if(light_flags & LIGHT_FROZEN)
l_range = null
l_power = null
l_color = null
l_on = null
l_angle = null
l_height = null

if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE)
l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players.
Expand All @@ -33,6 +34,9 @@
if(!isnull(l_on))
set_light_on(l_on)

if(!isnull(l_height))
set_light_height(l_height)

update_light()

/// Will update the light (duh).
Expand Down Expand Up @@ -167,6 +171,17 @@
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_ON, .)
return .

/// Setter for the height of our light
/atom/proc/set_light_height(new_value)
if(new_value == light_height || light_flags & LIGHT_FROZEN)
return
if(SEND_SIGNAL(src, COMSIG_ATOM_SET_LIGHT_HEIGHT, new_value) & COMPONENT_BLOCK_LIGHT_UPDATE)
return
. = light_height
light_height = new_value
SEND_SIGNAL(src, COMSIG_ATOM_UPDATE_LIGHT_HEIGHT, .)
return .

/// Setter for the light flags of this atom.
/atom/proc/set_light_flags(new_value)
if(new_value == light_flags || (light_flags & LIGHT_FROZEN && new_value & LIGHT_FROZEN))
Expand Down
24 changes: 15 additions & 9 deletions code/modules/lighting/lighting_source.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
var/light_range
/// The colour of the light, string, decomposed by parse_light_color()
var/light_color
/// The height of the light. The larger this is, the dimmer we'll start
var/light_height

// Variables for keeping track of the colour.
var/lum_r
Expand Down Expand Up @@ -216,20 +218,20 @@
/datum/light_source/proc/get_sheet(multiz = FALSE)
var/list/static/key_to_sheet = list()
var/range = max(1, light_range);
var/key = "[range]-[visual_offset]-[offset_x]-[offset_y]-[light_dir]-[light_angle]-[multiz]"
var/key = "[range]-[visual_offset]-[offset_x]-[offset_y]-[light_dir]-[light_angle]-[light_height]-[multiz]"
var/list/hand_back = key_to_sheet[key]
if(!hand_back)
if(multiz)
hand_back = generate_sheet_multiz(range, visual_offset, offset_x, offset_y, light_dir, light_angle)
hand_back = generate_sheet_multiz(range, visual_offset, offset_x, offset_y, light_dir, light_angle, light_height)
else
hand_back = generate_sheet(range, visual_offset, offset_x, offset_y, light_dir, light_angle)
hand_back = generate_sheet(range, visual_offset, offset_x, offset_y, light_dir, light_angle, light_height)
key_to_sheet[key] = hand_back
return hand_back

/// Returns a list of lists that encodes the light falloff of our source
/// Takes anything that impacts our generation as input
/// This function should be "pure", no side effects or reads from the source object
/datum/light_source/proc/generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, z_level = 0)
/datum/light_source/proc/generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, height, z_level = 0)
var/list/encode = list()
// How far away the turfs we get are, and how many there are are often not the same calculation
// So we need to include the visual offset, so we can ensure our sheet is large enough to accept all the distance differences
Expand All @@ -240,30 +242,30 @@
for(var/x in (-(bound_range) + x_offset - 0.5) to (bound_range + x_offset + 0.5))
var/list/row = list()
for(var/y in (-(bound_range) + y_offset - 0.5) to (bound_range + y_offset + 0.5))
row += falloff_at_coord(x, y, z_level, range, center_dir, light_angle)
row += falloff_at_coord(x, y, z_level, range, center_dir, angle, height)
encode += list(row)
return encode

/// Returns a THREE dimensional list of lists that encodes the lighting falloff of our source
/// Takes anything that impacts our generation as input
/// This function should be "pure", no side effects or reads from the passed object
/datum/light_source/proc/generate_sheet_multiz(range, visual_offset, x_offset, y_offset, center_dir, angle)
/datum/light_source/proc/generate_sheet_multiz(range, visual_offset, x_offset, y_offset, center_dir, angle, height)
var/list/encode = list()
var/z_range = SSmapping.max_plane_offset // Let's just be safe yeah?
for(var/z in -z_range to z_range)
var/list/sheet = generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, z)
var/list/sheet = generate_sheet(range, visual_offset, x_offset, y_offset, center_dir, angle, height, z)
encode += list(sheet)
return encode

/// Takes x y and z offsets from the source as input, alongside our source's range
/// Returns a value between 0 and 1, 0 being dark on that tile, 1 being fully lit
/datum/light_source/proc/falloff_at_coord(x, y, z, range, center_dir, angle)
/datum/light_source/proc/falloff_at_coord(x, y, z, range, center_dir, angle, height)
var/range_divisor = max(1, range)

// You may notice we use squares here even though there are three components
// Because z diffs are so functionally small, cubes and cube roots are too aggressive
// The larger the distance is, the less bright our light will be
var/multiplier = 1 - CLAMP01(sqrt(x ** 2 + y ** 2 + z ** 2 + LIGHTING_HEIGHT) / range_divisor)
var/multiplier = 1 - CLAMP01(sqrt(x ** 2 + y ** 2 + z ** 2 + height) / range_divisor)
if(angle >= 360 || angle <= 0)
return multiplier

Expand Down Expand Up @@ -428,6 +430,10 @@
light_angle = source_atom.light_angle
update = TRUE

if(source_atom.light_height != light_height)
light_height = source_atom.light_height
update = TRUE

var/list/visual_offsets = calculate_light_offset(visual_source)
if(visual_offsets[1] != offset_x || visual_offsets[2] != offset_y || source_turf != old_source_turf)
offset_x = visual_offsets[1]
Expand Down