[Coders needed] Colored light sources
Posted: Mon Apr 15, 2013 18:20
I've always wanted the ability to specify colored lights in Minetest. Someone already did that long ago, but the code is gone and likely wouldn't integrate with the latest source. This is unrelated to the discussion of hardware lighting, and is about achieving colored light sources with the existing voxel lighting.
Today I spent several hours trying to figure out how this could be done, hoping I could implement it myself. The lighting code is huger than I thought however (and IMO than necessary), and I could barely figure out half of what would need to be done. I won't be able to do this alone, at least not without some clear explanations. So here's what I figured out, for everyone else who wants this feature and wishes to help:
________________________________
First of all, we'd need a new Lua parameter which can be used to define the color of a light separately from its intensity, as well as different code functions for that. For the torch, light emission is defined in the following line of init.lua: light_source = LIGHT_MAX-1. My idea was to add something of the type light_color = { r = 0, g = 0.5, b = 1 } where each parameter multiplies light on that color channel. It would not interfere with light intensity, and if not set all values would be initialized as 1 (unchanged from how lights work now).
That's the easy part, but now comes the first problem: Light RGB needs to be calculated for each node (face or vertice). So for example, if you place a red torch then a green torch two nodes away, the node in between should be yellow. Torches already have a distance and intensity, so I assume it would need to be calculated in the same spot (only for 3 values instead of 1). Where would that be though?
Second problem is storing light colors. Light intensity is stored in param1 for nodes, which can hold a single value but uses bits (which I'm very bad at understanding). I assume that currently it uses 1 bit for intensity. In this case it would need to store 4 bits in total (Intensity, Red, Green, Blue). I did however find the functions where the work needs to be done: mapnode.cpp lines 47 and 66 (MapNode::setLight and MapNode::getLight). Problem is that from what I saw, param1 is saved and wrote in a million places, and I have no idea in how many areas it would need to be adapted.
Third concern is how to actually apply the colored lighting. This one I managed to figure out however; Light colors are already used to make moonlight blue. When shaders are disabled, that's done in mapblock_mesh line 337 (static void finalColorBlend). When shaders are enabled, it's in test_shader_1 file opengl_vertex.glsl. Note that light intensity is parsed as a fake SColor... where the Red means sun light, Green means moon light, Blue means light sources. They're just intensities though... hacky way if you ask me. The blue channel is what we care about.
________________________________
Those are the things I investigated so far. Adding the Lua functions and changing the shader and finalColorBlend are things I can do, but I don't know the rest. If anyone else wants this feature and is willing to code that part, I would be grateful. This has already been done once, and if someone could find the old code it might be very useful. Let me know what you think.
Today I spent several hours trying to figure out how this could be done, hoping I could implement it myself. The lighting code is huger than I thought however (and IMO than necessary), and I could barely figure out half of what would need to be done. I won't be able to do this alone, at least not without some clear explanations. So here's what I figured out, for everyone else who wants this feature and wishes to help:
________________________________
First of all, we'd need a new Lua parameter which can be used to define the color of a light separately from its intensity, as well as different code functions for that. For the torch, light emission is defined in the following line of init.lua: light_source = LIGHT_MAX-1. My idea was to add something of the type light_color = { r = 0, g = 0.5, b = 1 } where each parameter multiplies light on that color channel. It would not interfere with light intensity, and if not set all values would be initialized as 1 (unchanged from how lights work now).
That's the easy part, but now comes the first problem: Light RGB needs to be calculated for each node (face or vertice). So for example, if you place a red torch then a green torch two nodes away, the node in between should be yellow. Torches already have a distance and intensity, so I assume it would need to be calculated in the same spot (only for 3 values instead of 1). Where would that be though?
Second problem is storing light colors. Light intensity is stored in param1 for nodes, which can hold a single value but uses bits (which I'm very bad at understanding). I assume that currently it uses 1 bit for intensity. In this case it would need to store 4 bits in total (Intensity, Red, Green, Blue). I did however find the functions where the work needs to be done: mapnode.cpp lines 47 and 66 (MapNode::setLight and MapNode::getLight). Problem is that from what I saw, param1 is saved and wrote in a million places, and I have no idea in how many areas it would need to be adapted.
Third concern is how to actually apply the colored lighting. This one I managed to figure out however; Light colors are already used to make moonlight blue. When shaders are disabled, that's done in mapblock_mesh line 337 (static void finalColorBlend). When shaders are enabled, it's in test_shader_1 file opengl_vertex.glsl. Note that light intensity is parsed as a fake SColor... where the Red means sun light, Green means moon light, Blue means light sources. They're just intensities though... hacky way if you ask me. The blue channel is what we care about.
________________________________
Those are the things I investigated so far. Adding the Lua functions and changing the shader and finalColorBlend are things I can do, but I don't know the rest. If anyone else wants this feature and is willing to code that part, I would be grateful. This has already been done once, and if someone could find the old code it might be very useful. Let me know what you think.