[MIRROR] Micros the lighting subsystem (Saves a second of init) [MDB IGNORE] (#16461)

* Micros the lighting subsystem (Saves a second of init)

* Update stat_tracking.dm

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: Zonespace <41448081+Zonespace27@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-09-28 21:19:43 +02:00
committed by GitHub
parent bc982a87f6
commit 110fd07f34
9 changed files with 146 additions and 123 deletions

View File

@@ -38,11 +38,4 @@
} while(FALSE); \
usage = TICK_USAGE;
#define SET_COST_LINE(...) \
do { \
var/cost = TICK_USAGE; \
_costs["[__LINE__ ]"] += TICK_DELTA_TO_MS(cost - usage); \
_counting["[__LINE__ ]"] += 1; \
usage = TICK_USAGE; \
} while(FALSE)
#define SET_COST_LINE(...) SET_COST("[__LINE__]")

View File

@@ -25,13 +25,13 @@ SUBSYSTEM_DEF(lighting)
MC_SPLIT_TICK_INIT(3)
if(!init_tick_checks)
MC_SPLIT_TICK
var/list/queue = sources_queue
var/i = 0
for (i in 1 to length(queue))
var/datum/light_source/L = queue[i]
L.update_corners()
L.needs_update = LIGHTING_NO_UPDATE
if(init_tick_checks)

View File

@@ -4,10 +4,12 @@
// Mutable appearances are children of images, just so you know.
/mutable_appearance/New()
// Mutable appearances erase template vars on new, because they accept an appearance to copy as an arg
// If we have nothin to copy, we set the float plane
/mutable_appearance/New(mutable_appearance/to_copy)
..()
plane = FLOAT_PLANE // No clue why this is 0 by default yet images are on FLOAT_PLANE
// And yes this does have to be in the constructor, BYOND ignores it if you set it as a normal var
if(!to_copy)
plane = FLOAT_PLANE
/// Helper similar to image()
/proc/mutable_appearance(icon, icon_state = "", layer = FLOAT_LAYER, plane = FLOAT_PLANE, alpha = 255, appearance_flags = NONE)

View File

@@ -29,50 +29,48 @@
///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)
// Takes as an argument the coords to use as the bottom left (south west) of our corner
/datum/lighting_corner/New(x, y, z)
. = ..()
save_master(new_turf, turn(diagonal, 180))
var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction.
var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one.
src.x = x + 0.5
src.y = y + 0.5
x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5)
y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5)
// Alright. We're gonna take a set of coords, and from them do a loop clockwise
// To build out the turfs adjacent to us. This is pretty fast
var/turf/process_next = locate(x, y, z)
if(process_next)
master_SW = process_next
process_next.lighting_corner_NE = src
// Now, we go north!
process_next = get_step(process_next, NORTH)
else
// Yes this is slightly slower then having a guarenteeed turf, but there aren't many null turfs
// So this is pretty damn fast
process_next = locate(x, y + 1, z)
// 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/new_master_turf
// Ok, if we have a north turf, go there. otherwise, onto the next
if(process_next)
master_NW = process_next
process_next.lighting_corner_SE = src
// Now, TO THE EAST
process_next = get_step(process_next, EAST)
else
process_next = locate(x + 1, y + 1, z)
// Diagonal one is easy.
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)
// Etc etc
if(process_next)
master_NE = process_next
process_next.lighting_corner_SW = src
// Now, TO THE SOUTH AGAIN (SE)
process_next = get_step(process_next, SOUTH)
else
process_next = locate(x + 1, y, z)
// Now the horizontal one.
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.
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)
if (NORTHEAST)
master_NE = master
master.lighting_corner_SW = src
if (SOUTHEAST)
master_SE = master
master.lighting_corner_NW = src
if (SOUTHWEST)
master_SW = master
master.lighting_corner_NE = src
if (NORTHWEST)
master_NW = master
master.lighting_corner_SE = src
// anddd the last tile
if(process_next)
master_SE = process_next
process_next.lighting_corner_NW = src
/datum/lighting_corner/proc/self_destruct_if_idle()
if (!LAZYLEN(affecting))

View File

