[MIRROR] Micro-opt lighting (#9268)

Co-authored-by: ShadowLarkens <shadowlarkens@gmail.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2
2024-11-21 05:12:08 -07:00
committed by GitHub
parent 00968f9feb
commit a0840b571c
6 changed files with 130 additions and 125 deletions

View File

@@ -1,6 +1,6 @@
SUBSYSTEM_DEF(lighting)
name = "Lighting"
wait = 2
wait = 1 // CHOMPEdit
init_order = INIT_ORDER_LIGHTING
flags = SS_TICKER
runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY //CHOMPEdit Do some work during lobby waiting period. May as well.

View File

@@ -30,37 +30,49 @@
///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)
/datum/lighting_corner/New(x, y, z, dynamic) // CHOMPEdit
. = ..()
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.
// anddd the last tile
if(process_next)
master_SE = process_next
process_next.lighting_corner_NW = src
// 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.
if(((SSplanets && SSplanets.z_to_planet.len >= new_turf.z && SSplanets.z_to_planet[new_turf.z]) || SSlighting.get_pshandler_z(new_turf.z)) && new_turf.has_dynamic_lighting()) sunlight = SUNLIGHT_POSSIBLE //CHOMPEdit
if(((SSplanets && SSplanets.z_to_planet.len >= z && SSplanets.z_to_planet[z]) || SSlighting.get_pshandler_z(z)) && dynamic) sunlight = SUNLIGHT_POSSIBLE //CHOMPEdit
/datum/lighting_corner/proc/save_master(turf/master, dir)
switch (dir)

View File

@@ -61,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
@@ -68,22 +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
#else
@@ -92,31 +77,31 @@
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 = "transparent"
current_underlay.color = null
affected_turf.underlays |= current_underlay
else if(!set_luminosity)
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "dark"
current_underlay.color = null
affected_turf.underlays |= current_underlay
else
affected_turf.underlays -= current_underlay
current_underlay.icon_state = "gradient"
current_underlay.color = null //CHOMPEdit
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
)
affected_turf.underlays |= current_underlay
// 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.set_luminosity(set_luminosity)
/datum/lighting_object/proc/removefromturf()

View File

@@ -111,28 +111,44 @@
// 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.
// /tg/ falloff alg
#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; \
// Bay/Polaris falloff alg
//#define LUM_FALLOFF(C, T)(1 - CLAMP01(((C.x - T.x) ** 2 +(C.y - T.y) ** 2 + LIGHTING_HEIGHT) ** 0.6 / max(1, light_range)))
#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) \
); \
//CHOMPEdit Begin
#define APPLY_CORNER_NEW(C) \
. = LUM_FALLOFF(C, pixel_turf); \
. *= light_power; \
. = LUM_FALLOFF(C); \
. *= _light_power; \
var/OLD = effect_str[C]; \
if (. != 0){ \
LAZYADD(C.affecting, src); \
@@ -140,21 +156,22 @@
} \
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) \
); \
//CHOMPEdit End
#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 \
);
/datum/light_source/proc/remove_lum()
SETUP_CORNERS_REMOVAL_CACHE(src)
applied = FALSE
for (var/datum/lighting_corner/corner as anything in effect_str)
LAZYREMOVE(corner.affecting, src) //CHOMPEdit
@@ -163,6 +180,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)
@@ -174,6 +192,24 @@
/datum/light_source/proc/get_turfs_in_range()
return view(CEILING(light_range, 1), source_turf)
// Keep in mind. Lighting corners accept the bottom left (northwest) set of cords to them as input
//CHOMPEdit Start Dynamic light
#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, gen_for.has_dynamic_lighting()); \
} \
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, gen_for.has_dynamic_lighting()); \
} \
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, gen_for.has_dynamic_lighting()); \
} \
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.has_dynamic_lighting()); \
} \
gen_for.lighting_corners_initialised = TRUE;
//CHOMPEdit End
/datum/light_source/proc/update_corners()
var/update = FALSE
var/atom/source_atom = src.source_atom
@@ -236,24 +272,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 get_turfs_in_range())
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 in new_corners) //CHOMPEdit
//CHOMPEdit Begin
@@ -267,8 +306,8 @@
for (var/datum/lighting_corner/corner in corners - new_corners) // Existing corners //CHOMPEdit
//CHOMPEdit Begin
. = LUM_FALLOFF(corner, pixel_turf);
. *= light_power;
. = LUM_FALLOFF(corner);
. *= _light_power;
var/OLD = effect_str[corner];
if (. != 0)
effect_str[corner] = .
@@ -277,9 +316,9 @@
effect_str -= corner
corner.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) \
);
//CHOMPEdit End
@@ -293,9 +332,11 @@
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

