From a0840b571c9b285b5e402a20506600665a01422b Mon Sep 17 00:00:00 2001 From: CHOMPStation2 <58959929+CHOMPStation2@users.noreply.github.com> Date: Thu, 21 Nov 2024 05:12:08 -0700 Subject: [PATCH] [MIRROR] Micro-opt lighting (#9268) Co-authored-by: ShadowLarkens Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> --- code/controllers/subsystems/lighting.dm | 2 +- code/modules/lighting/lighting_corner.dm | 60 ++++++---- code/modules/lighting/lighting_overlay.dm | 41 +++---- code/modules/lighting/lighting_source.dm | 109 +++++++++++++------ code/modules/lighting/lighting_turf.dm | 35 ------ code/modules/lighting/sunlight_handler_ch.dm | 8 +- 6 files changed, 130 insertions(+), 125 deletions(-) diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm index aefe01f0ae..4f287f10cc 100644 --- a/code/controllers/subsystems/lighting.dm +++ b/code/controllers/subsystems/lighting.dm @@ -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. diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm index 778c907936..97a41477e5 100644 --- a/code/modules/lighting/lighting_corner.dm +++ b/code/modules/lighting/lighting_corner.dm @@ -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) diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 7faedb0a2a..9cc4e267c2 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -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)) + 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 - affected_turf.underlays -= current_underlay 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() diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 7e58f9789e..a5f9bfa167 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -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 (!T.lighting_corners_initialised) - T.generate_missing_corners() - 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 + if(IS_OPAQUE_TURF(T)) + continue + if (!T.lighting_corners_initialised) + 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 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 diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index 7ae41c206f..4dc8997917 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -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 diff --git a/code/modules/lighting/sunlight_handler_ch.dm b/code/modules/lighting/sunlight_handler_ch.dm index 9cf88bec51..585d9ffb29 100644 --- a/code/modules/lighting/sunlight_handler_ch.dm +++ b/code/modules/lighting/sunlight_handler_ch.dm @@ -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