@@ -8,14 +8,18 @@
///the turf that our light is applied to
var/turf/affected_turf
// Global list of lighting underlays, indexed by z level
GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z)
/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
. = ..()
current_underlay = mutable_appearance(LIGHTING_ICON, "transparent", source.z, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM)
current_underlay = new(GLOB.default_lighting_underlays_by_z[source.z])
affected_turf = source
if (affected_turf.lighting_object)
@@ -25,6 +29,9 @@
affected_turf.lighting_object = src
affected_turf.luminosity = 0
// This path is really hot. this is faster
// Really this should be a global var or something, but lets not think about that yes?
if(CONFIG_GET(flag/starlight))
for(var/turf/open/space/space_tile in RANGE_TURFS(1, affected_turf))
space_tile.update_starlight()
@@ -54,6 +61,7 @@
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
var/turf/affected_turf = src.affected_turf
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
@@ -61,21 +69,6 @@
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 = red_corner.cache_r
var/rg = red_corner.cache_g
var/rb = red_corner.cache_b
var/gr = green_corner.cache_r
var/gg = green_corner.cache_g
var/gb = green_corner.cache_b
var/br = blue_corner.cache_r
var/bg = blue_corner.cache_g
var/bb = blue_corner.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
@@ -85,28 +78,28 @@
var/set_luminosity = max > 1e-6
#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
var/mutable_appearance/current_underlay = src.current_underlay
affected_turf.underlays -= current_underlay
if(red_corner.cache_r & green_corner.cache_r & blue_corner.cache_r & alpha_corner.cache_r && \
(red_corner.cache_g + green_corner.cache_g + blue_corner.cache_g + alpha_corner.cache_g + \
red_corner.cache_b + green_corner.cache_b + blue_corner.cache_b + alpha_corner.cache_b == 8))
//anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
current_underlay.icon_state = "lighting_transparent"
current_underlay.color = null
affected_turf.underlays += current_underlay
else if(!set_luminosity)
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "lighting_dark"
current_underlay.color = null
affected_turf.underlays += current_underlay
else
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,
ar, ag, ab, 00,
red_corner.cache_r, red_corner.cache_g, red_corner.cache_b, 00,
green_corner.cache_r, green_corner.cache_g, green_corner.cache_b, 00,
blue_corner.cache_r, blue_corner.cache_g, blue_corner.cache_b, 00,
alpha_corner.cache_r, alpha_corner.cache_g, alpha_corner.cache_b, 00,
00, 00, 00, 01
)
// Of note. Most of the cost in this proc is here, I think because color matrix'd underlays DO NOT cache well, which is what adding to underlays does
// We use underlays because objects on each tile would fuck with maptick. if that ever changes, use an object for this instead
affected_turf.underlays += current_underlay
affected_turf.luminosity = set_luminosity

View File

@@ -4,6 +4,7 @@
if(!A.static_lighting)
continue
// I hate this so much dude. why do areas not track their turfs lummyyyyyyy
for(var/turf/T in A)
if(T.always_lit)
continue

View File