View File

@@ -142,38 +142,3 @@
/turf/proc/has_dynamic_lighting()
var/area/A = loc
return (IS_DYNAMIC_LIGHTING(src) && IS_DYNAMIC_LIGHTING(A))
/turf/proc/generate_missing_corners()
//CHOMPEdit Begin
var/turf/n = get_step(src,NORTH)
var/turf/s = get_step(src,SOUTH)
var/turf/w = get_step(src,WEST)
var/turf/e = get_step(src,EAST)
if (!lighting_corner_NE)
if(n && n.lighting_corner_SE)
lighting_corner_NE = n.lighting_corner_SE
else
lighting_corner_NE = new/datum/lighting_corner(src, NORTH|EAST)
if (!lighting_corner_SE)
if(e && e.lighting_corner_SW)
lighting_corner_SE = e.lighting_corner_SW
else
lighting_corner_SE = new/datum/lighting_corner(src, SOUTH|EAST)
if (!lighting_corner_SW)
if(s && s.lighting_corner_NW)
lighting_corner_SW = s.lighting_corner_NW
else
lighting_corner_SW = new/datum/lighting_corner(src, SOUTH|WEST)
if (!lighting_corner_NW)
if(w && w.lighting_corner_NE)
lighting_corner_NW = s.lighting_corner_NE
else
lighting_corner_NW = new/datum/lighting_corner(src, NORTH|WEST)
//CHOMPEdit End
lighting_corners_initialised = TRUE

View File

@@ -53,7 +53,7 @@
//Moved initialization here to make sure that it doesn't happen too early when replacing turfs.
/datum/sunlight_handler/proc/manualInit()
if(!holder.lighting_corners_initialised)
holder.generate_missing_corners()
GENERATE_MISSING_CORNERS(holder)
var/corners = list(holder.lighting_corner_NE,holder.lighting_corner_NW,holder.lighting_corner_SE,holder.lighting_corner_SW)
for(var/datum/lighting_corner/corner in corners)
if(corner.sunlight == SUNLIGHT_NONE)
@@ -62,7 +62,7 @@
sunlight_check()
/datum/sunlight_handler/proc/holder_change()
holder.generate_missing_corners() //Somehow corners are self destructing under specific circumstances. Likely race conditions. This is slightly unoptimal but may be necessary.
GENERATE_MISSING_CORNERS(holder) //Somehow corners are self destructing under specific circumstances. Likely race conditions. This is slightly unoptimal but may be necessary.
sunlight_check() //Also not optimal but made necessary by race conditions
sunlight_update()
for(var/dir in (cardinal + cornerdirs))
@@ -161,7 +161,7 @@
sunlight_update()
/datum/sunlight_handler/proc/sunlight_check()
holder.generate_missing_corners() //Somehow corners are self destructing under specific circumstances. Likely race conditions. This is slightly unoptimal but may be necessary.
GENERATE_MISSING_CORNERS(holder) //Somehow corners are self destructing under specific circumstances. Likely race conditions. This is slightly unoptimal but may be necessary.
set_sleeping(FALSE) //We set sleeping to false just incase. If the conditions are correct, we'll end up going back to sleeping soon enough anyways.
var/cur_sunlight = sunlight
if(holder.is_outdoors())
@@ -391,3 +391,5 @@
return TRUE
else
return FALSE
#undef GENERATE_MISSING_CORNERS