Turns lighting objects into a datum, makes all lighting be performed with an underlay. big maptick fix very good! (#58991)

credit to zewaka for the idea of using underlays

turns the lighting object movables that were unnecessary and increased maptick into a datum which then applies and removes an underlay in update(). also applies a lot of general lighting clean ups (mostly using as anything in loops and fixing single letter var names).

multiz is a little different by necessity, now only the bottom turf's lighting matters in the brightness of the top turf unlike master where the bottom turf's lighting object is hidden from the vis_contents of the top turf. there are still some kinks to iron out here though, since currently objects suspended in openspace (like tram platforms) look bad and glass floors look bad too

only thing i have left to do is make multiz work (well)

UPDATE: multiz now appears the same as far as i can tell, its possible there are other situations in which its different but datum mats work and it automatically updates if the turf below changes. now i just need to make the system less finnicky if at all possible (and possibly merge managed_turf_vis_content with managed_overlays maybe?)

new update: its basically equivalent to normal multiz as far as i can tell (visually at least, in the circumstances ive tested so far)

NEW NEW UPDATE: turfs no longer have the VIS_HIDE vis_flag and multiz works without stacking the lighting from the floor below! so this shouldnt have any overt drawbacks to master anymore

1 needless movable per tile is terrible for maptick. this is probably a larger improvement than my emissive blocker change in terms of maptick. im guessing we'd get around 0.6 average maptick per player after this where currently we get 0.85 or so

Edit: according to lemon, sybil reached 0.71 maptick per person when tm'd with this

if this is a big enough improvement i might finally be able to get rid of the Gone discord avatar
This commit is contained in:
Kylerace
2021-06-12 21:37:29 -07:00
committed by GitHub
parent 27604af0d1
commit d3a1bea859
27 changed files with 181 additions and 207 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
/area
luminosity = TRUE
luminosity = TRUE
var/dynamic_lighting = DYNAMIC_LIGHTING_ENABLED
/area/proc/set_dynamic_lighting(new_dynamic_lighting = DYNAMIC_LIGHTING_ENABLED)
+2 -5
View File
@@ -83,11 +83,8 @@
/atom/movable/Moved(atom/OldLoc, Dir)
. = ..()
var/datum/light_source/L
var/thing
for (thing in light_sources) // Cycle through the light sources on this atom and tell them to update.
L = thing
L.source_atom.update_light()
for (var/datum/light_source/light as anything in light_sources) // Cycle through the light sources on this atom and tell them to update.
light.source_atom.update_light()
/atom/proc/flash_lighting_fx(_range = FLASH_LIGHT_RANGE, _power = FLASH_LIGHT_POWER, _color = COLOR_WHITE, _duration = FLASH_LIGHT_DURATION)
+32 -28
View File
@@ -2,29 +2,32 @@
// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't).
// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting.
/datum/lighting_corner
var/list/datum/light_source/affecting // Light sources affecting us.
var/x = 0
var/y = 0
var/x = 0
var/y = 0
var/turf/master_NE
var/turf/master_SE
var/turf/master_SW
var/turf/master_NW
//"raw" color values, changed by update_lumcount()
var/lum_r = 0
var/lum_g = 0
var/lum_b = 0
var/needs_update = FALSE
//true color values, guaranteed to be between 0 and 1
var/cache_r = LIGHTING_SOFT_THRESHOLD
var/cache_g = LIGHTING_SOFT_THRESHOLD
var/cache_b = LIGHTING_SOFT_THRESHOLD
var/cache_r = LIGHTING_SOFT_THRESHOLD
var/cache_g = LIGHTING_SOFT_THRESHOLD
var/cache_b = LIGHTING_SOFT_THRESHOLD
var/cache_mx = 0
///the maximum of lum_r, lum_g, and lum_b. if this is > 1 then the three cached color values are divided by this
var/largest_color_luminosity = 0
///whether we are to be added to SSlighting's corners_queue list for an update
var/needs_update = FALSE
/datum/lighting_corner/New(turf/new_turf, diagonal)
. = ..()
@@ -39,22 +42,22 @@
// My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal).
// Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered.
// So we'll have this hardcode instead.
var/turf/T
var/turf/new_master_turf
// Diagonal one is easy.
T = get_step(new_turf, diagonal)
if (T) // In case we're on the map's border.
save_master(T, diagonal)
new_master_turf = get_step(new_turf, diagonal)
if (new_master_turf) // In case we're on the map's border.
save_master(new_master_turf, diagonal)
// Now the horizontal one.
T = get_step(new_turf, horizontal)
if (T) // Ditto.
save_master(T, ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
new_master_turf = get_step(new_turf, horizontal)
if (new_master_turf) // Ditto.
save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
// And finally the vertical one.
T = get_step(new_turf, vertical)
if (T)
save_master(T, ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
new_master_turf = get_step(new_turf, vertical)
if (new_master_turf)
save_master(new_master_turf, ((new_master_turf.x > x) ? EAST : WEST) | ((new_master_turf.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates.
/datum/lighting_corner/proc/save_master(turf/master, dir)
switch (dir)
@@ -101,13 +104,13 @@
var/lum_r = src.lum_r
var/lum_g = src.lum_g
var/lum_b = src.lum_b
var/mx = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1.
var/largest_color_luminosity = max(lum_r, lum_g, lum_b) // Scale it so one of them is the strongest lum, if it is above 1.
. = 1 // factor
if (mx > 1)
. = 1 / mx
if (largest_color_luminosity > 1)
. = 1 / largest_color_luminosity
#if LIGHTING_SOFT_THRESHOLD != 0
else if (mx < LIGHTING_SOFT_THRESHOLD)
else if (largest_color_luminosity < LIGHTING_SOFT_THRESHOLD)
. = 0 // 0 means soft lighting.
cache_r = round(lum_r * ., LIGHTING_ROUND_VALUE) || LIGHTING_SOFT_THRESHOLD
@@ -118,23 +121,24 @@
cache_g = round(lum_g * ., LIGHTING_ROUND_VALUE)
cache_b = round(lum_b * ., LIGHTING_ROUND_VALUE)
#endif
cache_mx = round(mx, LIGHTING_ROUND_VALUE)
var/atom/movable/lighting_object/lighting_object = master_NE?.lighting_object
src.largest_color_luminosity = round(largest_color_luminosity, LIGHTING_ROUND_VALUE)
var/datum/lighting_object/lighting_object = master_NE?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_SE?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_SW?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
SSlighting.objects_queue += lighting_object
lighting_object = master_NW?.lighting_object
if (lighting_object && !lighting_object.needs_update)
lighting_object.needs_update = TRUE
+64 -100
View File
@@ -1,64 +1,48 @@
/atom/movable/lighting_object
name = ""
anchored = TRUE
icon = LIGHTING_ICON
icon_state = "transparent"
color = null //we manually set color in init instead
plane = LIGHTING_PLANE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
invisibility = INVISIBILITY_LIGHTING
vis_flags = VIS_HIDE
/datum/lighting_object
///the underlay we are currently applying to our turf to apply light
var/mutable_appearance/current_underlay
///whether we are already in the SSlighting.objects_queue list
var/needs_update = FALSE
var/turf/myturf
/atom/movable/lighting_object/Initialize(mapload)
///the turf that our light is applied to
var/turf/affected_turf
/datum/lighting_object/New(turf/source)
if(!isturf(source))
qdel(src, force=TRUE)
stack_trace("a lighting object was assigned to [source], a non turf! ")
return
. = ..()
verbs.Cut()
//We avoid setting this in the base as if we do then the parent atom handling will add_atom_color it and that
//is totally unsuitable for this object, as we are always changing it's colour manually
color = LIGHTING_BASE_MATRIX
myturf = loc
if (myturf.lighting_object)
qdel(myturf.lighting_object, force = TRUE)
myturf.lighting_object = src
myturf.luminosity = 0
current_underlay = mutable_appearance(LIGHTING_ICON, "transparent", source.z, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM)
for(var/turf/open/space/S in RANGE_TURFS(1, src)) //RANGE_TURFS is in code\__HELPERS\game.dm
S.update_starlight()
affected_turf = source
if (affected_turf.lighting_object)
qdel(affected_turf.lighting_object, force = TRUE)
stack_trace("a lighting object was assigned to a turf that already had a lighting object!")
affected_turf.lighting_object = src
affected_turf.luminosity = 0
for(var/turf/open/space/space_tile in RANGE_TURFS(1, affected_turf))
space_tile.update_starlight()
needs_update = TRUE
SSlighting.objects_queue += src
/atom/movable/lighting_object/Destroy(force)
if (force)
SSlighting.objects_queue -= src
if (loc != myturf)
var/turf/oldturf = get_turf(myturf)
var/turf/newturf = get_turf(loc)
stack_trace("A lighting object was qdeleted with a different loc then it is suppose to have ([COORD(oldturf)] -> [COORD(newturf)])")
if (isturf(myturf))
myturf.lighting_object = null
myturf.luminosity = 1
myturf = null
return ..()
else
/datum/lighting_object/Destroy(force)
if (!force)
return QDEL_HINT_LETMELIVE
SSlighting.objects_queue -= src
if (isturf(affected_turf))
affected_turf.lighting_object = null
affected_turf.luminosity = 1
affected_turf.underlays -= current_underlay
affected_turf = null
return ..()
/atom/movable/lighting_object/proc/update()
if (loc != myturf)
if (loc)
var/turf/oldturf = get_turf(myturf)
var/turf/newturf = get_turf(loc)
warning("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!")
qdel(src, TRUE)
return
/datum/lighting_object/proc/update()
// To the future coder who sees this and thinks
// "Why didn't he just use a loop?"
@@ -68,31 +52,30 @@
// Oh it's also shorter line wise.
// Including with these comments.
// See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are.
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
var/datum/lighting_corner/cr = myturf.lighting_corner_SW || dummy_lighting_corner
var/datum/lighting_corner/cg = myturf.lighting_corner_SE || dummy_lighting_corner
var/datum/lighting_corner/cb = myturf.lighting_corner_NW || dummy_lighting_corner
var/datum/lighting_corner/ca = myturf.lighting_corner_NE || dummy_lighting_corner
var/datum/lighting_corner/red_corner = affected_turf.lighting_corner_SW || dummy_lighting_corner
var/datum/lighting_corner/green_corner = affected_turf.lighting_corner_SE || dummy_lighting_corner
var/datum/lighting_corner/blue_corner = affected_turf.lighting_corner_NW || dummy_lighting_corner
var/datum/lighting_corner/alpha_corner = affected_turf.lighting_corner_NE || dummy_lighting_corner
var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
var/max = max(red_corner.largest_color_luminosity, green_corner.largest_color_luminosity, blue_corner.largest_color_luminosity, alpha_corner.largest_color_luminosity)
var/rr = cr.cache_r
var/rg = cr.cache_g
var/rb = cr.cache_b
var/rr = red_corner.cache_r
var/rg = red_corner.cache_g
var/rb = red_corner.cache_b
var/gr = cg.cache_r
var/gg = cg.cache_g
var/gb = cg.cache_b
var/gr = green_corner.cache_r
var/gg = green_corner.cache_g
var/gb = green_corner.cache_b
var/br = cb.cache_r
var/bg = cb.cache_g
var/bb = cb.cache_b
var/br = blue_corner.cache_r
var/bg = blue_corner.cache_g
var/bb = blue_corner.cache_b
var/ar = ca.cache_r
var/ag = ca.cache_g
var/ab = ca.cache_b
var/ar = alpha_corner.cache_r
var/ag = alpha_corner.cache_g
var/ab = alpha_corner.cache_b
#if LIGHTING_SOFT_THRESHOLD != 0
var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD
@@ -103,15 +86,20 @@
#endif
if((rr & gr & br & ar) && (rg + gg + bg + ag + rb + gb + bb + ab == 8))
//anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
icon_state = "transparent"
color = null
//anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "transparent"
current_underlay.color = null
affected_turf.underlays += current_underlay
else if(!set_luminosity)
icon_state = "dark"
color = null
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "dark"
current_underlay.color = null
affected_turf.underlays += current_underlay
else
icon_state = null
color = list(
affected_turf.underlays -= current_underlay
current_underlay.icon_state = null
current_underlay.color = list(
rr, rg, rb, 00,
gr, gg, gb, 00,
br, bg, bb, 00,
@@ -119,30 +107,6 @@
00, 00, 00, 01
)
luminosity = set_luminosity
affected_turf.underlays += current_underlay
// Variety of overrides so the overlays don't get affected by weird things.
/atom/movable/lighting_object/ex_act(severity)
return FALSE
/atom/movable/lighting_object/singularity_act()
return
/atom/movable/lighting_object/singularity_pull()
return
/atom/movable/lighting_object/blob_act()
return
/atom/movable/lighting_object/onTransitZ()
return
/atom/movable/lighting_object/wash(clean_types)
SHOULD_CALL_PARENT(FALSE) // lighting objects are dirty, confirmed
return
// Override here to prevent things accidentally moving around overlays.
/atom/movable/lighting_object/forceMove(atom/destination, no_tp=FALSE, harderforce = FALSE)
if(harderforce)
. = ..()
affected_turf.luminosity = set_luminosity
+2 -1
View File
@@ -1,3 +1,4 @@
/proc/create_all_lighting_objects()
for(var/area/A in world)
if(!IS_DYNAMIC_LIGHTING(A))
@@ -8,6 +9,6 @@
if(!IS_DYNAMIC_LIGHTING(T))
continue
new/atom/movable/lighting_object(T)
new/datum/lighting_object(T)
CHECK_TICK
CHECK_TICK
+32 -23
View File
@@ -2,14 +2,21 @@
// These are the main datums that emit light.
/datum/light_source
var/atom/top_atom // The atom we're emitting light from (for example a mob if we're from a flashlight that's being held).
var/atom/source_atom // The atom that we belong to.
///The atom we're emitting light from (for example a mob if we're from a flashlight that's being held).
var/atom/top_atom
///The atom that we belong to.
var/atom/source_atom
var/turf/source_turf // The turf under the above.
var/turf/pixel_turf // The turf the top_atom appears to over.
var/light_power // Intensity of the emitter light.
var/light_range // The range of the emitted light.
var/light_color // The colour of the light, string, decomposed by parse_light_color()
///The turf under the source atom.
var/turf/source_turf
///The turf the top_atom appears to over.
var/turf/pixel_turf
///Intensity of the emitter light.
var/light_power
/// The range of the emitted light.
var/light_range
/// The colour of the light, string, decomposed by parse_light_color()
var/light_color
// Variables for keeping track of the colour.
var/lum_r
@@ -21,11 +28,14 @@
var/tmp/applied_lum_g
var/tmp/applied_lum_b
var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners.
/// List used to store how much we're affecting corners.
var/list/datum/lighting_corner/effect_str
var/applied = FALSE // Whether we have applied our light yet or not.
/// Whether we have applied our light yet or not.
var/applied = FALSE
var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update.
/// whether we are to be added to SSlighting's sources_queue list for an update
var/needs_update = LIGHTING_NO_UPDATE
/datum/light_source/New(atom/owner, atom/top)
@@ -124,8 +134,7 @@
. * applied_lum_b \
);
// This is the define used to calculate falloff.
/// This is the define used to calculate falloff.
/datum/light_source/proc/remove_lum()
applied = FALSE
for (var/datum/lighting_corner/corner as anything in effect_str)
@@ -134,14 +143,14 @@
effect_str = null
/datum/light_source/proc/recalc_corner(datum/lighting_corner/C)
/datum/light_source/proc/recalc_corner(datum/lighting_corner/corner)
LAZYINITLIST(effect_str)
if (effect_str[C]) // Already have one.
REMOVE_CORNER(C)
effect_str[C] = 0
if (effect_str[corner]) // Already have one.
REMOVE_CORNER(corner)
effect_str[corner] = 0
APPLY_CORNER(C)
effect_str[C] = .
APPLY_CORNER(corner)
effect_str[corner] = .
/datum/light_source/proc/update_corners()
@@ -178,9 +187,9 @@
pixel_turf = get_turf_pixel(top_atom)
update = TRUE
else
var/P = get_turf_pixel(top_atom)
if (P != pixel_turf)
pixel_turf = P
var/pixel_loc = get_turf_pixel(top_atom)
if (pixel_loc != pixel_turf)
pixel_turf = pixel_loc
update = TRUE
if (!isturf(source_turf))
@@ -206,7 +215,7 @@
return //nothing's changed
var/list/datum/lighting_corner/corners = list()
var/list/turf/turfs = list()
var/list/turf/turfs = list()
if (source_turf)
var/oldlum = source_turf.luminosity
@@ -246,7 +255,7 @@
effect_str -= corner
var/list/datum/lighting_corner/gone_corners = effect_str - corners
for (var/datum/lighting_corner/corner as anything in gone_corners)
for (var/datum/lighting_corner/corner as anything in gone_corners)
REMOVE_CORNER(corner)
LAZYREMOVE(corner.affecting, src)
effect_str -= gone_corners
+12 -13
View File
@@ -7,18 +7,18 @@
/turf/proc/lighting_clear_overlay()
if (lighting_object)
qdel(lighting_object, TRUE)
qdel(lighting_object, force=TRUE)
// Builds a lighting object for us, but only if our area is dynamic.
/turf/proc/lighting_build_overlay()
if (lighting_object)
qdel(lighting_object,force=TRUE) //Shitty fix for lighting objects persisting after death
qdel(lighting_object, force=TRUE) //Shitty fix for lighting objects persisting after death
var/area/A = loc
if (!IS_DYNAMIC_LIGHTING(A) && !light_sources)
var/area/our_area = loc
if (!IS_DYNAMIC_LIGHTING(our_area) && !light_sources)
return
new/atom/movable/lighting_object(src)
new/datum/lighting_object(src)
// Used to get a scaled lumcount.
/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
@@ -39,7 +39,7 @@
L = lighting_corner_NW
if (L)
totallums += L.lum_r + L.lum_b + L.lum_g
totallums /= 12 // 4 corners, each with 3 channels, get the average.
@@ -57,7 +57,7 @@
if (!lighting_object)
return FALSE
return !(lighting_object.luminosity || dynamic_lumcount)
return !(luminosity || dynamic_lumcount)
///Proc to add movable sources of opacity on the turf and let it handle lighting code.
@@ -85,8 +85,7 @@
reconsider_lights()
return
directional_opacity = NONE
for(var/am in opacity_sources)
var/atom/movable/opacity_source = am
for(var/atom/movable/opacity_source as anything in opacity_sources)
if(opacity_source.flags_1 & ON_BORDER_1)
directional_opacity |= opacity_source.dir
else //If fulltile and opaque, then the whole tile blocks view, no need to continue checking.
@@ -107,14 +106,14 @@
/turf/proc/generate_missing_corners()
if (!lighting_corner_NE)
lighting_corner_NE = new/datum/lighting_corner(src, NORTH|EAST)
if (!lighting_corner_SE)
lighting_corner_SE = new/datum/lighting_corner(src, SOUTH|EAST)
if (!lighting_corner_SW)
lighting_corner_SW = new/datum/lighting_corner(src, SOUTH|WEST)
if (!lighting_corner_NW)
lighting_corner_NW = new/datum/lighting_corner(src, NORTH|WEST)
lighting_corners_initialised = TRUE