@@ -140,31 +140,53 @@
// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line.
// As such this all gets counted as a single line.
// The braces and semicolons are there to be able to do this on a single line.
#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range)))
// This exists so we can cache the vars used in this macro, and save MASSIVE time :)
// Most of this is saving off datum var accesses, tho some of it does actually cache computation
// You will NEED to call this before you call APPLY_CORNER
#define SETUP_CORNERS_CACHE(lighting_source) \
var/_turf_x = lighting_source.pixel_turf.x; \
var/_turf_y = lighting_source.pixel_turf.y; \
var/_range_divisor = max(1, lighting_source.light_range); \
var/_light_power = lighting_source.light_power; \
var/_applied_lum_r = lighting_source.applied_lum_r; \
var/_applied_lum_g = lighting_source.applied_lum_g; \
var/_applied_lum_b = lighting_source.applied_lum_b; \
var/_lum_r = lighting_source.lum_r; \
var/_lum_g = lighting_source.lum_g; \
var/_lum_b = lighting_source.lum_b; \
#define SETUP_CORNERS_REMOVAL_CACHE(lighting_source) \
var/_applied_lum_r = lighting_source.applied_lum_r; \
var/_applied_lum_g = lighting_source.applied_lum_g; \
var/_applied_lum_b = lighting_source.applied_lum_b;
#define LUM_FALLOFF(C) (1 - CLAMP01(sqrt((C.x - _turf_x) ** 2 + (C.y - _turf_y) ** 2 + LIGHTING_HEIGHT) / _range_divisor))
#define APPLY_CORNER(C) \
. = LUM_FALLOFF(C, pixel_turf); \
. *= light_power; \
. = LUM_FALLOFF(C); \
. *= _light_power; \
var/OLD = effect_str[C]; \
\
C.update_lumcount \
( \
(. * lum_r) - (OLD * applied_lum_r), \
(. * lum_g) - (OLD * applied_lum_g), \
(. * lum_b) - (OLD * applied_lum_b) \
(. * _lum_r) - (OLD * _applied_lum_r), \
(. * _lum_g) - (OLD * _applied_lum_g), \
(. * _lum_b) - (OLD * _applied_lum_b) \
); \
#define REMOVE_CORNER(C) \
. = -effect_str[C]; \
C.update_lumcount \
( \
. * applied_lum_r, \
. * applied_lum_g, \
. * applied_lum_b \
. * _applied_lum_r, \
. * _applied_lum_g, \
. * _applied_lum_b \
);
/// This is the define used to calculate falloff.
/datum/light_source/proc/remove_lum()
SETUP_CORNERS_REMOVAL_CACHE(src)
applied = FALSE
for (var/datum/lighting_corner/corner as anything in effect_str)
REMOVE_CORNER(corner)
@@ -173,6 +195,7 @@
effect_str = null
/datum/light_source/proc/recalc_corner(datum/lighting_corner/corner)
SETUP_CORNERS_CACHE(src)
LAZYINITLIST(effect_str)
if (effect_str[corner]) // Already have one.
REMOVE_CORNER(corner)
@@ -182,6 +205,22 @@
effect_str[corner] = .
// Keep in mind. Lighting corners accept the bottom left (northwest) set of cords to them as input
#define GENERATE_MISSING_CORNERS(gen_for) \
if (!gen_for.lighting_corner_NE) { \
gen_for.lighting_corner_NE = new /datum/lighting_corner(gen_for.x, gen_for.y, gen_for.z); \
} \
if (!gen_for.lighting_corner_SE) { \
gen_for.lighting_corner_SE = new /datum/lighting_corner(gen_for.x, gen_for.y - 1, gen_for.z); \
} \
if (!gen_for.lighting_corner_SW) { \
gen_for.lighting_corner_SW = new /datum/lighting_corner(gen_for.x - 1, gen_for.y - 1, gen_for.z); \
} \
if (!gen_for.lighting_corner_NW) { \
gen_for.lighting_corner_NW = new /datum/lighting_corner(gen_for.x - 1, gen_for.y, gen_for.z); \
} \
gen_for.lighting_corners_initialised = TRUE;
/datum/light_source/proc/update_corners()
var/update = FALSE
var/atom/source_atom = src.source_atom
@@ -244,24 +283,27 @@
return //nothing's changed
var/list/datum/lighting_corner/corners = list()
var/list/turf/turfs = list()
if (source_turf)
var/oldlum = source_turf.luminosity
source_turf.luminosity = CEILING(light_range, 1)
for(var/turf/T in view(CEILING(light_range, 1), source_turf))
if(!IS_OPAQUE_TURF(T))
if(IS_OPAQUE_TURF(T))
continue
if (!T.lighting_corners_initialised)
T.generate_missing_corners()
GENERATE_MISSING_CORNERS(T)
corners[T.lighting_corner_NE] = 0
corners[T.lighting_corner_SE] = 0
corners[T.lighting_corner_SW] = 0
corners[T.lighting_corner_NW] = 0
turfs += T
source_turf.luminosity = oldlum
var/list/datum/lighting_corner/new_corners = (corners - effect_str)
LAZYINITLIST(effect_str)
SETUP_CORNERS_CACHE(src)
var/list/datum/lighting_corner/new_corners = (corners - src.effect_str)
LAZYINITLIST(src.effect_str)
var/list/effect_str = src.effect_str
if (needs_update == LIGHTING_VIS_UPDATE)
for (var/datum/lighting_corner/corner as anything in new_corners)
APPLY_CORNER(corner)
@@ -274,7 +316,8 @@
if (. != 0)
LAZYADD(corner.affecting, src)
effect_str[corner] = .
// New corners are a subset of corners. so if they're both the same length, there are NO old corners!
if(length(corners) != length(new_corners))
for (var/datum/lighting_corner/corner as anything in corners - new_corners) // Existing corners
APPLY_CORNER(corner)
if (. != 0)
@@ -293,9 +336,12 @@
applied_lum_g = lum_g
applied_lum_b = lum_b
UNSETEMPTY(effect_str)
UNSETEMPTY(src.effect_str)
#undef EFFECT_UPDATE
#undef LUM_FALLOFF
#undef REMOVE_CORNER
#undef APPLY_CORNER
#undef SETUP_CORNERS_REMOVAL_CACHE
#undef SETUP_CORNERS_CACHE
#undef GENERATE_MISSING_CORNERS

View File

@@ -100,17 +100,3 @@
else
lighting_clear_overlay()
/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

View File

@@ -18,4 +18,8 @@
else // in case a single trait is passed in
SSmapping.z_trait_levels[new_traits] += list(new_z)
if(length(GLOB.default_lighting_underlays_by_z) < z_value)
GLOB.default_lighting_underlays_by_z.len = z_value
GLOB.default_lighting_underlays_by_z[z_value] = mutable_appearance(LIGHTING_ICON, "transparent", new_z, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM)
set_linkage(new_traits[ZTRAIT_LINKAGE])