448 lines
20 KiB
Lua
448 lines
20 KiB
Lua
--- === hs.redshift ===
|
|
---
|
|
--- Inverts and/or lowers the color temperature of the screen(s) on a schedule, for a more pleasant experience at night
|
|
---
|
|
--- Usage:
|
|
--- ```
|
|
--- -- make a windowfilterDisable for redshift: VLC, Photos and screensaver/login window will disable color adjustment and inversion
|
|
--- local wfRedshift=hs.window.filter.new({VLC={focused=true},Photos={focused=true},loginwindow={visible=true,allowRoles='*'}},'wf-redshift')
|
|
--- -- start redshift: 2800K + inverted from 21 to 7, very long transition duration (19->23 and 5->9)
|
|
--- hs.redshift.start(2800,'21:00','7:00','4h',true,wfRedshift)
|
|
--- -- allow manual control of inverted colors
|
|
--- hs.hotkey.bind(HYPER,'f1','Invert',hs.redshift.toggleInvert)
|
|
--- ```
|
|
---
|
|
--- Note:
|
|
--- * As of macOS 10.12.4, Apple provides "Night Shift", which implements a simple red-shift effect, as part of the OS. It seems unlikely that `hs.redshift` will see significant future development.
|
|
|
|
local screen=require'hs.screen'
|
|
local timer=require'hs.timer'
|
|
local windowfilter=require'hs.window.filter'
|
|
local settings=require'hs.settings'
|
|
local log=require'hs.logger'.new('redshift')
|
|
local redshift={setLogLevel=log.setLogLevel} -- module
|
|
|
|
local type,ipairs,pairs,next,floor,abs,min,max,sformat=type,ipairs,pairs,next,math.floor,math.abs,math.min,math.max,string.format
|
|
|
|
local SETTING_INVERTED_OVERRIDE='hs.redshift.inverted.override'
|
|
local SETTING_DISABLED_OVERRIDE='hs.redshift.disabled.override'
|
|
--local BLACKPOINT = {red=0.00000001,green=0.00000001,blue=0.00000001}
|
|
local BLACKPOINT = {red=0,green=0,blue=0}
|
|
--local COLORRAMP
|
|
|
|
local running,nightStart,nightEnd,dayStart,dayEnd,nightTemp,dayTemp
|
|
local tmr,tmrNext,applyGamma,screenWatcher
|
|
local invertRequests,invertCallbacks,invertAtNight,invertUser,prevInvert={},{}
|
|
local disableRequests,disableUser={}
|
|
local wfDisable,modulewfDisable
|
|
|
|
local function round(v) return floor(0.5+v) end
|
|
local function lerprgb(p,a,b) return {red=a[1]*(1-p)+b[1]*p,green=a[2]*(1-p)+b[2]*p,blue=a[3]*(1-p)+b[3]*p} end
|
|
local function ilerp(v,s,e,a,b)
|
|
if s>e then
|
|
if v<e then v=v+86400 end
|
|
e=e+86400
|
|
end
|
|
local p=(v-s)/(e-s)
|
|
return a*(1-p)+b*p
|
|
end
|
|
local function getGamma(temp)
|
|
local R,lb,ub=redshift.COLORRAMP
|
|
for k,_ in pairs(R) do
|
|
if k<=temp then lb=max(lb or 0,k) else ub=min(ub or 10000,k) end
|
|
end
|
|
if lb==nil or ub==nil then local t=R[ub or lb] return {red=t[1],green=t[2],blue=t[3]} end
|
|
local p=(temp-lb)/(ub-lb)
|
|
return lerprgb(p,R[lb],R[ub])
|
|
-- local idx=floor(temp/100)-9
|
|
-- local p=(temp%100)/100
|
|
-- return lerprgb(p,COLORRAMP[idx],COLORRAMP[idx+1])
|
|
end
|
|
local function between(v,s,e)
|
|
if s<=e then return v>=s and v<=e else return v>=s or v<=e end
|
|
end
|
|
|
|
local function isInverted()
|
|
if not running then return false end
|
|
if invertUser~=nil then return invertUser and 'user'
|
|
else return next(invertRequests) or false end
|
|
end
|
|
local function isDisabled()
|
|
if not running then return true end
|
|
if disableUser~=nil then return disableUser and 'user'
|
|
else return next(disableRequests) or false end
|
|
end
|
|
|
|
-- core fn
|
|
applyGamma=function()
|
|
if tmrNext then tmrNext:stop() tmrNext=nil end
|
|
local now=timer.localTime()
|
|
local temp,timeNext,invertReq
|
|
if isDisabled() then temp=6500 timeNext=now-1 log.i('disabled')
|
|
elseif between(now,nightStart,nightEnd) then temp=ilerp(now,nightStart,nightEnd,dayTemp,nightTemp) --dusk
|
|
elseif between(now,dayStart,dayEnd) then temp=ilerp(now,dayStart,dayEnd,nightTemp,dayTemp) --dawn
|
|
elseif between(now,dayEnd,nightStart) then temp=dayTemp timeNext=nightStart log.i('daytime')--day
|
|
elseif between(now,nightEnd,dayStart) then invertReq=invertAtNight temp=nightTemp timeNext=dayStart log.i('nighttime')--night
|
|
else error('wtf') end
|
|
redshift.requestInvert('redshift-night',invertReq)
|
|
local invert=isInverted()
|
|
local gamma=getGamma(temp)
|
|
log.df('set color temperature %dK (gamma %d,%d,%d)%s',floor(temp),round(gamma.red*100),
|
|
round(gamma.green*100),round(gamma.blue*100),invert and (' - inverted by '..invert) or '')
|
|
for _,scr in ipairs(screen.allScreens()) do
|
|
scr:setGamma(invert and BLACKPOINT or gamma,invert and gamma or BLACKPOINT)
|
|
end
|
|
if invert~=prevInvert then
|
|
log.i('inverted status changed',next(invertCallbacks) and '- notifying callbacks' or '')
|
|
for _,fn in pairs(invertCallbacks) do fn(invert) end
|
|
prevInvert=invert
|
|
end
|
|
if timeNext then
|
|
tmrNext=timer.doAt(timeNext,applyGamma)
|
|
else
|
|
tmr:start()
|
|
end
|
|
end
|
|
|
|
--- hs.redshift.invertSubscribe([id,]fn)
|
|
--- Function
|
|
--- Subscribes a callback to be notified when the color inversion status changes
|
|
---
|
|
--- Parameters:
|
|
--- * id - (optional) a string identifying the requester (usually the module name); if omitted, `fn` itself will be the identifier; this identifier must be passed to `hs.redshift.invertUnsubscribe()`
|
|
--- * fn - a function that will be called whenever color inversion status changes; it must accept a single parameter, a string or false as per the return value of `hs.redshift.isInverted()`
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
---
|
|
--- Notes:
|
|
--- * You can use this to dynamically adjust the UI colors in your modules or configuration, if appropriate.
|
|
function redshift.invertSubscribe(key,fn)
|
|
if type(key)=='function' then fn=key end
|
|
if type(key)~='string' and type(key)~='function' then error('invalid key',2) end
|
|
if type(fn)~='function' then error('invalid callback',2) end
|
|
invertCallbacks[key]=fn
|
|
log.i('add invert callback',key)
|
|
return running and fn(isInverted())
|
|
end
|
|
--- hs.redshift.invertUnsubscribe(id)
|
|
--- Function
|
|
--- Unsubscribes a previously subscribed color inversion change callback
|
|
---
|
|
--- Parameters:
|
|
--- * id - a string identifying the requester or the callback function itself, depending on how you
|
|
--- called `hs.redshift.invertSubscribe()`
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
function redshift.invertUnsubscribe(key)
|
|
if not invertCallbacks[key] then return end
|
|
log.i('remove invert callback',key)
|
|
invertCallbacks[key]=nil
|
|
end
|
|
|
|
--- hs.redshift.isInverted() -> string or false
|
|
--- Function
|
|
--- Checks if the colors are currently inverted
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * false if the colors are not currently inverted; otherwise, a string indicating the reason, one of:
|
|
--- * "user" for the user override (see `hs.redshift.toggleInvert()`)
|
|
--- * "redshift-night" if `hs.redshift.start()` was called with `invertAtNight` set to true,
|
|
--- and it's currently night time
|
|
--- * the ID string (usually the module name) provided to `hs.redshift.requestInvert()`, if another module requested color inversion
|
|
redshift.isInverted=isInverted
|
|
|
|
redshift.isDisabled=isDisabled
|
|
|
|
--- hs.redshift.requestInvert(id,v)
|
|
--- Function
|
|
--- Sets or clears a request for color inversion
|
|
---
|
|
--- Parameters:
|
|
--- * id - a string identifying the requester (usually the module name)
|
|
--- * v - a boolean indicating whether to invert the colors (if true) or clear any previous requests (if false or nil)
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
---
|
|
--- Notes:
|
|
--- * you can use this function e.g. to automatically invert colors if the ambient light sensor reading drops below
|
|
--- a certain threshold (`hs.brightness.DDCauto()` can optionally do exactly that)
|
|
--- * if the user's configuration doesn't explicitly start the redshift module, calling this will have no effect
|
|
|
|
local function request(t,k,v)
|
|
if type(k)~='string' then error('key must be a string',3) end
|
|
if v==false then v=nil end
|
|
if t[k]~=v then t[k]=v return true end
|
|
end
|
|
function redshift.requestInvert(key,v)
|
|
if request(invertRequests,key,v) then
|
|
log.f('invert request from %s %s',key,v and '' or 'canceled')
|
|
return running and applyGamma()
|
|
end
|
|
end
|
|
function redshift.requestDisable(key,v)
|
|
if request(disableRequests,key,v) then
|
|
log.f('disable color adjustment request from %s %s',key,v and '' or 'canceled')
|
|
return running and applyGamma()
|
|
end
|
|
end
|
|
|
|
--- hs.redshift.toggleInvert([v])
|
|
--- Function
|
|
--- Sets or clears the user override for color inversion.
|
|
---
|
|
--- Parameters:
|
|
--- * v - (optional) a boolean; if true, the override will invert the colors no matter what; if false, the override will disable color inversion no matter what; if omitted or nil, it will toggle the override, i.e. clear it if it's currently enforced, or set it to the opposite of the current color inversion status otherwise.
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
---
|
|
--- Notes:
|
|
--- * This function should be bound to a hotkey, e.g.: `hs.hotkey.bind('ctrl-cmd','=','Invert',hs.redshift.toggleInvert)`
|
|
function redshift.toggleInvert(v)
|
|
if not running then return end
|
|
if v==nil and invertUser==nil then v=not isInverted() end
|
|
if v~=nil and type(v)~='boolean' then error ('v must be a boolean or nil',2) end
|
|
log.f('invert user override%s',v==true and ': inverted' or (v==false and ': not inverted' or ' cancelled'))
|
|
if v==nil then settings.clear(SETTING_INVERTED_OVERRIDE)
|
|
else settings.set(SETTING_INVERTED_OVERRIDE,v) end
|
|
invertUser=v
|
|
return applyGamma()
|
|
end
|
|
|
|
--- hs.redshift.toggle([v])
|
|
--- Function
|
|
--- Sets or clears the user override for color temperature adjustment.
|
|
---
|
|
--- Parameters:
|
|
--- * v - (optional) a boolean; if true, the override will enable color temperature adjustment on the given schedule; if false, the override will disable color temperature adjustment; if omitted or nil, it will toggle the override, i.e. clear it if it's currently enforced, or set it to the opposite of the current color temperature adjustment status otherwise.
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
---
|
|
--- Notes:
|
|
--- * This function should be bound to a hotkey, e.g.: `hs.hotkey.bind('ctrl-cmd','-','Redshift',hs.redshift.toggle)`
|
|
function redshift.toggle(v)
|
|
if not running then return end
|
|
if v==nil then
|
|
if disableUser==nil then v=not isDisabled() end
|
|
elseif type(v)~='boolean' then error ('v must be a boolean or nil',2)
|
|
else v=not v end
|
|
log.f('color adjustment user override%s',v==true and ': disabled' or (v==false and ': enabled' or ' cancelled'))
|
|
if v==nil then settings.clear(SETTING_DISABLED_OVERRIDE)
|
|
else settings.set(SETTING_DISABLED_OVERRIDE,v) end
|
|
disableUser=v
|
|
return applyGamma()
|
|
end
|
|
|
|
--- hs.redshift.stop()
|
|
--- Function
|
|
--- Stops the module and disables color adjustment and color inversion
|
|
---
|
|
--- Parameters:
|
|
--- * None
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
function redshift.stop()
|
|
if not running then return end
|
|
log.i('stopped')
|
|
tmr:stop()
|
|
screen.restoreGamma()
|
|
if wfDisable then
|
|
if modulewfDisable then modulewfDisable:delete() modulewfDisable=nil
|
|
else wfDisable:unsubscribe(redshift.wfsubs) end
|
|
wfDisable=nil
|
|
end
|
|
if tmrNext then tmrNext:stop() tmrNext=nil end
|
|
screenWatcher:stop() screenWatcher=nil
|
|
running=nil
|
|
end
|
|
local function gc(t) return t.stop()end
|
|
|
|
local function stime(time)
|
|
return sformat('%02d:%02d:%02d',floor(time/3600),floor(time/60)%60,floor(time%60))
|
|
end
|
|
|
|
tmr=timer.delayed.new(10,applyGamma)
|
|
--- hs.redshift.start(colorTemp,nightStart,nightEnd[,transition[,invertAtNight[,windowfilterDisable[,dayColorTemp]]]])
|
|
--- Function
|
|
--- Sets the schedule and (re)starts the module
|
|
---
|
|
--- Parameters:
|
|
--- * colorTemp - a number indicating the desired color temperature (Kelvin) during the night cycle;
|
|
--- the recommended range is between 3600K and 1400K; lower values (minimum 1000K) result in a more pronounced adjustment
|
|
--- * nightStart - a string in the format "HH:MM" (24-hour clock) or number of seconds after midnight
|
|
--- (see `hs.timer.seconds()`) indicating when the night cycle should start
|
|
--- * nightEnd - a string in the format "HH:MM" (24-hour clock) or number of seconds after midnight
|
|
--- (see `hs.timer.seconds()`) indicating when the night cycle should end
|
|
--- * transition - (optional) a string or number of seconds (see `hs.timer.seconds()`) indicating the duration of
|
|
--- the transition to the night color temperature and back; if omitted, defaults to 1 hour
|
|
--- * invertAtNight - (optional) a boolean indicating whether the colors should be inverted (in addition to
|
|
--- the color temperature shift) during the night; if omitted, defaults to false
|
|
--- * windowfilterDisable - (optional) an `hs.window.filter` instance that will disable color adjustment
|
|
--- (and color inversion) whenever any window is allowed; alternatively, you can just provide a list of application
|
|
--- names (typically media apps and/or apps for color-sensitive work) and a windowfilter will be created
|
|
--- for you that disables color adjustment whenever one of these apps is focused
|
|
--- * dayColorTemp - (optional) a number indicating the desired color temperature (in Kelvin) during the day cycle;
|
|
--- you can use this to maintain some degree of "redshift" during the day as well, or, if desired, you can
|
|
--- specify a value higher than 6500K (up to 10000K) for more bluish colors, although that's not recommended;
|
|
--- if omitted, defaults to 6500K, which disables color adjustment and restores your screens' original color profiles
|
|
---
|
|
--- Returns:
|
|
--- * None
|
|
function redshift.start(nTemp,nStart,nEnd,dur,invert,wf,dTemp)
|
|
if not dTemp then dTemp=6500 end
|
|
if nTemp<1000 or nTemp>10000 or dTemp<1000 or dTemp>10000 then error('invalid color temperature',2) end
|
|
nStart,nEnd=timer.seconds(nStart),timer.seconds(nEnd)
|
|
dur=timer.seconds(dur or 3600)
|
|
if dur>14400 then error('max transition time is 4h',2) end
|
|
if abs(nStart-nEnd)<dur or abs(nStart-nEnd+86400)<dur
|
|
or abs(nStart-nEnd-86400)<dur then error('nightTime too close to dayTime',2) end
|
|
nightTemp,dayTemp=floor(nTemp),floor(dTemp)
|
|
redshift.stop()
|
|
|
|
invertAtNight=invert
|
|
nightStart,nightEnd=(nStart-dur/2)%86400,(nStart+dur/2)%86400
|
|
dayStart,dayEnd=(nEnd-dur/2)%86400,(nEnd+dur/2)%86400
|
|
log.f('started: %dK @ %s -> %dK @ %s,%s %dK @ %s -> %dK @ %s',
|
|
dayTemp,stime(nightStart),nightTemp,stime(nightEnd),invert and ' inverted,' or '',nightTemp,stime(dayStart),dayTemp,stime(dayEnd))
|
|
running=true
|
|
tmr:setDelay(max(1,dur/200))
|
|
screenWatcher=screen.watcher.new(function()tmr:start(5)end):start()
|
|
invertUser=settings.get(SETTING_INVERTED_OVERRIDE)
|
|
disableUser=settings.get(SETTING_DISABLED_OVERRIDE)
|
|
applyGamma()
|
|
if wf~=nil then
|
|
if windowfilter.iswf(wf) then wfDisable=wf
|
|
else
|
|
wfDisable=windowfilter.new(wf,'wf-redshift',log.getLogLevel())
|
|
modulewfDisable=wfDisable
|
|
if type(wf=='table') then
|
|
local isAppList=true
|
|
for k,v in pairs(wf) do
|
|
if type(k)~='number' or type(v)~='string' then isAppList=false break end
|
|
end
|
|
if isAppList then wfDisable:setOverrideFilter{focused=true} end
|
|
end
|
|
end
|
|
redshift.wfsubs={
|
|
[windowfilter.hasWindow]=function()redshift.requestDisable('wf-redshift',true)end,
|
|
[windowfilter.hasNoWindows]=function()redshift.requestDisable('wf-redshift')end,
|
|
}
|
|
wfDisable:subscribe(redshift.wfsubs,true)
|
|
end
|
|
end
|
|
|
|
--- hs.redshift.COLORRAMP
|
|
--- Variable
|
|
--- A table holding the gamma values for given color temperatures; each key must be a color temperature number in K (useful values are between
|
|
--- 1400 and 6500), and each value must be a list of 3 gamma numbers between 0 and 1 for red, green and blue respectively.
|
|
--- The table must have at least two entries (a lower and upper bound); the actual gamma values used for a given color temperature
|
|
--- are linearly interpolated between the two closest entries; linear interpolation isn't particularly precise for this use case,
|
|
--- so you should provide as many values as possible.
|
|
---
|
|
--- Notes:
|
|
--- * `hs.inspect(hs.redshift.COLORRAMP)` from the console will show you how the table is built
|
|
--- * the default ramp has entries from 1000K to 10000K every 100K
|
|
redshift.COLORRAMP={ -- from https://github.com/jonls/redshift/blob/master/src/colorramp.c
|
|
[1000]={1.00000000, 0.18172716, 0.00000000}, -- 1000K
|
|
[1100]={1.00000000, 0.25503671, 0.00000000}, -- 1100K
|
|
[1200]={1.00000000, 0.30942099, 0.00000000}, -- 1200K
|
|
[1300]={1.00000000, 0.35357379, 0.00000000}, -- ...
|
|
[1400]={1.00000000, 0.39091524, 0.00000000},
|
|
[1500]={1.00000000, 0.42322816, 0.00000000},
|
|
[1600]={1.00000000, 0.45159884, 0.00000000},
|
|
[1700]={1.00000000, 0.47675916, 0.00000000},
|
|
[1800]={1.00000000, 0.49923747, 0.00000000},
|
|
[1900]={1.00000000, 0.51943421, 0.00000000},
|
|
[2000]={1.00000000, 0.54360078, 0.08679949},
|
|
[2100]={1.00000000, 0.56618736, 0.14065513},
|
|
[2200]={1.00000000, 0.58734976, 0.18362641},
|
|
[2300]={1.00000000, 0.60724493, 0.22137978},
|
|
[2400]={1.00000000, 0.62600248, 0.25591950},
|
|
[2500]={1.00000000, 0.64373109, 0.28819679},
|
|
[2600]={1.00000000, 0.66052319, 0.31873863},
|
|
[2700]={1.00000000, 0.67645822, 0.34786758},
|
|
[2800]={1.00000000, 0.69160518, 0.37579588},
|
|
[2900]={1.00000000, 0.70602449, 0.40267128},
|
|
[3000]={1.00000000, 0.71976951, 0.42860152},
|
|
[3100]={1.00000000, 0.73288760, 0.45366838},
|
|
[3200]={1.00000000, 0.74542112, 0.47793608},
|
|
[3300]={1.00000000, 0.75740814, 0.50145662},
|
|
[3400]={1.00000000, 0.76888303, 0.52427322},
|
|
[3500]={1.00000000, 0.77987699, 0.54642268},
|
|
[3600]={1.00000000, 0.79041843, 0.56793692},
|
|
[3700]={1.00000000, 0.80053332, 0.58884417},
|
|
[3800]={1.00000000, 0.81024551, 0.60916971},
|
|
[3900]={1.00000000, 0.81957693, 0.62893653},
|
|
[4000]={1.00000000, 0.82854786, 0.64816570},
|
|
[4100]={1.00000000, 0.83717703, 0.66687674},
|
|
[4200]={1.00000000, 0.84548188, 0.68508786},
|
|
[4300]={1.00000000, 0.85347859, 0.70281616},
|
|
[4400]={1.00000000, 0.86118227, 0.72007777},
|
|
[4500]={1.00000000, 0.86860704, 0.73688797},
|
|
[4600]={1.00000000, 0.87576611, 0.75326132},
|
|
[4700]={1.00000000, 0.88267187, 0.76921169},
|
|
[4800]={1.00000000, 0.88933596, 0.78475236},
|
|
[4900]={1.00000000, 0.89576933, 0.79989606},
|
|
[5000]={1.00000000, 0.90198230, 0.81465502},
|
|
[5100]={1.00000000, 0.90963069, 0.82838210},
|
|
[5200]={1.00000000, 0.91710889, 0.84190889},
|
|
[5300]={1.00000000, 0.92441842, 0.85523742},
|
|
[5400]={1.00000000, 0.93156127, 0.86836903},
|
|
[5500]={1.00000000, 0.93853986, 0.88130458},
|
|
[5600]={1.00000000, 0.94535695, 0.89404470},
|
|
[5700]={1.00000000, 0.95201559, 0.90658983},
|
|
[5800]={1.00000000, 0.95851906, 0.91894041},
|
|
[5900]={1.00000000, 0.96487079, 0.93109690},
|
|
[6000]={1.00000000, 0.97107439, 0.94305985},
|
|
[6100]={1.00000000, 0.97713351, 0.95482993},
|
|
[6200]={1.00000000, 0.98305189, 0.96640795},
|
|
[6300]={1.00000000, 0.98883326, 0.97779486},
|
|
[6400]={1.00000000, 0.99448139, 0.98899179},
|
|
[6500]={1.00000000, 1.00000000, 1.00000000}, -- 6500K
|
|
-- [6500]={0.99999997, 0.99999997, 0.99999997}, --6500K
|
|
[6600]={0.98947904, 0.99348723, 1.00000000},
|
|
[6700]={0.97940448, 0.98722715, 1.00000000},
|
|
[6800]={0.96975025, 0.98120637, 1.00000000},
|
|
[6900]={0.96049223, 0.97541240, 1.00000000},
|
|
[7000]={0.95160805, 0.96983355, 1.00000000},
|
|
[7100]={0.94303638, 0.96443333, 1.00000000},
|
|
[7200]={0.93480451, 0.95923080, 1.00000000},
|
|
[7300]={0.92689056, 0.95421394, 1.00000000},
|
|
[7400]={0.91927697, 0.94937330, 1.00000000},
|
|
[7500]={0.91194747, 0.94470005, 1.00000000},
|
|
[7600]={0.90488690, 0.94018594, 1.00000000},
|
|
[7700]={0.89808115, 0.93582323, 1.00000000},
|
|
[7800]={0.89151710, 0.93160469, 1.00000000},
|
|
[7900]={0.88518247, 0.92752354, 1.00000000},
|
|
[8000]={0.87906581, 0.92357340, 1.00000000},
|
|
[8100]={0.87315640, 0.91974827, 1.00000000},
|
|
[8200]={0.86744421, 0.91604254, 1.00000000},
|
|
[8300]={0.86191983, 0.91245088, 1.00000000},
|
|
[8400]={0.85657444, 0.90896831, 1.00000000},
|
|
[8500]={0.85139976, 0.90559011, 1.00000000},
|
|
[8600]={0.84638799, 0.90231183, 1.00000000},
|
|
[8700]={0.84153180, 0.89912926, 1.00000000},
|
|
[8800]={0.83682430, 0.89603843, 1.00000000},
|
|
[8900]={0.83225897, 0.89303558, 1.00000000},
|
|
[9000]={0.82782969, 0.89011714, 1.00000000},
|
|
[9100]={0.82353066, 0.88727974, 1.00000000},
|
|
[9200]={0.81935641, 0.88452017, 1.00000000},
|
|
[9300]={0.81530175, 0.88183541, 1.00000000},
|
|
[9400]={0.81136180, 0.87922257, 1.00000000},
|
|
[9500]={0.80753191, 0.87667891, 1.00000000},
|
|
[9600]={0.80380769, 0.87420182, 1.00000000},
|
|
[9700]={0.80018497, 0.87178882, 1.00000000},
|
|
[9800]={0.79665980, 0.86943756, 1.00000000},
|
|
[9900]={0.79322843, 0.86714579, 1.00000000},
|
|
[10000]={0.78988728, 0.86491137, 1.00000000}, -- 10000K
|
|
}
|
|
return setmetatable(redshift,{__gc=gc})
|