mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-28 18:11:16 +00:00
* Starlight Polish (Space is blue!) (#72886) <!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request Adds support to underlays to realize_overlays Ensures decals properly handle plane offsets Fixes space lighting double applying if it's changeturf'd into. this will be important later Makes solar vis_contents block emissives as expected Moves transit tube overlays to update_overlays, adds emissive blockers to them #### Adds render steps An expansion on render_target based emissive blockers. They allow us to hijack an object's appearance and draw it somewhere else, or even modify it, THEN draw it somewhere else. They chain quite nicely Fixes shuttles deleting z holder objects #### Makes space emissive, makes walls and floors block emissives The core idea here goes like this: We make space glow, and give its overlays some color This way, the tile and space parallax remain fullbright, along with anything that doesn't block emissives, but anything that does block emissives will instead get shaded the color of starlight This requires a bit of extra work, see later This is done automatically with render relays, which now support specifiying layer and color (Need to make an editor for these one of these days) The emissive blocking floor stuff requires making a second render plate to prevent double scaling Also adds some new layering defines for lighting, and ensures all turf lights have a layer. We'll get to this soon #### Makes things in space blue We color them the same as starlight, by taking advantage of space being emissive This means that things in space that block emissive will block it correctly and be colored blue by the light overlay, but space itself will remain fullbright This does require redefining what always_lit means, but nothing but cordons use that so it's fineee #### Makes glass above space glow, and some other stuff Glass tiles that sit above space will now shine light with matching color to the glasses color. This includes mat tiles. Glass tiles (not mat because they have no alpha) also only partially block emissives. Adds a new proc that uses render steps to acomplish this, essentially we're cutting out bits below X alpha and drawing what remains as an emissive. #### Modifies partial space showing to support glow Essentially, alongside displaying space as an underlay, we also display a light overlay colored like starlight. That starlight overlay gets masked to only be visible in bits that do not contain any alpha. We also mask the turf lighting to not go into bits that have no alpha, to ensure we get the effect we want. This is done with that lighting layer thing I mentioned earlier. #### Makes appearance realization's list output ordered I want it output in order of overlay, sub overlay suboverlay, next overlay Need to use insert for that ## Why It's Good For The Game Pretty! Also having space be emissive is a very very good way to test for fucked emissive blockers (If it's broken why are we even drawing the overlay) I know for a fact mob blockers on lizards and socks are kinda yorked, I think there's more <details> <summary> Old </summary>    </details> <details> <summary> New </summary>    </details> ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and it's effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 add: Space now makes things in it starlight faintly blue fix: Glass floors that display space now properly let space shine through them, rather then hiding it in the dark add: Glass floors above space now glow faintly depending on their glass type /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. --> --------- Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> * update modular * Update _decal.dm * Update _decal.dm --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com> Co-authored-by: Tom <8881105+tf-4@users.noreply.github.com> Co-authored-by: lessthanthree <83487515+lessthnthree@users.noreply.github.com>
333 lines
16 KiB
Plaintext
333 lines
16 KiB
Plaintext
/*!
|
|
* Custom rendering solution to allow for advanced effects
|
|
* We (ab)use plane masters and render source/target to cheaply render 2+ planes as 1
|
|
* if you want to read more read the _render_readme.md
|
|
*/
|
|
|
|
|
|
/**
|
|
* Render relay object assigned to a plane master to be able to relay it's render onto other planes that are not it's own
|
|
*/
|
|
/atom/movable/render_plane_relay
|
|
screen_loc = "CENTER"
|
|
layer = -1
|
|
plane = 0
|
|
appearance_flags = PASS_MOUSE | NO_CLIENT_COLOR | KEEP_TOGETHER
|
|
/// If we render into a critical plane master, or not
|
|
var/critical_target = FALSE
|
|
|
|
/**
|
|
* ## Rendering plate
|
|
*
|
|
* Acts like a plane master, but for plane masters
|
|
* Renders other planes onto this plane, through the use of render objects
|
|
* Any effects applied onto this plane will act on the unified plane
|
|
* IE a bulge filter will apply as if the world was one object
|
|
* remember that once planes are unified on a render plate you cant change the layering of them!
|
|
*/
|
|
/atom/movable/screen/plane_master/rendering_plate
|
|
name = "Default rendering plate"
|
|
multiz_scaled = FALSE
|
|
|
|
///this plate renders the final screen to show to the player
|
|
/atom/movable/screen/plane_master/rendering_plate/master
|
|
name = "Master rendering plate"
|
|
documentation = "The endpoint of all plane masters, you can think of this as the final \"view\" we draw.\
|
|
<br>If offset is not 0 this will be drawn to the transparent plane of the floor above, but otherwise this is drawn to nothing, or shown to the player."
|
|
plane = RENDER_PLANE_MASTER
|
|
render_relay_planes = list()
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/master/show_to(mob/mymob)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
if(offset == 0)
|
|
return
|
|
// Non 0 offset render plates will relay up to the transparent plane above them, assuming they're not on the same z level as their target of course
|
|
var/datum/hud/hud = home.our_hud
|
|
// show_to can be called twice successfully with no hide_from call. Ensure no runtimes off the registers from this
|
|
if(hud)
|
|
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change), override = TRUE)
|
|
offset_change(hud?.current_plane_offset || 0)
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/master/hide_from(mob/oldmob)
|
|
. = ..()
|
|
if(offset == 0)
|
|
return
|
|
var/datum/hud/hud = home.our_hud
|
|
if(hud)
|
|
UnregisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change))
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/master/proc/on_offset_change(datum/source, old_offset, new_offset)
|
|
SIGNAL_HANDLER
|
|
offset_change(new_offset)
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/master/proc/offset_change(new_offset)
|
|
if(new_offset == offset) // If we're on our own z layer, relay to nothing, just draw
|
|
remove_relay_from(GET_NEW_PLANE(RENDER_PLANE_TRANSPARENT, offset - 1))
|
|
else // Otherwise, regenerate the relay
|
|
add_relay_to(GET_NEW_PLANE(RENDER_PLANE_TRANSPARENT, offset - 1))
|
|
|
|
///renders general in charachter game objects
|
|
/atom/movable/screen/plane_master/rendering_plate/game_plate
|
|
name = "Game rendering plate"
|
|
documentation = "Holds all objects that are ahhh, in character? is maybe the best way to describe it.\
|
|
<br>We apply a displacement effect from the gravity pulse plane too, so we can warp the game world."
|
|
plane = RENDER_PLANE_GAME
|
|
render_relay_planes = list(RENDER_PLANE_MASTER)
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/game_plate/Initialize(mapload)
|
|
. = ..()
|
|
add_filter("displacer", 1, displacement_map_filter(render_source = OFFSET_RENDER_TARGET(GRAVITY_PULSE_RENDER_TARGET, offset), size = 10))
|
|
|
|
// Blackness renders weird when you view down openspace, because of transforms and borders and such
|
|
// This is a consequence of not using lummy's grouped transparency, but I couldn't get that to work without totally fucking up
|
|
// Sight flags, and shooting vis_contents usage to the moon. So we're doin it different.
|
|
// If image vis contents worked (it should in 515), and we were ok with a maptick cost (wait for threaded maptick) this could be fixed
|
|
/atom/movable/screen/plane_master/rendering_plate/transparent
|
|
name = "Transparent plate"
|
|
documentation = "The master rendering plate from the offset below ours will be mirrored onto this plane. That way we achive a \"stack\" effect.\
|
|
<br>This plane exists to uplayer the master rendering plate to the correct spot in our z layer's rendering order"
|
|
plane = RENDER_PLANE_TRANSPARENT
|
|
appearance_flags = PLANE_MASTER
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/transparent/Initialize(mapload, datum/plane_master_group/home, offset)
|
|
. = ..()
|
|
// Don't display us if we're below everything else yeah?
|
|
AddComponent(/datum/component/plane_hide_highest_offset)
|
|
color = list(0.9,0,0,0, 0,0.9,0,0, 0,0,0.9,0, 0,0,0,1, 0,0,0,0)
|
|
|
|
///Contains most things in the game world
|
|
/atom/movable/screen/plane_master/rendering_plate/game_world
|
|
name = "Game world plate"
|
|
documentation = "Contains most of the objects in the world. Mobs, machines, etc. Note the drop shadow, it gives a very nice depth effect."
|
|
plane = RENDER_PLANE_GAME_WORLD
|
|
appearance_flags = PLANE_MASTER //should use client color
|
|
blend_mode = BLEND_OVERLAY
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/game_world/show_to(mob/mymob)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
remove_filter("AO")
|
|
if(istype(mymob) && mymob.client?.prefs?.read_preference(/datum/preference/toggle/ambient_occlusion))
|
|
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
|
|
|
|
///Contains all lighting objects
|
|
/atom/movable/screen/plane_master/rendering_plate/lighting
|
|
name = "Lighting plate"
|
|
documentation = "Anything on this plane will be <b>multiplied</b> with the plane it's rendered onto (typically the game plane).\
|
|
<br>That's how lighting functions at base. Because it uses BLEND_MULTIPLY and occasionally color matrixes, it needs a backdrop of blackness.\
|
|
<br>See <a href=\"https://secure.byond.com/forum/?post=2141928\">This byond post</a>\
|
|
<br>Lemme see uh, we're masked by the emissive plane so it can actually function (IE: make things glow in the dark).\
|
|
<br>We're also masked by the overlay lighting plane, which contains all the movable lights in the game. It draws to us and also the game plane.\
|
|
<br>Masks us out so it has the breathing room to apply its effect.\
|
|
<br>Oh and we quite often have our alpha changed to achive night vision effects, or things of that sort."
|
|
plane = RENDER_PLANE_LIGHTING
|
|
blend_mode_override = BLEND_MULTIPLY
|
|
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
critical = PLANE_CRITICAL_DISPLAY
|
|
|
|
/*!
|
|
* This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.
|
|
*
|
|
* Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.
|
|
* Emissive blockers are pasted with an atom color that converts them to be entirely some different color.
|
|
* Emissive overlays and emissive blockers are put onto the same plane.
|
|
* The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.
|
|
* A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.
|
|
* This is then used to alpha mask the lighting plane.
|
|
*/
|
|
/atom/movable/screen/plane_master/rendering_plate/lighting/Initialize(mapload)
|
|
. = ..()
|
|
add_filter("emissives", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(EMISSIVE_RENDER_TARGET, offset), flags = MASK_INVERSE))
|
|
add_filter("object_lighting", 2, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(O_LIGHTING_VISUAL_RENDER_TARGET, offset), flags = MASK_INVERSE))
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/lighting/show_to(mob/mymob)
|
|
. = ..()
|
|
if(!.)
|
|
return
|
|
// This applies a backdrop to our lighting plane
|
|
// Why do plane masters need a backdrop sometimes? Read https://secure.byond.com/forum/?post=2141928
|
|
// Basically, we need something to brighten
|
|
// unlit is perhaps less needed rn, it exists to provide a fullbright for things that can't see the lighting plane
|
|
// but we don't actually use invisibility to hide the lighting plane anymore, so it's pointless
|
|
var/atom/movable/screen/backdrop = mymob.overlay_fullscreen("lighting_backdrop_lit#[offset]", /atom/movable/screen/fullscreen/lighting_backdrop/lit)
|
|
// Need to make sure they're on our plane, ALL the time. We always need a backdrop
|
|
SET_PLANE_EXPLICIT(backdrop, PLANE_TO_TRUE(backdrop.plane), src)
|
|
backdrop = mymob.overlay_fullscreen("lighting_backdrop_unlit#[offset]", /atom/movable/screen/fullscreen/lighting_backdrop/unlit)
|
|
SET_PLANE_EXPLICIT(backdrop, PLANE_TO_TRUE(backdrop.plane), src)
|
|
|
|
// Sorry, this is a bit annoying
|
|
// Basically, we only want the lighting plane we can actually see to attempt to render
|
|
// If we don't our lower plane gets totally overriden by the black void of the upper plane
|
|
var/datum/hud/hud = home.our_hud
|
|
// show_to can be called twice successfully with no hide_from call. Ensure no runtimes off the registers from this
|
|
if(hud)
|
|
RegisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change), override = TRUE)
|
|
offset_change(hud?.current_plane_offset || 0)
|
|
set_alpha(mymob.lighting_alpha)
|
|
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/lighting/hide_from(mob/oldmob)
|
|
. = ..()
|
|
oldmob.clear_fullscreen("lighting_backdrop_lit")
|
|
oldmob.clear_fullscreen("lighting_backdrop_unlit")
|
|
var/datum/hud/hud = home.our_hud
|
|
if(hud)
|
|
UnregisterSignal(hud, COMSIG_HUD_OFFSET_CHANGED, PROC_REF(on_offset_change))
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/lighting/proc/on_offset_change(datum/source, old_offset, new_offset)
|
|
SIGNAL_HANDLER
|
|
offset_change(new_offset)
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/lighting/proc/offset_change(mob_offset)
|
|
// Offsets stack down remember. This implies that we're above the mob's view plane, and shouldn't render
|
|
if(offset < mob_offset)
|
|
disable_alpha()
|
|
else
|
|
enable_alpha()
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/emissive_slate
|
|
name = "Emissive Plate"
|
|
documentation = "This system works by exploiting BYONDs color matrix filter to use layers to handle emissive blockers.\
|
|
<br>Emissive overlays are pasted with an atom color that converts them to be entirely some specific color.\
|
|
<br>Emissive blockers are pasted with an atom color that converts them to be entirely some different color.\
|
|
<br>Emissive overlays and emissive blockers are put onto the same plane (This one).\
|
|
<br>The layers for the emissive overlays and emissive blockers cause them to mask eachother similar to normal BYOND objects.\
|
|
<br>A color matrix filter is applied to the emissive plane to mask out anything that isn't whatever the emissive color is.\
|
|
<br>This is then used to alpha mask the lighting plane."
|
|
plane = EMISSIVE_RENDER_PLATE
|
|
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
|
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
render_target = EMISSIVE_RENDER_TARGET
|
|
render_relay_planes = list()
|
|
critical = PLANE_CRITICAL_DISPLAY
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/emissive_slate/Initialize(mapload, datum/plane_master_group/home, offset)
|
|
. = ..()
|
|
add_filter("emissive_mask", 1, alpha_mask_filter(render_source = OFFSET_RENDER_TARGET(EMISSIVE_MASK_RENDER_TARGET, offset)))
|
|
add_filter("em_block_masking", 2, color_matrix_filter(GLOB.em_mask_matrix))
|
|
if(offset != 0)
|
|
add_relay_to(GET_NEW_PLANE(EMISSIVE_RENDER_PLATE, offset - 1), relay_layer = EMISSIVE_Z_BELOW_LAYER)
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/mask_emissive
|
|
name = "Emissive Mask"
|
|
documentation = "Any part of this plane that is transparent will be transparent in the emissive plane.\
|
|
<br>This is done to ensure emissives don't light things up \"through\" the darkness that normally sits at the bottom of the lighting plane.\
|
|
<br>We relay copies of the space, floor and wall planes to it, so we can use them as masks. Then we just boost any existing alpha to 100% and we're done."
|
|
plane = EMISSIVE_MASK_PLANE
|
|
appearance_flags = PLANE_MASTER|NO_CLIENT_COLOR
|
|
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
|
render_target = EMISSIVE_MASK_RENDER_TARGET
|
|
render_relay_planes = list()
|
|
|
|
/atom/movable/screen/plane_master/rendering_plate/mask_emissive/Initialize(mapload, datum/plane_master_group/home, offset)
|
|
. = ..()
|
|
// Uses a filter cause the alpha slider will fuck up colors and we want to be editable
|
|
add_filter("pump_alpha", 1, color_matrix_filter(list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,255, 0,0,0,0)))
|
|
|
|
///render plate for OOC stuff like ghosts, hud-screen effects, etc
|
|
/atom/movable/screen/plane_master/rendering_plate/non_game
|
|
name = "Non-Game rendering plate"
|
|
documentation = "Renders anything that's out of character. Mostly useful as a converse to the game rendering plate."
|
|
plane = RENDER_PLANE_NON_GAME
|
|
render_relay_planes = list(RENDER_PLANE_MASTER)
|
|
|
|
|
|
/**
|
|
* Plane master proc called in Initialize() that creates relay objects, and sets them uo as needed
|
|
* Sets:
|
|
* * layer from plane to avoid z-fighting
|
|
* * planes to relay the render to
|
|
* * render_source so that the plane will render on these objects
|
|
* * mouse opacity to ensure proper mouse hit tracking
|
|
* * name for debugging purposes
|
|
* Other vars such as alpha will automatically be applied with the render source
|
|
*/
|
|
/atom/movable/screen/plane_master/proc/generate_render_relays()
|
|
var/relay_loc = "CENTER"
|
|
// If we're using a submap (say for a popup window) make sure we draw onto it
|
|
if(home?.map)
|
|
relay_loc = "[home.map]:[relay_loc]"
|
|
|
|
var/list/generated_planes = list()
|
|
for(var/atom/movable/render_plane_relay/relay as anything in relays)
|
|
generated_planes += relay.plane
|
|
|
|
for(var/relay_plane in (render_relay_planes - generated_planes))
|
|
generate_relay_to(relay_plane, relay_loc)
|
|
|
|
if(blend_mode != BLEND_MULTIPLY)
|
|
blend_mode = BLEND_DEFAULT
|
|
relays_generated = TRUE
|
|
|
|
/// Creates a connection between this plane master and the passed in plane
|
|
/// Helper for out of system code, shouldn't be used in this file
|
|
/// Build system to differenchiate between generated and non generated render relays
|
|
/atom/movable/screen/plane_master/proc/add_relay_to(target_plane, blend_override, relay_layer, relay_color)
|
|
if(get_relay_to(target_plane))
|
|
return
|
|
render_relay_planes += target_plane
|
|
var/client/display_lad = home?.our_hud?.mymob?.client
|
|
var/atom/movable/render_plane_relay/relay = generate_relay_to(target_plane, show_to = display_lad, blend_override = blend_override, relay_layer = relay_layer)
|
|
relay.color = relay_color
|
|
|
|
/proc/get_plane_master_render_base(name)
|
|
return "*[name]: AUTOGENERATED RENDER TGT"
|
|
|
|
/atom/movable/screen/plane_master/proc/generate_relay_to(target_plane, relay_loc, client/show_to, blend_override, relay_layer)
|
|
if(!length(relays) && !initial(render_target))
|
|
render_target = OFFSET_RENDER_TARGET(get_plane_master_render_base(name), offset)
|
|
if(!relay_loc)
|
|
relay_loc = "CENTER"
|
|
// If we're using a submap (say for a popup window) make sure we draw onto it
|
|
if(home?.map)
|
|
relay_loc = "[home.map]:[relay_loc]"
|
|
var/blend_to_use = blend_override
|
|
if(isnull(blend_to_use))
|
|
blend_to_use = blend_mode_override || initial(blend_mode)
|
|
|
|
var/atom/movable/render_plane_relay/relay = new()
|
|
relay.render_source = render_target
|
|
relay.plane = target_plane
|
|
relay.screen_loc = relay_loc
|
|
// There are two rules here
|
|
// 1: layer needs to be positive (negative layers are treated as float layers)
|
|
// 2: lower planes (including offset ones) need to be layered below higher ones (because otherwise they'll render fucky)
|
|
// By multiplying LOWEST_EVER_PLANE by 30, we give 30 offsets worth of room to planes before they start going negative
|
|
// Bet
|
|
// We allow for manuel override if requested. careful with this
|
|
relay.layer = relay_layer || (plane + abs(LOWEST_EVER_PLANE * 30)) //layer must be positive but can be a decimal
|
|
relay.blend_mode = blend_to_use
|
|
relay.mouse_opacity = mouse_opacity
|
|
relay.name = render_target
|
|
relay.critical_target = PLANE_IS_CRITICAL(target_plane)
|
|
relays += relay
|
|
// Relays are sometimes generated early, before huds have a mob to display stuff to
|
|
// That's what this is for
|
|
if(show_to)
|
|
show_to.screen += relay
|
|
return relay
|
|
|
|
/// Breaks a connection between this plane master, and the passed in place
|
|
/atom/movable/screen/plane_master/proc/remove_relay_from(target_plane)
|
|
render_relay_planes -= target_plane
|
|
var/atom/movable/render_plane_relay/existing_relay = get_relay_to(target_plane)
|
|
if(!existing_relay)
|
|
return
|
|
relays -= existing_relay
|
|
if(!length(relays) && !initial(render_target))
|
|
render_target = null
|
|
var/client/lad = home?.our_hud?.mymob?.client
|
|
if(lad)
|
|
lad.screen -= existing_relay
|
|
|
|
/// Gets the relay atom we're using to connect to the target plane, if one exists
|
|
/atom/movable/screen/plane_master/proc/get_relay_to(target_plane)
|
|
for(var/atom/movable/render_plane_relay/relay in relays)
|
|
if(relay.plane == target_plane)
|
|
return relay
|
|
|
|
return null
|