Problem description:
I am trying to create a lighting engine for the /vg/ branch of SS13.
The system works by using a PLANE_MASTER assigned for lighting.
On that plane master, we have a dark backdrop.
This dark backdrop is illuminated by a dark plane with very low transparency.
On that dark plane, we draw several light objects of various shapes.
This works fine for white light sources. But when we have light sources of different colours, they tend to mix badly and aggressively shift to white light.
That's because we draw everything - notably, we generated our light overlays - using BLEND_ADD. When two light sources L1 and L2 of different RGB values collide, the result is :
R(L1+L2) = R(L1)+R(L2)
G(L1+L2) = G(L1)+G(L2)
B(L1+L2) = B(L1)+B(L2)
A(L1+L2) = A(L1)+A(L2)
So if L1 and L2 are not purely monochromatic, the result of two identical lights overlapping is not the same light with brighter intensity, but a whiter light with brighter intensity.
Ideally we want:
R(L1+L2) = sqrt(R(L1)*R(L2))
G(L1+L2) = sqrt(G(L1)*G(L2))
B(L1+L2) = sqrt(B(L1)*B(L2))
A(L1+L2) = A(L1)+A(L2)
Or any sort of averaging for the colour and addition for the alpha/intensity.
I have not found a way to make this possible.
Code:
Our planes:
/obj/abstract/screen/plane
name = ""
screen_loc = "CENTER"
blend_mode = BLEND_MULTIPLY
layer = 1
/obj/abstract/screen/plane/New(var/client/C)
..()
if(istype(C))
C.screen += src
verbs.Cut()
/obj/abstract/screen/plane/master
icon = 'icons/mob/screen1.dmi'
appearance_flags = NO_CLIENT_COLOR | PLANE_MASTER | RESET_TRANSFORM | RESET_COLOR | RESET_ALPHA
color = LIGHTING_PLANEMASTER_COLOR // Completely black.
plane = LIGHTING_PLANE
mouse_opacity = 0
//poor inheritance shitcode
/obj/abstract/screen/backdrop
blend_mode = BLEND_OVERLAY
icon = 'icons/mob/screen1.dmi'
icon_state = "black"
layer = BACKGROUND_LAYER
screen_loc = "CENTER"
plane = LIGHTING_PLANE
/obj/abstract/screen/backdrop/New(var/client/C)
..()
if(istype(C)) C.screen += src
var/matrix/M = matrix()
M.Scale(world.view*3)
transform = M
verbs.Cut()
/obj/abstract/screen/plane/dark
blend_mode = BLEND_ADD
mouse_opacity = 0
plane = LIGHTING_PLANE // Just below the master plane.
icon = 'icons/lighting/over_dark.dmi'
alpha = 10
appearance_flags = RESET_TRANSFORM | RESET_COLOR | RESET_ALPHA
var/list/alphas = list()
var/colours = null // will animate() to that colour next check_dark_vision()
/obj/abstract/screen/plane/dark/New()
..()
var/matrix/M = matrix()
M.Scale(world.view*2.2)
transform = M
Our light object:
/atom/movable/light
appearance_flags = KEEP_TOGETHER
plane = LIGHTING_PLANE
Casting a light consists of adding together semi-transparent objects which are then assigned to the atom's overlays.
So far playing with RESET_COLOR has not helped.
Thank you for your help.
a1 = A(L1)/(A(L1)+A(L2))
a2 = A(L2)/(A(L1)+A(L2))
R(L1+L2) = sqrt(a1*R(L1)*a2*R(L2))
G(L1+L2) = sqrt(a1*G(L1)*a2*G(L2))
B(L1+L2) = sqrt(a1*B(L1)*a2*B(L2))
A(L1+L2) = A(L1)+A(L2)
I am actually not sure if this is possible given BYOND's current features, but as a special new BLEND_MODE it would be extremely satisfying.