mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2025-12-30 12:02:24 +00:00
Ambient Occlusion (#3419)
Adds an implementation of Europa's wall ambient occlusion, extended to operate on openturfs as well.
This commit is contained in:
62
code/modules/ambient_occlusion/ao_openspace.dm
Normal file
62
code/modules/ambient_occlusion/ao_openspace.dm
Normal file
@@ -0,0 +1,62 @@
|
||||
// Openturfs need special snowflake CAO and UA behavior - they're shadowing based on turf type instead of ao opacity,
|
||||
// as well as applying the overlays to the openspace shadower object instead of the turf itself.
|
||||
|
||||
/turf/simulated/open/calculate_ao_neighbors()
|
||||
ao_neighbors = 0
|
||||
var/turf/T
|
||||
for (var/tdir in cardinal)
|
||||
T = get_step(src, tdir)
|
||||
if (isopenturf(T))
|
||||
ao_neighbors |= 1 << tdir
|
||||
|
||||
if (ao_neighbors & N_NORTH)
|
||||
if (ao_neighbors & N_WEST)
|
||||
T = get_step(src, NORTHWEST)
|
||||
if (isopenturf(T))
|
||||
ao_neighbors |= N_NORTHWEST
|
||||
|
||||
if (ao_neighbors & N_EAST)
|
||||
T = get_step(src, NORTHEAST)
|
||||
if (isopenturf(T))
|
||||
ao_neighbors |= N_NORTHEAST
|
||||
|
||||
if (ao_neighbors & N_SOUTH)
|
||||
if (ao_neighbors & N_WEST)
|
||||
T = get_step(src, SOUTHWEST)
|
||||
if (isopenturf(T))
|
||||
ao_neighbors |= N_SOUTHWEST
|
||||
|
||||
if (ao_neighbors & N_EAST)
|
||||
T = get_step(src, SOUTHEAST)
|
||||
if (isopenturf(T))
|
||||
ao_neighbors |= N_SOUTHEAST
|
||||
|
||||
/turf/simulated/open/update_ao()
|
||||
if (ao_overlays)
|
||||
shadower.cut_overlay(ao_overlays)
|
||||
ao_overlays.Cut()
|
||||
|
||||
var/list/cache = SSicon_cache.ao_cache
|
||||
|
||||
for(var/i = 1 to 4)
|
||||
var/cdir = cornerdirs[i]
|
||||
var/corner = 0
|
||||
|
||||
if (ao_neighbors & (1 << cdir))
|
||||
corner |= 2
|
||||
if (ao_neighbors & (1 << turn(cdir, 45)))
|
||||
corner |= 1
|
||||
if (ao_neighbors & (1 << turn(cdir, -45)))
|
||||
corner |= 4
|
||||
|
||||
if (corner != 7) // 7 is the 'no shadows' state, no reason to add overlays for it.
|
||||
var/image/I = cache["[corner]-[i]"]
|
||||
if (!I)
|
||||
I = make_ao_image(corner, i)
|
||||
|
||||
LAZYADD(ao_overlays, I)
|
||||
|
||||
UNSETEMPTY(ao_overlays)
|
||||
|
||||
if (ao_overlays)
|
||||
shadower.add_overlay(ao_overlays)
|
||||
115
code/modules/ambient_occlusion/ao_turf.dm
Normal file
115
code/modules/ambient_occlusion/ao_turf.dm
Normal file
@@ -0,0 +1,115 @@
|
||||
#ifdef AO_USE_LIGHTING_OPACITY
|
||||
#define AO_TURF_CHECK(T) (!T.has_opaque_atom)
|
||||
#else
|
||||
#define AO_TURF_CHECK(T) (!T.density || !T.opacity)
|
||||
#endif
|
||||
|
||||
/turf
|
||||
var/permit_ao = TRUE
|
||||
var/tmp/list/ao_overlays // Current ambient occlusion overlays. Tracked so we can reverse them without dropping all priority overlays.
|
||||
var/tmp/ao_neighbors = 0
|
||||
var/ao_queued = AO_UPDATE_NONE
|
||||
|
||||
/turf/proc/regenerate_ao()
|
||||
for (var/thing in RANGE_TURFS(1, src))
|
||||
var/turf/T = thing
|
||||
if (T.permit_ao)
|
||||
T.queue_ao(TRUE)
|
||||
|
||||
/turf/proc/calculate_ao_neighbors()
|
||||
ao_neighbors = 0
|
||||
if (!permit_ao)
|
||||
return
|
||||
|
||||
var/turf/T
|
||||
for (var/tdir in cardinal)
|
||||
T = get_step(src, tdir)
|
||||
if (T && AO_TURF_CHECK(T))
|
||||
ao_neighbors |= 1 << tdir
|
||||
|
||||
if (ao_neighbors & N_NORTH)
|
||||
if (ao_neighbors & N_WEST)
|
||||
T = get_step(src, NORTHWEST)
|
||||
if (AO_TURF_CHECK(T))
|
||||
ao_neighbors |= N_NORTHWEST
|
||||
|
||||
if (ao_neighbors & N_EAST)
|
||||
T = get_step(src, NORTHEAST)
|
||||
if (AO_TURF_CHECK(T))
|
||||
ao_neighbors |= N_NORTHEAST
|
||||
|
||||
if (ao_neighbors & N_SOUTH)
|
||||
if (ao_neighbors & N_WEST)
|
||||
T = get_step(src, SOUTHWEST)
|
||||
if (AO_TURF_CHECK(T))
|
||||
ao_neighbors |= N_SOUTHWEST
|
||||
|
||||
if (ao_neighbors & N_EAST)
|
||||
T = get_step(src, SOUTHEAST)
|
||||
if (AO_TURF_CHECK(T))
|
||||
ao_neighbors |= N_SOUTHEAST
|
||||
|
||||
/proc/make_ao_image(corner, i)
|
||||
var/list/cache = SSicon_cache.ao_cache
|
||||
var/cstr = "[corner]"
|
||||
var/key = "[cstr]-[i]"
|
||||
|
||||
var/image/I = image('icons/turf/flooring/shadows.dmi', cstr, dir = 1 << (i-1))
|
||||
I.alpha = WALL_AO_ALPHA
|
||||
I.blend_mode = BLEND_OVERLAY
|
||||
I.appearance_flags = RESET_ALPHA|RESET_COLOR|TILE_BOUND
|
||||
|
||||
. = cache[key] = I
|
||||
|
||||
/turf/proc/queue_ao(rebuild = TRUE)
|
||||
if (!ao_queued)
|
||||
SSocclusion.queue += src
|
||||
|
||||
var/new_level = rebuild ? AO_UPDATE_REBUILD : AO_UPDATE_OVERLAY
|
||||
if (ao_queued < new_level)
|
||||
ao_queued = new_level
|
||||
|
||||
/turf/proc/update_ao()
|
||||
if (ao_overlays)
|
||||
cut_overlay(ao_overlays, TRUE)
|
||||
ao_overlays.Cut()
|
||||
|
||||
if (!permit_ao)
|
||||
return
|
||||
|
||||
var/list/cache = SSicon_cache.ao_cache
|
||||
|
||||
if (!has_opaque_atom)
|
||||
for(var/i = 1 to 4)
|
||||
var/cdir = cornerdirs[i]
|
||||
var/corner = 0
|
||||
|
||||
if (ao_neighbors & (1 << cdir))
|
||||
corner |= 2
|
||||
if (ao_neighbors & (1 << turn(cdir, 45)))
|
||||
corner |= 1
|
||||
if (ao_neighbors & (1 << turn(cdir, -45)))
|
||||
corner |= 4
|
||||
|
||||
if (corner != 7) // 7 is the 'no shadows' state, no reason to add overlays for it.
|
||||
var/image/I = cache["[corner]-[i]"]
|
||||
if (!I)
|
||||
I = make_ao_image(corner, i) // this will also add the image to the cache.
|
||||
|
||||
if (!pixel_x && !pixel_y && !pixel_w && !pixel_z) // We can only use the cache if we're not shifting.
|
||||
LAZYADD(ao_overlays, I)
|
||||
else
|
||||
// There's a pixel var set, so we're going to need to make a new instance just for this type.
|
||||
var/mutable_appearance/MA = new(I)
|
||||
// We invert the offsets here to counteract the pixel shifting of the parent turf.
|
||||
MA.pixel_x = -(pixel_x)
|
||||
MA.pixel_y = -(pixel_y)
|
||||
MA.pixel_w = -(pixel_w)
|
||||
MA.pixel_z = -(pixel_z)
|
||||
|
||||
LAZYADD(ao_overlays, MA)
|
||||
|
||||
UNSETEMPTY(ao_overlays)
|
||||
|
||||
if (ao_overlays)
|
||||
add_overlay(ao_overlays, TRUE)
|
||||
@@ -104,6 +104,9 @@
|
||||
if (new_opacity == TRUE)
|
||||
T.has_opaque_atom = TRUE
|
||||
T.reconsider_lights()
|
||||
#ifdef AO_USE_LIGHTING_OPACITY
|
||||
T.regenerate_ao()
|
||||
#endif
|
||||
else
|
||||
var/old_has_opaque_atom = T.has_opaque_atom
|
||||
T.recalc_atom_opacity()
|
||||
|
||||
@@ -119,20 +119,38 @@
|
||||
|
||||
// Can't think of a good name, this proc will recalculate the has_opaque_atom variable.
|
||||
/turf/proc/recalc_atom_opacity()
|
||||
#ifdef AO_USE_LIGHTING_OPACITY
|
||||
var/old = has_opaque_atom
|
||||
#endif
|
||||
|
||||
has_opaque_atom = FALSE
|
||||
for (var/atom/A in src.contents + src) // Loop through every movable atom on our tile PLUS ourselves (we matter too...)
|
||||
if (A.opacity)
|
||||
has_opaque_atom = TRUE
|
||||
return // No need to continue if we find something opaque.
|
||||
if (opacity)
|
||||
has_opaque_atom = TRUE
|
||||
else
|
||||
for (var/thing in src) // Loop through every movable atom on our tile
|
||||
var/atom/movable/A = thing
|
||||
if (A.opacity)
|
||||
has_opaque_atom = TRUE
|
||||
break // No need to continue if we find something opaque.
|
||||
|
||||
#ifdef AO_USE_LIGHTING_OPACITY
|
||||
if (old != has_opaque_atom)
|
||||
queue_ao()
|
||||
#endif
|
||||
|
||||
// If an opaque movable atom moves around we need to potentially update visibility.
|
||||
/turf/Entered(atom/movable/Obj, atom/OldLoc)
|
||||
. = ..()
|
||||
|
||||
if (Obj && Obj.opacity)
|
||||
if (Obj && Obj.opacity && !has_opaque_atom)
|
||||
has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.
|
||||
reconsider_lights()
|
||||
|
||||
#ifdef AO_USE_LIGHTING_OPACITY
|
||||
// Hook for AO.
|
||||
regenerate_ao()
|
||||
#endif
|
||||
|
||||
/turf/Exited(atom/movable/Obj, atom/newloc)
|
||||
. = ..()
|
||||
|
||||
@@ -187,9 +205,12 @@
|
||||
var/list/old_affecting_lights = affecting_lights
|
||||
var/old_lighting_overlay = lighting_overlay
|
||||
var/list/old_corners = corners
|
||||
var/old_ao_neighbors = ao_neighbors
|
||||
|
||||
. = ..()
|
||||
|
||||
ao_neighbors = old_ao_neighbors
|
||||
|
||||
recalc_atom_opacity()
|
||||
lighting_overlay = old_lighting_overlay
|
||||
if (lighting_overlay && lighting_overlay.loc != src)
|
||||
|
||||
@@ -168,6 +168,7 @@
|
||||
. = ..()
|
||||
icon_state = "" // Clear out the debug icon.
|
||||
SSopenturf.openspace_turfs += src
|
||||
shadower = new(src)
|
||||
update()
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user