mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 18:22:14 +00:00
[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:
@@ -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__]")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
Reference in New Issue
Block a user