Ok... this took waaaaay longer than I thought it would, but it's all working now.
Here's the Lua:
Code: Select all
function gadget:GetInfo()
return {
name = "GLSL Lighting",
desc = "The P.U.R.E. GLSL Realtime lighting implementation.",
author = "Argh",
date = "November 4, 2008",
license = "Public Domain, or the least-restrictive rights in your country of residence",
layer = 0,
--handler = true,
enabled = true -- loaded by default?
}
end
if (gadgetHandler:IsSyncedCode()) then
----------------------------------------------------------------------------------------------------------SYNCED
local function CreateLightMe(u, ud, team, p, r, g, b, a)
p = Spring.GetUnitScriptPiece(u,p)
SendToUnsynced("CreateLight",u, ud, team, p, r, g, b, a)
end
local function DestroyLightMe(u, ud, team)
SendToUnsynced("DestroyLight",u, ud, team)
end
function gadget:Initialize()
gadgetHandler:RegisterGlobal("CreateLightMe", CreateLightMe)
gadgetHandler:RegisterGlobal("DestroyLightMe", DestroyLightMe)
end
function gadget:UnitDestroyed(u,ud,team)
SendToUnsynced("DestroyLight",u, ud, team)
end
----------------------------------------------------------------------------------------------------------END SYNCED
else
----------------------------------------------------------------------------------------------------------UNSYNCED
local UseShader = 0
local LP
function gadget:Initialize()
GLSL_LIGHT_Shader = gl.CreateShader({
vertex = [[
void main() {
vec3 normal, lightDir;
vec4 diffuse;
float NdotL;
normal = normalize(gl_NormalMatrix * gl_Normal);
lightDir = normalize(gl_LightSource[0].position);
NdotL = max(dot(normal, lightDir), 0.0);
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
gl_FrontColor = NdotL * diffuse;
gl_Position = ftransform();
}
]],
fragment = [[
void main()
{
gl_FragColor = gl_Color;
}
]],
})
if (GLSL_LIGHT_Shader == nil) then
Spring.Echo("GLSL Light Shader Failed"..gl.GetShaderLog())
return false
else
Spring.Echo("GLSL Light Shader Succeeded")
UseShader = 1;
end
end
local tinsert = table.insert
local tremove = table.remove
local LightList = {unit, piece, red, green, blue, alpha}
local GetUnitPiecePosDir = Spring.GetUnitPiecePosDir
function gadget:RecvFromSynced(name, u, ud, team, p, r, g, b, a)
if name == "CreateLight" then
for k, v in ipairs (LightList) do
if v.unit == u then
tremove (LightList,k)
end
end
tinsert (LightList,{unit = u, piece = p, red = r, green = g, blue = b, alpha = a})
elseif name == "DestroyLight" then
for k, v in ipairs (LightList) do
if v.unit == u then
tremove (LightList,k)
end
end
end
end
function gadget:DrawWorld()
if UseShader == 1 and LightList[1] ~nil then
local myIDList = Spring.GetVisibleUnits(-1,3000,false)
if myIDList[1] ~= nil then
for _,myID in ipairs(myIDList) do
if (Spring.IsUnitVisible(myID)) then
for _,id in ipairs(LightList) do
if id.unit == myID then
gl.DepthTest(GL.LEQUAL)
gl.Culling(GL.BACK)
gl.Blending(true)
gl.Lighting(true)
local x,y,z = Spring.GetUnitPiecePosition(id.unit,id.piece)
--Spring.Echo(id.unit,id.piece,x,y,z)
gl.Light(0,GL.POSITION,-x,y,z)
gl.Material({diffuse = {id.red, id.green, id.blue, id.alpha},})
gl.UseShader(GLSL_LIGHT_Shader)
gl.PolygonOffset(-2,-2)
gl.Unit(myID,true)
gl.Light(0,false)
gl.PolygonOffset(0,0)
gl.ResetState()
gl.Lighting(false)
end
end
end
end
end
end
end
----------------------------------------------------------------------------------------------------------END
end
Then in BOS, just feed it:
call-script lua_CreateLightMe(light, 0, 1, 0, 1);
And voila:
And the best part is that it's nearly free- the hit CPU-wise is low, and the hit on the GPU is practically nil (of course, if the light list gets big enough, that will change, but meh, there's always a cost somewhere).
I'm going to expand this to include multiple lights here in a bit, after doing some cleanup, adding integer conversions for the light colors and speedups. But it's really quite cheap and very effective, and you can try it out now