From f11d634a36e1d146c02cb4e22ee097cc0265524a Mon Sep 17 00:00:00 2001 From: deathride58 Date: Tue, 26 Mar 2019 22:32:11 -0400 Subject: [PATCH 1/4] Attempts to optimize the lighting process by ditching the inverse-square falloff algorithm in favor of a linear one --- code/modules/lighting/lighting_source.dm | 604 ++++++++++++----------- 1 file changed, 306 insertions(+), 298 deletions(-) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 59ce11baeb..bde0a61be5 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -1,298 +1,306 @@ -// This is where the fun begins. -// 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. - - 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() - - // Variables for keeping track of the colour. - var/lum_r - var/lum_g - var/lum_b - - // The lumcount values used to apply the light. - var/tmp/applied_lum_r - 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. - var/list/turf/affecting_turfs - - var/applied = FALSE // Whether we have applied our light yet or not. - - var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update. - - -/datum/light_source/New(var/atom/owner, var/atom/top) - source_atom = owner // Set our new owner. - LAZYADD(source_atom.light_sources, src) - top_atom = top - if (top_atom != source_atom) - LAZYADD(top_atom.light_sources, src) - - source_turf = top_atom - pixel_turf = get_turf_pixel(top_atom) || source_turf - - light_power = source_atom.light_power - light_range = source_atom.light_range - light_color = source_atom.light_color - - parse_light_color() - - update() - - return ..() - -/datum/light_source/Destroy(force) - remove_lum() - if (source_atom) - LAZYREMOVE(source_atom.light_sources, src) - - if (top_atom) - LAZYREMOVE(top_atom.light_sources, src) - - if (needs_update) - GLOB.lighting_update_lights -= src - - . = ..() - -// Yes this doesn't align correctly on anything other than 4 width tabs. -// If you want it to go switch everybody to elastic tab stops. -// Actually that'd be great if you could! -#define EFFECT_UPDATE(level) \ - if (needs_update == LIGHTING_NO_UPDATE) \ - GLOB.lighting_update_lights += src; \ - if (needs_update < level) \ - needs_update = level; \ - - -// This proc will cause the light source to update the top atom, and add itself to the update queue. -/datum/light_source/proc/update(var/atom/new_top_atom) - // This top atom is different. - if (new_top_atom && new_top_atom != top_atom) - if(top_atom != source_atom && top_atom.light_sources) // Remove ourselves from the light sources of that top atom. - LAZYREMOVE(top_atom.light_sources, src) - - top_atom = new_top_atom - - if (top_atom != source_atom) - LAZYADD(top_atom.light_sources, src) // Add ourselves to the light sources of our new top atom. - - EFFECT_UPDATE(LIGHTING_CHECK_UPDATE) - -// Will force an update without checking if it's actually needed. -/datum/light_source/proc/force_update() - EFFECT_UPDATE(LIGHTING_FORCE_UPDATE) - -// Will cause the light source to recalculate turfs that were removed or added to visibility only. -/datum/light_source/proc/vis_update() - EFFECT_UPDATE(LIGHTING_VIS_UPDATE) - -// Decompile the hexadecimal colour into lumcounts of each perspective. -/datum/light_source/proc/parse_light_color() - if (light_color) - lum_r = GetRedPart (light_color) / 255 - lum_g = GetGreenPart (light_color) / 255 - lum_b = GetBluePart (light_color) / 255 - else - lum_r = 1 - lum_g = 1 - lum_b = 1 - -// Macro that applies light to a new corner. -// It is a macro in the interest of speed, yet not having to copy paste it. -// 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))) - -#define APPLY_CORNER(C) \ - . = LUM_FALLOFF(C, pixel_turf); \ - . *= light_power; \ - var/OLD = effect_str[C]; \ - effect_str[C] = .; \ - \ - C.update_lumcount \ - ( \ - (. * 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 \ - ); - -// This is the define used to calculate falloff. - -/datum/light_source/proc/remove_lum() - applied = FALSE - var/thing - for (thing in affecting_turfs) - var/turf/T = thing - LAZYREMOVE(T.affecting_lights, src) - - affecting_turfs = null - - var/datum/lighting_corner/C - for (thing in effect_str) - C = thing - REMOVE_CORNER(C) - - LAZYREMOVE(C.affecting, src) - - effect_str = null - -/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C) - LAZYINITLIST(effect_str) - if (effect_str[C]) // Already have one. - REMOVE_CORNER(C) - effect_str[C] = 0 - - APPLY_CORNER(C) - UNSETEMPTY(effect_str) - -/datum/light_source/proc/update_corners() - var/update = FALSE - var/atom/source_atom = src.source_atom - - if (QDELETED(source_atom)) - qdel(src) - return - - if (source_atom.light_power != light_power) - light_power = source_atom.light_power - update = TRUE - - if (source_atom.light_range != light_range) - light_range = source_atom.light_range - update = TRUE - - if (!top_atom) - top_atom = source_atom - update = TRUE - - if (!light_range || !light_power) - qdel(src) - return - - if (isturf(top_atom)) - if (source_turf != top_atom) - source_turf = top_atom - pixel_turf = source_turf - update = TRUE - else if (top_atom.loc != source_turf) - source_turf = top_atom.loc - pixel_turf = get_turf_pixel(top_atom) - update = TRUE - else - var/P = get_turf_pixel(top_atom) - if (P != pixel_turf) - pixel_turf = P - update = TRUE - - if (!isturf(source_turf)) - if (applied) - remove_lum() - return - - if (light_range && light_power && !applied) - update = TRUE - - if (source_atom.light_color != light_color) - light_color = source_atom.light_color - parse_light_color() - update = TRUE - - else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b) - update = TRUE - - if (update) - needs_update = LIGHTING_CHECK_UPDATE - applied = TRUE - else if (needs_update == LIGHTING_CHECK_UPDATE) - return //nothing's changed - - var/list/datum/lighting_corner/corners = list() - var/list/turf/turfs = list() - var/thing - var/datum/lighting_corner/C - var/turf/T - if (source_turf) - var/oldlum = source_turf.luminosity - source_turf.luminosity = CEILING(light_range, 1) - for(T in view(CEILING(light_range, 1), source_turf)) - for (thing in T.get_corners(source_turf)) - C = thing - corners[C] = 0 - turfs += T - source_turf.luminosity = oldlum - - LAZYINITLIST(affecting_turfs) - var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. - affecting_turfs += L - for (thing in L) - T = thing - LAZYADD(T.affecting_lights, src) - - L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. - affecting_turfs -= L - for (thing in L) - T = thing - LAZYREMOVE(T.affecting_lights, src) - - LAZYINITLIST(effect_str) - if (needs_update == LIGHTING_VIS_UPDATE) - for (thing in corners - effect_str) // New corners - C = thing - LAZYADD(C.affecting, src) - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) - else - L = corners - effect_str - for (thing in L) // New corners - C = thing - LAZYADD(C.affecting, src) - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) - - for (thing in corners - L) // Existing corners - C = thing - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) - - L = effect_str - corners - for (thing in L) // Old, now gone, corners. - C = thing - REMOVE_CORNER(C) - LAZYREMOVE(C.affecting, src) - effect_str -= L - - applied_lum_r = lum_r - applied_lum_g = lum_g - applied_lum_b = lum_b - - UNSETEMPTY(effect_str) - UNSETEMPTY(affecting_turfs) - -#undef EFFECT_UPDATE -#undef LUM_FALLOFF -#undef REMOVE_CORNER -#undef APPLY_CORNER +// This is where the fun begins. +// 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. + + 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() + + // Variables for keeping track of the colour. + var/lum_r + var/lum_g + var/lum_b + + // The lumcount values used to apply the light. + var/tmp/applied_lum_r + 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. + var/list/turf/affecting_turfs + + var/applied = FALSE // Whether we have applied our light yet or not. + + var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update. + + +/datum/light_source/New(var/atom/owner, var/atom/top) + source_atom = owner // Set our new owner. + LAZYADD(source_atom.light_sources, src) + top_atom = top + if (top_atom != source_atom) + LAZYADD(top_atom.light_sources, src) + + source_turf = top_atom + pixel_turf = get_turf_pixel(top_atom) || source_turf + + light_power = source_atom.light_power + light_range = source_atom.light_range + light_color = source_atom.light_color + + parse_light_color() + + update() + + return ..() + +/datum/light_source/Destroy(force) + remove_lum() + if (source_atom) + LAZYREMOVE(source_atom.light_sources, src) + + if (top_atom) + LAZYREMOVE(top_atom.light_sources, src) + + if (needs_update) + GLOB.lighting_update_lights -= src + + . = ..() + +// Yes this doesn't align correctly on anything other than 4 width tabs. +// If you want it to go switch everybody to elastic tab stops. +// Actually that'd be great if you could! +#define EFFECT_UPDATE(level) \ + if (needs_update == LIGHTING_NO_UPDATE) \ + GLOB.lighting_update_lights += src; \ + if (needs_update < level) \ + needs_update = level; \ + + +// This proc will cause the light source to update the top atom, and add itself to the update queue. +/datum/light_source/proc/update(var/atom/new_top_atom) + // This top atom is different. + if (new_top_atom && new_top_atom != top_atom) + if(top_atom != source_atom && top_atom.light_sources) // Remove ourselves from the light sources of that top atom. + LAZYREMOVE(top_atom.light_sources, src) + + top_atom = new_top_atom + + if (top_atom != source_atom) + LAZYADD(top_atom.light_sources, src) // Add ourselves to the light sources of our new top atom. + + EFFECT_UPDATE(LIGHTING_CHECK_UPDATE) + +// Will force an update without checking if it's actually needed. +/datum/light_source/proc/force_update() + EFFECT_UPDATE(LIGHTING_FORCE_UPDATE) + +// Will cause the light source to recalculate turfs that were removed or added to visibility only. +/datum/light_source/proc/vis_update() + EFFECT_UPDATE(LIGHTING_VIS_UPDATE) + +// Decompile the hexadecimal colour into lumcounts of each perspective. +/datum/light_source/proc/parse_light_color() + if (light_color) + lum_r = GetRedPart (light_color) / 255 + lum_g = GetGreenPart (light_color) / 255 + lum_b = GetBluePart (light_color) / 255 + else + lum_r = 1 + lum_g = 1 + lum_b = 1 + +// Macro that applies light to a new corner. +// It is a macro in the interest of speed, yet not having to copy paste it. +// 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. + +//Original lighting falloff calculation. This looks the best out of the three. However, this is also the most expensive. +//#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) + +//Cubic lighting falloff. This has the *exact* same range as the original lighting falloff calculation, down to the exact decimal, but it looks a little unnatural due to the harsher falloff and how it's generally brighter across the board. +//#define LUM_FALLOFF(C, T) (1 - CLAMP01((((C.x - T.x) * (C.x - T.x)) + ((C.y - T.y) * (C.y - T.y)) + LIGHTING_HEIGHT) / max(1, light_range*light_range))) + +//Linear lighting falloff. This resembles the original lighting falloff calculation the best, but results in lights having a slightly larger range, which is most noticable with large light sources. This looks the darkest out of the three due to how lights are brighter closer to the source compared to the original falloff algorithm. This falloff method also does not at all take into account lighting height, as it acts as a flat reduction to light range with this method. +#define LUM_FALLOFF(C, T) (1 - CLAMP01(((abs(C.x - T.x) + abs(C.y - T.y))) / max(1, light_range))) + +#define APPLY_CORNER(C) \ + . = LUM_FALLOFF(C, pixel_turf); \ + . *= light_power; \ + var/OLD = effect_str[C]; \ + effect_str[C] = .; \ + \ + C.update_lumcount \ + ( \ + (. * 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 \ + ); + +// This is the define used to calculate falloff. + +/datum/light_source/proc/remove_lum() + applied = FALSE + var/thing + for (thing in affecting_turfs) + var/turf/T = thing + LAZYREMOVE(T.affecting_lights, src) + + affecting_turfs = null + + var/datum/lighting_corner/C + for (thing in effect_str) + C = thing + REMOVE_CORNER(C) + + LAZYREMOVE(C.affecting, src) + + effect_str = null + +/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C) + LAZYINITLIST(effect_str) + if (effect_str[C]) // Already have one. + REMOVE_CORNER(C) + effect_str[C] = 0 + + APPLY_CORNER(C) + UNSETEMPTY(effect_str) + +/datum/light_source/proc/update_corners() + var/update = FALSE + var/atom/source_atom = src.source_atom + + if (QDELETED(source_atom)) + qdel(src) + return + + if (source_atom.light_power != light_power) + light_power = source_atom.light_power + update = TRUE + + if (source_atom.light_range != light_range) + light_range = source_atom.light_range + update = TRUE + + if (!top_atom) + top_atom = source_atom + update = TRUE + + if (!light_range || !light_power) + qdel(src) + return + + if (isturf(top_atom)) + if (source_turf != top_atom) + source_turf = top_atom + pixel_turf = source_turf + update = TRUE + else if (top_atom.loc != source_turf) + source_turf = top_atom.loc + pixel_turf = get_turf_pixel(top_atom) + update = TRUE + else + var/P = get_turf_pixel(top_atom) + if (P != pixel_turf) + pixel_turf = P + update = TRUE + + if (!isturf(source_turf)) + if (applied) + remove_lum() + return + + if (light_range && light_power && !applied) + update = TRUE + + if (source_atom.light_color != light_color) + light_color = source_atom.light_color + parse_light_color() + update = TRUE + + else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b) + update = TRUE + + if (update) + needs_update = LIGHTING_CHECK_UPDATE + applied = TRUE + else if (needs_update == LIGHTING_CHECK_UPDATE) + return //nothing's changed + + var/list/datum/lighting_corner/corners = list() + var/list/turf/turfs = list() + var/thing + var/datum/lighting_corner/C + var/turf/T + if (source_turf) + var/oldlum = source_turf.luminosity + source_turf.luminosity = CEILING(light_range, 1) + for(T in view(CEILING(light_range, 1), source_turf)) + for (thing in T.get_corners(source_turf)) + C = thing + corners[C] = 0 + turfs += T + source_turf.luminosity = oldlum + + LAZYINITLIST(affecting_turfs) + var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. + affecting_turfs += L + for (thing in L) + T = thing + LAZYADD(T.affecting_lights, src) + + L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. + affecting_turfs -= L + for (thing in L) + T = thing + LAZYREMOVE(T.affecting_lights, src) + + LAZYINITLIST(effect_str) + if (needs_update == LIGHTING_VIS_UPDATE) + for (thing in corners - effect_str) // New corners + C = thing + LAZYADD(C.affecting, src) + if (!C.active) + effect_str[C] = 0 + continue + APPLY_CORNER(C) + else + L = corners - effect_str + for (thing in L) // New corners + C = thing + LAZYADD(C.affecting, src) + if (!C.active) + effect_str[C] = 0 + continue + APPLY_CORNER(C) + + for (thing in corners - L) // Existing corners + C = thing + if (!C.active) + effect_str[C] = 0 + continue + APPLY_CORNER(C) + + L = effect_str - corners + for (thing in L) // Old, now gone, corners. + C = thing + REMOVE_CORNER(C) + LAZYREMOVE(C.affecting, src) + effect_str -= L + + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b + + UNSETEMPTY(effect_str) + UNSETEMPTY(affecting_turfs) + +#undef EFFECT_UPDATE +#undef LUM_FALLOFF +#undef REMOVE_CORNER +#undef APPLY_CORNER From 8ea35bf6d814ba3885d2d2486030c87b68e5ab19 Mon Sep 17 00:00:00 2001 From: deathride58 Date: Wed, 27 Mar 2019 00:39:52 -0400 Subject: [PATCH 2/4] Adds a somewhat hacky octagonal linear lighting algorithm --- code/modules/lighting/lighting_source.dm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index bde0a61be5..de9e8a90ca 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -117,8 +117,12 @@ //Cubic lighting falloff. This has the *exact* same range as the original lighting falloff calculation, down to the exact decimal, but it looks a little unnatural due to the harsher falloff and how it's generally brighter across the board. //#define LUM_FALLOFF(C, T) (1 - CLAMP01((((C.x - T.x) * (C.x - T.x)) + ((C.y - T.y) * (C.y - T.y)) + LIGHTING_HEIGHT) / max(1, light_range*light_range))) -//Linear lighting falloff. This resembles the original lighting falloff calculation the best, but results in lights having a slightly larger range, which is most noticable with large light sources. This looks the darkest out of the three due to how lights are brighter closer to the source compared to the original falloff algorithm. This falloff method also does not at all take into account lighting height, as it acts as a flat reduction to light range with this method. -#define LUM_FALLOFF(C, T) (1 - CLAMP01(((abs(C.x - T.x) + abs(C.y - T.y))) / max(1, light_range))) +//Linear lighting falloff. This resembles the original lighting falloff calculation the best, but results in lights having a slightly larger range, which is most noticable with large light sources. This also results in lights being diamond-shaped, fuck. This looks the darkest out of the three due to how lights are brighter closer to the source compared to the original falloff algorithm. This falloff method also does not at all take into account lighting height, as it acts as a flat reduction to light range with this method. +//#define LUM_FALLOFF(C, T) (1 - CLAMP01(((abs(C.x - T.x) + abs(C.y - T.y))) / max(1, light_range+1))) + +//Linear lighting falloff but with an octagonal shape in place of a diamond shape. Lummox JR please add pointer support. +#define GET_LUM_DIST(DISTX, DISTY) (DISTX + DISTY + abs(DISTX - DISTY)*0.4) +#define LUM_FALLOFF(C, T) (1 - CLAMP01(GET_LUM_DIST(abs(C.x - T.x), abs(C.y - T.y)) / max(1, light_range+1))) #define APPLY_CORNER(C) \ . = LUM_FALLOFF(C, pixel_turf); \ @@ -302,5 +306,6 @@ #undef EFFECT_UPDATE #undef LUM_FALLOFF +#undef GET_LUM_DIST #undef REMOVE_CORNER #undef APPLY_CORNER From f4bdef2368ea9056139c06c6147b6fa20d0a565e Mon Sep 17 00:00:00 2001 From: deathride58 Date: Sat, 30 Mar 2019 21:21:10 -0400 Subject: [PATCH 3/4] properly takes into account LIGHTING_HEIGHT for linear falloff --- code/modules/lighting/lighting_source.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index de9e8a90ca..fd5ea917a1 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -122,7 +122,7 @@ //Linear lighting falloff but with an octagonal shape in place of a diamond shape. Lummox JR please add pointer support. #define GET_LUM_DIST(DISTX, DISTY) (DISTX + DISTY + abs(DISTX - DISTY)*0.4) -#define LUM_FALLOFF(C, T) (1 - CLAMP01(GET_LUM_DIST(abs(C.x - T.x), abs(C.y - T.y)) / max(1, light_range+1))) +#define LUM_FALLOFF(C, T) (1 - CLAMP01(max(GET_LUM_DIST(abs(C.x - T.x), abs(C.y - T.y)),LIGHTING_HEIGHT) / max(1, light_range+1))) #define APPLY_CORNER(C) \ . = LUM_FALLOFF(C, pixel_turf); \ From 69d7cd2ff5bf9c5a513b316fc6c573db97c0f7e8 Mon Sep 17 00:00:00 2001 From: deathride58 Date: Sat, 30 Mar 2019 22:57:08 -0400 Subject: [PATCH 4/4] Adds Lohikar's optimization for update_corners --- code/modules/lighting/lighting_source.dm | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index fd5ea917a1..8f4aea3925 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -28,6 +28,11 @@ var/needs_update = LIGHTING_NO_UPDATE // Whether we are queued for an update. +// Thanks to Lohikar for flinging this tiny bit of code at me, increasing my brain cell count from 1 to 2 in the process. +// This macro will only offset up to 1 tile, but anything with a greater offset is an outlier and probably should handle its own lighting offsets. +// Anything pixelshifted 16px or more will be considered on the next tile. +#define GET_APPROXIMATE_PIXEL_DIR(PX, PY) ((!(PX) ? 0 : ((PX >= 16 ? EAST : (PX <= -16 ? WEST : 0)))) | (!PY ? 0 : (PY >= 16 ? NORTH : (PY <= -16 ? SOUTH : 0)))) +#define UPDATE_APPROXIMATE_PIXEL_TURF var/_mask = GET_APPROXIMATE_PIXEL_DIR(top_atom.pixel_x, top_atom.pixel_y); pixel_turf = _mask ? (get_step(source_turf, _mask) || source_turf) : source_turf /datum/light_source/New(var/atom/owner, var/atom/top) source_atom = owner // Set our new owner. @@ -37,7 +42,7 @@ LAZYADD(top_atom.light_sources, src) source_turf = top_atom - pixel_turf = get_turf_pixel(top_atom) || source_turf + UPDATE_APPROXIMATE_PIXEL_TURF light_power = source_atom.light_power light_range = source_atom.light_range @@ -202,17 +207,12 @@ if (isturf(top_atom)) if (source_turf != top_atom) source_turf = top_atom - pixel_turf = source_turf + UPDATE_APPROXIMATE_PIXEL_TURF update = TRUE else if (top_atom.loc != source_turf) source_turf = top_atom.loc - pixel_turf = get_turf_pixel(top_atom) + UPDATE_APPROXIMATE_PIXEL_TURF update = TRUE - else - var/P = get_turf_pixel(top_atom) - if (P != pixel_turf) - pixel_turf = P - update = TRUE if (!isturf(source_turf)) if (applied)