Alright, so here goes:
First off, the first version probably wouldn't have colored lights because I'm not yet certain how one would set them up, and it
may have color bleeding, depending on how difficult it ends up being to get a texture and then average its pixels together into one color. So, for the purposes of this explanation, I will omit colored lighting, but retain color bleeding, as it is one of the most necessary features of something 'realistically' lit.
Ok, so let's set up this map!
First and most importantly, the map has to be set up properly by the mapper. The way I envision it, a new exclusive sector effect would be introduced not into the game or into SRB2DB but one that would only be recognized (and then eliminated) by the lighting script/executable/plug-in/whatever form it ends up taking. (I will hereby call it 'script' just because.) When a sector had this effect, the lighting script would recognize it as a 'light emitting sector' and then use its light value as the 'light intensity.'
For any sector with this effect (here just a random number), the script would automatically create a colormap tagged to that sector (and, when I get to it, somehow scooting around FOFs) with a light of #000000[conversion of light value out of 255 to opacity value out of 36] (this step is unneccessary for this demo and will be skipped). Then it would proceed to give other sectors bordering this sector that don't emit light colormaps based off of this value.
For the purposes of this demo (and also because I have not yet figured out how this function will actually work) I'll give these non-light-emitting sectors a light value of 128 so that they 'reflect' 50% of the light and also 'color' it by 50%. This will be total overkill but will help get the point across. Since I don't have a decay function yet, I'll say that a reflect value of 128 leads to a 'decay size' of 128. This is how far the light can travel before the script ends the sector and decreases the brightness. I've decided that, to prevent a ridiculous number of sectors from being created, the coloring will be reduced from a full 24 bits (RRGGBB) to only 12 bits (RGB). E.g., a color mixed that returns as #14B3C9 would round to #1BD and then be colormapped as #11BBDD, so it's more likely to share a tag and thus reduce the amount of crap the script creates. So, let's draw the first of these sectors and tag it up.
In order to do this, the script would 'step' 128 fracunits along the normal of every line forming the border between these sectors (I made it one here for simplicity). Then it would step the next 128, and so on...but wait! There's an outcropping there, and light can't go through an outcropping! No problem: here we must begin making the penumbra, or 'half-shadow,' of the cave entrance, using angles derived from the midpoint of the border line. I would probably add a 'penumbra resolution' function to determine the amount of splitting and checking the script must do, but for here I'll just do a resolution of one: one linedef split, and a check at that point.
The shaded area here is now only capable of receiving
half the light, if it can receive light at all. This is akin to a regular shadow check, only that it determines where the halfway point is for light projection.
Don't worry, this is confusing as hell for me to put into words, that's why I'm providing images.
We can then use the same idea to get the fully shadowed areas by using the angles of the far vertices. If they 'collide' before the object is reached, it gets a harder shadow based soley on the penumbra vertices. Then, fill in the light blocks, and voila!--the first lighting pass is complete.
Bringing it up in SRB2, we see it doesn't look bad--save for those ghastly full dark spots.
What brings about that anyhow?
Well, so far we've only calculated the direct lighting. There's indirect lighting too, meaning the light that reflects off of the unlit linedefs that then hits (and reflects ad infinitum). But bouncing to infinity would take far too long for a script such as this, so I decided that, given the buggy nature of colormaps (subtract 8 for half the intensity--???) and the fact that the innaccuracies multiply as the light iterates, only one bounce--for two light passes--should suffice. This one may take A LOT longer, so beware!
Alright, I simplified the geometry because all those funky angles...I just would explode trying to get my head around them all. This is why it should be automated :-)
So each of these linedefs now has to have the same process as the first border linedef applied to them, but with the light halved and mixed with 50% of the average color of its texture. So I loaded up GFZROCK in GIMP and found that its average color was #88440a. So each linedef reflects #442206, or #442200 if I simplify it (which I may not, in fact.) This is then multiplied by the current percentage of the light on the linedef and added to the current light of each new sector until it all peters out. So I'm gonna do this... ~sigh~
No, I'm not gonna do this. It'll take far too long. I'm just going to do one of the linedefs to show how the reflected light will have quite an impact. As well, a few tests of the light addition shows that 128 is actually too large a reflectivity value... 64 or perhaps even 32 would be much better suited to the task (I did a little bit of two linedefs' reflections added together and the reflections were brighter than just the first pass :-P ).
It doesn't look too bad either, and begins to demonstrate the 'color bleeding' properties of the reflected light:
Notice how the reflectively-lit areas have a reddish hue? That's because GFZROCK is made of primarily red light.
It's also important to note that the script keeps a record of each linedef's initial reflected light level in order to avoid accidental second reflections that could botch the light and get stuck recursively. So any impact created by a second reflection in this step would not impact the outcome of a linedef's reflected lighting.
Multiple lights are very easy with this method, as the values from one light are simply added to the existing values of the previous light, with sectors being broken up as they were before.
The only three "bugs" so far that I can think of is (1) the oddities that could ensue from odd occlusions of the different penumbra 'test rays.' But I'm certain that with an actual additive formula in place, this would easily just be ignored. (2) That it ignores FOFs. I don't know how I'd work around this one. (3) It's 'ground-biased,' meaning the function acts only for light falling on the ground; a short hump would cast a shadow through the whole sector behind it and light from an alcove above would not light what's below it at all.
And that...well, that took me a full day to write and execute and is basically a full summary of how this thing works.
Have test WAD.
Have my table I made up:
1 A 100%
2 B 93.75
3 C 87.5
4 D 81.25
5 E 75
6 F 68.75
7 G 62.5
8 H 56.25
9 I 50%
10 J 46.875
11 K 43.75
12 L 40.625
13 M 37.5
14 N 34.375
15 O 31.25
16 P 28.125
17 Q 25%
18 R 23.4375
19 S 21.875
20 T 20.3125
21 U 18.75
22 V 17.1875
23 W 15.625
24 X 14.0625
25 Y 12.5%
26 Z 11.71875
27 0
28 1
29 2
30 3
31 4
32 5
33 6 6.25%
34 7
35 8
36 9
And have fun! This could work!