mirror of
https://github.com/tanema/light_world.lua.git
synced 2024-12-24 20:24:19 +00:00
added back in some options in the short example to give a better refraction example
This commit is contained in:
parent
3c559635e9
commit
12b2bd8b32
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
.DS_Store
|
||||
light_world_profiling_report.txt
|
||||
|
@ -1,8 +1,11 @@
|
||||
-- Example: Animation Example
|
||||
local LightWorld = require "lib"
|
||||
local anim8 = require 'lib.anim8'
|
||||
local ProFi = require 'examples.vendor.ProFi'
|
||||
|
||||
function love.load()
|
||||
ProFi:start()
|
||||
|
||||
x, y, z, scale = 0, 0, 1, 1
|
||||
-- load images
|
||||
image = love.graphics.newImage("examples/gfx/scott_pilgrim.png")
|
||||
|
@ -1,5 +1,6 @@
|
||||
-- Example: Complex Example
|
||||
local LightWorld = require "lib"
|
||||
local ProFi = require 'examples.vendor.ProFi'
|
||||
|
||||
function initScene()
|
||||
-- physic world
|
||||
@ -32,6 +33,8 @@ function initScene()
|
||||
end
|
||||
|
||||
function love.load()
|
||||
ProFi:start()
|
||||
|
||||
love.graphics.setBackgroundColor(0, 0, 0)
|
||||
love.graphics.setDefaultFilter("nearest", "nearest")
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
-- Example: Short Example
|
||||
local LightWorld = require "lib"
|
||||
local ProFi = require 'examples.vendor.ProFi'
|
||||
|
||||
function love.load()
|
||||
ProFi:start()
|
||||
|
||||
testShader = 0
|
||||
x = 0
|
||||
y = 0
|
||||
@ -17,6 +20,8 @@ function love.load()
|
||||
-- create light world
|
||||
lightWorld = LightWorld({
|
||||
ambient = {55,55,55},
|
||||
refractionStrength = 32.0,
|
||||
reflectionVisibility = 0.75,
|
||||
})
|
||||
|
||||
-- create light
|
||||
@ -157,7 +162,9 @@ function love.draw()
|
||||
love.graphics.polygon("fill", polygonTest:getPoints())
|
||||
love.graphics.setColor(255, 255, 255)
|
||||
love.graphics.draw(image, 64 - image:getWidth() * 0.5, 64 - image:getHeight() * 0.5)
|
||||
|
||||
end)
|
||||
love.graphics.rectangle('line', lightMouse.x - lightMouse.range, lightMouse.y - lightMouse.range, lightMouse.range*2, lightMouse.range*2)
|
||||
love.graphics.pop()
|
||||
|
||||
love.graphics.setBlendMode("alpha")
|
||||
|
@ -1,8 +1,11 @@
|
||||
-- Example: STI Example
|
||||
local LightWorld = require "lib"
|
||||
local sti = require 'examples.vendor.sti'
|
||||
local ProFi = require 'examples.vendor.ProFi'
|
||||
|
||||
function love.load()
|
||||
ProFi:start()
|
||||
|
||||
x = 0
|
||||
y = 0
|
||||
z = 1
|
||||
|
456
examples/vendor/ProFi.lua
vendored
Normal file
456
examples/vendor/ProFi.lua
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
--[[
|
||||
ProFi v1.3, by Luke Perkin 2012. MIT Licence http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
Example:
|
||||
ProFi = require 'ProFi'
|
||||
ProFi:start()
|
||||
some_function()
|
||||
another_function()
|
||||
coroutine.resume( some_coroutine )
|
||||
ProFi:stop()
|
||||
ProFi:writeReport( 'MyProfilingReport.txt' )
|
||||
|
||||
API:
|
||||
*Arguments are specified as: type/name/default.
|
||||
ProFi:start( string/once/nil )
|
||||
ProFi:stop()
|
||||
ProFi:checkMemory( number/interval/0, string/note/'' )
|
||||
ProFi:writeReport( string/filename/'ProFi.txt' )
|
||||
ProFi:reset()
|
||||
ProFi:setHookCount( number/hookCount/0 )
|
||||
ProFi:setGetTimeMethod( function/getTimeMethod/os.clock )
|
||||
ProFi:setInspect( string/methodName, number/levels/1 )
|
||||
]]
|
||||
|
||||
-----------------------
|
||||
-- Locals:
|
||||
-----------------------
|
||||
|
||||
local ProFi = {}
|
||||
local onDebugHook, sortByDurationDesc, sortByCallCount, getTime
|
||||
local DEFAULT_DEBUG_HOOK_COUNT = 0
|
||||
local FORMAT_HEADER_LINE = "| %-50s: %-40s: %-20s: %-12s: %-12s: %-12s|\n"
|
||||
local FORMAT_OUTPUT_LINE = "| %s: %-12s: %-12s: %-12s|\n"
|
||||
local FORMAT_INSPECTION_LINE = "> %s: %-12s\n"
|
||||
local FORMAT_TOTALTIME_LINE = "| TOTAL TIME = %f\n"
|
||||
local FORMAT_MEMORY_LINE = "| %-20s: %-16s: %-16s| %s\n"
|
||||
local FORMAT_HIGH_MEMORY_LINE = "H %-20s: %-16s: %-16sH %s\n"
|
||||
local FORMAT_LOW_MEMORY_LINE = "L %-20s: %-16s: %-16sL %s\n"
|
||||
local FORMAT_TITLE = "%-50.50s: %-40.40s: %-20s"
|
||||
local FORMAT_LINENUM = "%4i"
|
||||
local FORMAT_TIME = "%04.3f"
|
||||
local FORMAT_RELATIVE = "%03.2f%%"
|
||||
local FORMAT_COUNT = "%7i"
|
||||
local FORMAT_KBYTES = "%7i Kbytes"
|
||||
local FORMAT_MBYTES = "%7.1f Mbytes"
|
||||
local FORMAT_MEMORY_HEADER1 = "\n=== HIGH & LOW MEMORY USAGE ===============================\n"
|
||||
local FORMAT_MEMORY_HEADER2 = "=== MEMORY USAGE ==========================================\n"
|
||||
local FORMAT_BANNER = [[
|
||||
###############################################################################################################
|
||||
##### ProFi, a lua profiler. This profile was generated on: %s
|
||||
##### ProFi is created by Luke Perkin 2012 under the MIT Licence, www.locofilm.co.uk
|
||||
##### Version 1.3. Get the most recent version at this gist: https://gist.github.com/2838755
|
||||
###############################################################################################################
|
||||
|
||||
]]
|
||||
|
||||
-----------------------
|
||||
-- Public Methods:
|
||||
-----------------------
|
||||
|
||||
--[[
|
||||
Starts profiling any method that is called between this and ProFi:stop().
|
||||
Pass the parameter 'once' to so that this methodis only run once.
|
||||
Example:
|
||||
ProFi:start( 'once' )
|
||||
]]
|
||||
function ProFi:start( param )
|
||||
if param == 'once' then
|
||||
if self:shouldReturn() then
|
||||
return
|
||||
else
|
||||
self.should_run_once = true
|
||||
end
|
||||
end
|
||||
self.has_started = true
|
||||
self.has_finished = false
|
||||
self:resetReports( self.reports )
|
||||
self:startHooks()
|
||||
self.startTime = getTime()
|
||||
end
|
||||
|
||||
--[[
|
||||
Stops profiling.
|
||||
]]
|
||||
function ProFi:stop()
|
||||
if self:shouldReturn() then
|
||||
return
|
||||
end
|
||||
self.stopTime = getTime()
|
||||
self:stopHooks()
|
||||
self.has_finished = true
|
||||
end
|
||||
|
||||
function ProFi:checkMemory( interval, note )
|
||||
local time = getTime()
|
||||
local interval = interval or 0
|
||||
if self.lastCheckMemoryTime and time < self.lastCheckMemoryTime + interval then
|
||||
return
|
||||
end
|
||||
self.lastCheckMemoryTime = time
|
||||
local memoryReport = {
|
||||
['time'] = time;
|
||||
['memory'] = collectgarbage('count');
|
||||
['note'] = note or '';
|
||||
}
|
||||
table.insert( self.memoryReports, memoryReport )
|
||||
self:setHighestMemoryReport( memoryReport )
|
||||
self:setLowestMemoryReport( memoryReport )
|
||||
end
|
||||
|
||||
--[[
|
||||
Writes the profile report to a file.
|
||||
Param: [filename:string:optional] defaults to 'ProFi.txt' if not specified.
|
||||
]]
|
||||
function ProFi:writeReport( filename )
|
||||
if #self.reports > 0 or #self.memoryReports > 0 then
|
||||
filename = filename or 'ProFi.txt'
|
||||
self:sortReportsWithSortMethod( self.reports, self.sortMethod )
|
||||
self:writeReportsToFilename( filename )
|
||||
print( string.format("[ProFi]\t Report written to %s", filename) )
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Resets any profile information stored.
|
||||
]]
|
||||
function ProFi:reset()
|
||||
self.reports = {}
|
||||
self.reportsByTitle = {}
|
||||
self.memoryReports = {}
|
||||
self.highestMemoryReport = nil
|
||||
self.lowestMemoryReport = nil
|
||||
self.has_started = false
|
||||
self.has_finished = false
|
||||
self.should_run_once = false
|
||||
self.lastCheckMemoryTime = nil
|
||||
self.hookCount = self.hookCount or DEFAULT_DEBUG_HOOK_COUNT
|
||||
self.sortMethod = self.sortMethod or sortByDurationDesc
|
||||
self.inspect = nil
|
||||
end
|
||||
|
||||
--[[
|
||||
Set how often a hook is called.
|
||||
See http://pgl.yoyo.org/luai/i/debug.sethook for information.
|
||||
Param: [hookCount:number] if 0 ProFi counts every time a function is called.
|
||||
if 2 ProFi counts every other 2 function calls.
|
||||
]]
|
||||
function ProFi:setHookCount( hookCount )
|
||||
self.hookCount = hookCount
|
||||
end
|
||||
|
||||
--[[
|
||||
Set how the report is sorted when written to file.
|
||||
Param: [sortType:string] either 'duration' or 'count'.
|
||||
'duration' sorts by the time a method took to run.
|
||||
'count' sorts by the number of times a method was called.
|
||||
]]
|
||||
function ProFi:setSortMethod( sortType )
|
||||
if sortType == 'duration' then
|
||||
self.sortMethod = sortByDurationDesc
|
||||
elseif sortType == 'count' then
|
||||
self.sortMethod = sortByCallCount
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
By default the getTime method is os.clock (CPU time),
|
||||
If you wish to use other time methods pass it to this function.
|
||||
Param: [getTimeMethod:function]
|
||||
]]
|
||||
function ProFi:setGetTimeMethod( getTimeMethod )
|
||||
getTime = getTimeMethod
|
||||
end
|
||||
|
||||
--[[
|
||||
Allows you to inspect a specific method.
|
||||
Will write to the report a list of methods that
|
||||
call this method you're inspecting, you can optionally
|
||||
provide a levels parameter to traceback a number of levels.
|
||||
Params: [methodName:string] the name of the method you wish to inspect.
|
||||
[levels:number:optional] the amount of levels you wish to traceback, defaults to 1.
|
||||
]]
|
||||
function ProFi:setInspect( methodName, levels )
|
||||
if self.inspect then
|
||||
self.inspect.methodName = methodName
|
||||
self.inspect.levels = levels or 1
|
||||
else
|
||||
self.inspect = {
|
||||
['methodName'] = methodName;
|
||||
['levels'] = levels or 1;
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------
|
||||
-- Implementations methods:
|
||||
-----------------------
|
||||
|
||||
function ProFi:shouldReturn( )
|
||||
return self.should_run_once and self.has_finished
|
||||
end
|
||||
|
||||
function ProFi:getFuncReport( funcInfo )
|
||||
local title = self:getTitleFromFuncInfo( funcInfo )
|
||||
local funcReport = self.reportsByTitle[ title ]
|
||||
if not funcReport then
|
||||
funcReport = self:createFuncReport( funcInfo )
|
||||
self.reportsByTitle[ title ] = funcReport
|
||||
table.insert( self.reports, funcReport )
|
||||
end
|
||||
return funcReport
|
||||
end
|
||||
|
||||
function ProFi:getTitleFromFuncInfo( funcInfo )
|
||||
local name = funcInfo.name or 'anonymous'
|
||||
local source = funcInfo.short_src or 'C_FUNC'
|
||||
local linedefined = funcInfo.linedefined or 0
|
||||
linedefined = string.format( FORMAT_LINENUM, linedefined )
|
||||
return string.format(FORMAT_TITLE, source, name, linedefined)
|
||||
end
|
||||
|
||||
function ProFi:createFuncReport( funcInfo )
|
||||
local name = funcInfo.name or 'anonymous'
|
||||
local source = funcInfo.source or 'C Func'
|
||||
local linedefined = funcInfo.linedefined or 0
|
||||
local funcReport = {
|
||||
['title'] = self:getTitleFromFuncInfo( funcInfo );
|
||||
['count'] = 0;
|
||||
['timer'] = 0;
|
||||
}
|
||||
return funcReport
|
||||
end
|
||||
|
||||
function ProFi:startHooks()
|
||||
debug.sethook( onDebugHook, 'cr', self.hookCount )
|
||||
end
|
||||
|
||||
function ProFi:stopHooks()
|
||||
debug.sethook()
|
||||
end
|
||||
|
||||
function ProFi:sortReportsWithSortMethod( reports, sortMethod )
|
||||
if reports then
|
||||
table.sort( reports, sortMethod )
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:writeReportsToFilename( filename )
|
||||
local file, err = io.open( filename, 'w' )
|
||||
assert( file, err )
|
||||
self:writeBannerToFile( file )
|
||||
if #self.reports > 0 then
|
||||
self:writeProfilingReportsToFile( self.reports, file )
|
||||
end
|
||||
if #self.memoryReports > 0 then
|
||||
self:writeMemoryReportsToFile( self.memoryReports, file )
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
|
||||
function ProFi:writeProfilingReportsToFile( reports, file )
|
||||
local totalTime = self.stopTime - self.startTime
|
||||
local totalTimeOutput = string.format(FORMAT_TOTALTIME_LINE, totalTime)
|
||||
file:write( totalTimeOutput )
|
||||
local header = string.format( FORMAT_HEADER_LINE, "FILE", "FUNCTION", "LINE", "TIME", "RELATIVE", "CALLED" )
|
||||
file:write( header )
|
||||
for i, funcReport in ipairs( reports ) do
|
||||
local timer = string.format(FORMAT_TIME, funcReport.timer)
|
||||
local count = string.format(FORMAT_COUNT, funcReport.count)
|
||||
local relTime = string.format(FORMAT_RELATIVE, (funcReport.timer / totalTime) * 100 )
|
||||
local outputLine = string.format(FORMAT_OUTPUT_LINE, funcReport.title, timer, relTime, count )
|
||||
file:write( outputLine )
|
||||
if funcReport.inspections then
|
||||
self:writeInpsectionsToFile( funcReport.inspections, file )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:writeMemoryReportsToFile( reports, file )
|
||||
file:write( FORMAT_MEMORY_HEADER1 )
|
||||
self:writeHighestMemoryReportToFile( file )
|
||||
self:writeLowestMemoryReportToFile( file )
|
||||
file:write( FORMAT_MEMORY_HEADER2 )
|
||||
for i, memoryReport in ipairs( reports ) do
|
||||
local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_MEMORY_LINE )
|
||||
file:write( outputLine )
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:writeHighestMemoryReportToFile( file )
|
||||
local memoryReport = self.highestMemoryReport
|
||||
local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_HIGH_MEMORY_LINE )
|
||||
file:write( outputLine )
|
||||
end
|
||||
|
||||
function ProFi:writeLowestMemoryReportToFile( file )
|
||||
local memoryReport = self.lowestMemoryReport
|
||||
local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_LOW_MEMORY_LINE )
|
||||
file:write( outputLine )
|
||||
end
|
||||
|
||||
function ProFi:formatMemoryReportWithFormatter( memoryReport, formatter )
|
||||
local time = string.format(FORMAT_TIME, memoryReport.time)
|
||||
local kbytes = string.format(FORMAT_KBYTES, memoryReport.memory)
|
||||
local mbytes = string.format(FORMAT_MBYTES, memoryReport.memory/1024)
|
||||
local outputLine = string.format(formatter, time, kbytes, mbytes, memoryReport.note)
|
||||
return outputLine
|
||||
end
|
||||
|
||||
function ProFi:writeBannerToFile( file )
|
||||
local banner = string.format(FORMAT_BANNER, os.date())
|
||||
file:write( banner )
|
||||
end
|
||||
|
||||
function ProFi:writeInpsectionsToFile( inspections, file )
|
||||
local inspectionsList = self:sortInspectionsIntoList( inspections )
|
||||
file:write('\n==^ INSPECT ^======================================================================================================== COUNT ===\n')
|
||||
for i, inspection in ipairs( inspectionsList ) do
|
||||
local line = string.format(FORMAT_LINENUM, inspection.line)
|
||||
local title = string.format(FORMAT_TITLE, inspection.source, inspection.name, line)
|
||||
local count = string.format(FORMAT_COUNT, inspection.count)
|
||||
local outputLine = string.format(FORMAT_INSPECTION_LINE, title, count )
|
||||
file:write( outputLine )
|
||||
end
|
||||
file:write('===============================================================================================================================\n\n')
|
||||
end
|
||||
|
||||
function ProFi:sortInspectionsIntoList( inspections )
|
||||
local inspectionsList = {}
|
||||
for k, inspection in pairs(inspections) do
|
||||
inspectionsList[#inspectionsList+1] = inspection
|
||||
end
|
||||
table.sort( inspectionsList, sortByCallCount )
|
||||
return inspectionsList
|
||||
end
|
||||
|
||||
function ProFi:resetReports( reports )
|
||||
for i, report in ipairs( reports ) do
|
||||
report.timer = 0
|
||||
report.count = 0
|
||||
report.inspections = nil
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:shouldInspect( funcInfo )
|
||||
return self.inspect and self.inspect.methodName == funcInfo.name
|
||||
end
|
||||
|
||||
function ProFi:getInspectionsFromReport( funcReport )
|
||||
local inspections = funcReport.inspections
|
||||
if not inspections then
|
||||
inspections = {}
|
||||
funcReport.inspections = inspections
|
||||
end
|
||||
return inspections
|
||||
end
|
||||
|
||||
function ProFi:getInspectionWithKeyFromInspections( key, inspections )
|
||||
local inspection = inspections[key]
|
||||
if not inspection then
|
||||
inspection = {
|
||||
['count'] = 0;
|
||||
}
|
||||
inspections[key] = inspection
|
||||
end
|
||||
return inspection
|
||||
end
|
||||
|
||||
function ProFi:doInspection( inspect, funcReport )
|
||||
local inspections = self:getInspectionsFromReport( funcReport )
|
||||
local levels = 5 + inspect.levels
|
||||
local currentLevel = 5
|
||||
while currentLevel < levels do
|
||||
local funcInfo = debug.getinfo( currentLevel, 'nS' )
|
||||
if funcInfo then
|
||||
local source = funcInfo.short_src or '[C]'
|
||||
local name = funcInfo.name or 'anonymous'
|
||||
local line = funcInfo.linedefined
|
||||
local key = source..name..line
|
||||
local inspection = self:getInspectionWithKeyFromInspections( key, inspections )
|
||||
inspection.source = source
|
||||
inspection.name = name
|
||||
inspection.line = line
|
||||
inspection.count = inspection.count + 1
|
||||
currentLevel = currentLevel + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:onFunctionCall( funcInfo )
|
||||
local funcReport = ProFi:getFuncReport( funcInfo )
|
||||
funcReport.callTime = getTime()
|
||||
funcReport.count = funcReport.count + 1
|
||||
if self:shouldInspect( funcInfo ) then
|
||||
self:doInspection( self.inspect, funcReport )
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:onFunctionReturn( funcInfo )
|
||||
local funcReport = ProFi:getFuncReport( funcInfo )
|
||||
if funcReport.callTime then
|
||||
funcReport.timer = funcReport.timer + (getTime() - funcReport.callTime)
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:setHighestMemoryReport( memoryReport )
|
||||
if not self.highestMemoryReport then
|
||||
self.highestMemoryReport = memoryReport
|
||||
else
|
||||
if memoryReport.memory > self.highestMemoryReport.memory then
|
||||
self.highestMemoryReport = memoryReport
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ProFi:setLowestMemoryReport( memoryReport )
|
||||
if not self.lowestMemoryReport then
|
||||
self.lowestMemoryReport = memoryReport
|
||||
else
|
||||
if memoryReport.memory < self.lowestMemoryReport.memory then
|
||||
self.lowestMemoryReport = memoryReport
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------
|
||||
-- Local Functions:
|
||||
-----------------------
|
||||
|
||||
getTime = os.clock
|
||||
|
||||
onDebugHook = function( hookType )
|
||||
local funcInfo = debug.getinfo( 2, 'nS' )
|
||||
if hookType == "call" then
|
||||
ProFi:onFunctionCall( funcInfo )
|
||||
elseif hookType == "return" then
|
||||
ProFi:onFunctionReturn( funcInfo )
|
||||
end
|
||||
end
|
||||
|
||||
sortByDurationDesc = function( a, b )
|
||||
return a.timer > b.timer
|
||||
end
|
||||
|
||||
sortByCallCount = function( a, b )
|
||||
return a.count > b.count
|
||||
end
|
||||
|
||||
-----------------------
|
||||
-- Return Module:
|
||||
-----------------------
|
||||
|
||||
ProFi:reset()
|
||||
return ProFi
|
24
lib/body.lua
24
lib/body.lua
@ -497,13 +497,8 @@ function body:setShadowType(type, ...)
|
||||
end
|
||||
|
||||
function body:isInLightRange(light)
|
||||
if self.type == 'circle' then
|
||||
return light.range > math.sqrt(math.pow(light.x - self.x, 2) + math.pow(light.y - self.y, 2))
|
||||
else
|
||||
local cx, cy = self.x + (self.width * 0.5), self.y + (self.height * 0.5)
|
||||
local distance = math.sqrt(math.pow(light.x - cx, 2) + math.pow(light.y - cy, 2))
|
||||
return distance <= light.range + (self.width > self.height and self.width or self.height)
|
||||
end
|
||||
local l, t, w = light.x - light.range, light.y - light.range, light.range*2
|
||||
return self:isInRange(l,t,w,w,1)
|
||||
end
|
||||
|
||||
function body:isInRange(l, t, w, h, s)
|
||||
@ -516,7 +511,7 @@ function body:isInRange(l, t, w, h, s)
|
||||
|
||||
local bx, by, bw, bh = self.x - radius, self.y - radius, radius * 2, radius * 2
|
||||
|
||||
return self.visible and (bx+bw) > (-l/s) and bx < (-l+w)/s and (by+bh) > (-t/s) and by < (-t+h)/s
|
||||
return self.visible and (bx+bw) > (l/s) and bx < (l+w)/s and (by+bh) > (t/s) and by < (t+h)/s
|
||||
end
|
||||
|
||||
function body:drawAnimation()
|
||||
@ -535,11 +530,7 @@ function body:drawNormal()
|
||||
end
|
||||
|
||||
function body:drawGlow()
|
||||
if self.glowStrength > 0.0 then
|
||||
love.graphics.setColor(self.glowRed * self.glowStrength, self.glowGreen * self.glowStrength, self.glowBlue * self.glowStrength)
|
||||
else
|
||||
love.graphics.setColor(0, 0, 0)
|
||||
end
|
||||
love.graphics.setColor(self.glowRed * self.glowStrength, self.glowGreen * self.glowStrength, self.glowBlue * self.glowStrength)
|
||||
|
||||
if self.type == "circle" then
|
||||
love.graphics.circle("fill", self.x, self.y, self.radius)
|
||||
@ -548,7 +539,7 @@ function body:drawGlow()
|
||||
elseif self.type == "polygon" then
|
||||
love.graphics.polygon("fill", unpack(self.data))
|
||||
elseif (self.type == "image" or self.type == "animation") and self.img then
|
||||
if self.glowStrength > 0.0 and self.glow then
|
||||
if self.glow then
|
||||
love.graphics.setShader(self.glowShader)
|
||||
self.glowShader:send("glowImage", self.glow)
|
||||
self.glowShader:send("glowTime", love.timer.getTime() * 0.5)
|
||||
@ -556,14 +547,15 @@ function body:drawGlow()
|
||||
else
|
||||
love.graphics.setColor(0, 0, 0)
|
||||
end
|
||||
|
||||
if self.type == "animation" then
|
||||
self.animation:draw(self.img, self.x - self.ix, self.y - self.iy)
|
||||
else
|
||||
love.graphics.draw(self.img, self.x - self.ix, self.y - self.iy)
|
||||
end
|
||||
end
|
||||
|
||||
love.graphics.setShader()
|
||||
love.graphics.setShader()
|
||||
end
|
||||
end
|
||||
|
||||
function body:drawRefraction()
|
||||
|
46
lib/init.lua
46
lib/init.lua
@ -51,6 +51,11 @@ function light_world:init(options)
|
||||
self.glowTimer = 0.0
|
||||
self.glowDown = false
|
||||
|
||||
self.disableGlow = false
|
||||
self.disableMaterial = false
|
||||
self.disableReflection = true
|
||||
self.disableRefraction = true
|
||||
|
||||
options = options or {}
|
||||
for k, v in pairs(options) do self[k] = v end
|
||||
|
||||
@ -87,7 +92,7 @@ end
|
||||
|
||||
function light_world:update(dt)
|
||||
for i = 1, #self.body do
|
||||
if self.body[i]:isInRange(self.l,self.t,self.w,self.h,self.s) and
|
||||
if self.body[i]:isInRange(-self.l,-self.t,self.w,self.h,self.s) and
|
||||
self.body[i].type == 'animation' then
|
||||
self.body[i]:update(dt)
|
||||
end
|
||||
@ -97,11 +102,11 @@ end
|
||||
function light_world:draw(cb)
|
||||
util.drawto(self.render_buffer, self.l, self.t, self.s, function()
|
||||
cb( self.l,self.t,self.w,self.h,self.s)
|
||||
self:drawMaterial( self.l,self.t,self.w,self.h,self.s)
|
||||
_ = self.disableMaterial or self:drawMaterial( self.l,self.t,self.w,self.h,self.s)
|
||||
self:drawNormalShading( self.l,self.t,self.w,self.h,self.s)
|
||||
self:drawGlow( self.l,self.t,self.w,self.h,self.s)
|
||||
self:drawRefraction( self.l,self.t,self.w,self.h,self.s)
|
||||
self:drawReflection( self.l,self.t,self.w,self.h,self.s)
|
||||
_ = self.disableGlow or self:drawGlow( self.l,self.t,self.w,self.h,self.s)
|
||||
_ = self.disableRefraction or self:drawRefraction( self.l,self.t,self.w,self.h,self.s)
|
||||
_ = self.disableReflection or self:drawReflection( self.l,self.t,self.w,self.h,self.s)
|
||||
end)
|
||||
self.post_shader:drawWith(self.render_buffer, self.l, self.t, self.s)
|
||||
end
|
||||
@ -123,7 +128,7 @@ function light_world:drawNormalShading(l,t,w,h,s)
|
||||
self.normalMap:clear()
|
||||
util.drawto(self.normalMap, l, t, s, function()
|
||||
for i = 1, #self.body do
|
||||
if self.body[i]:isInRange(l,t,w,h,s) then
|
||||
if self.body[i]:isInRange(-l,-t,w,h,s) then
|
||||
self.body[i]:drawNormal()
|
||||
end
|
||||
end
|
||||
@ -136,7 +141,7 @@ function light_world:drawNormalShading(l,t,w,h,s)
|
||||
self.shadowMap:clear()
|
||||
util.drawto(self.shadowMap, l, t, s, function()
|
||||
for k = 1, #self.body do
|
||||
if self.body[k]:isInLightRange(self.lights[i]) and self.body[k]:isInRange(l,t,w,h,s) then
|
||||
if self.body[k]:isInLightRange(self.lights[i]) and self.body[k]:isInRange(-l,-t,w,h,s) then
|
||||
self.body[k]:drawShadow(self.lights[i])
|
||||
end
|
||||
end
|
||||
@ -162,7 +167,7 @@ end
|
||||
-- draw material
|
||||
function light_world:drawMaterial(l,t,w,h,s)
|
||||
for i = 1, #self.body do
|
||||
if self.body[i]:isInRange(l,t,w,h,s) then
|
||||
if self.body[i]:isInRange(-l,-t,w,h,s) then
|
||||
self.body[i]:drawMaterial()
|
||||
end
|
||||
end
|
||||
@ -180,18 +185,22 @@ function light_world:drawGlow(l,t,w,h,s)
|
||||
self.glowDown = not self.glowDown
|
||||
end
|
||||
|
||||
local has_glow = false
|
||||
-- create glow map
|
||||
self.glowMap:clear(0, 0, 0)
|
||||
util.drawto(self.glowMap, l, t, s, function()
|
||||
for i = 1, #self.body do
|
||||
if self.body[i]:isInRange(l,t,w,h,s) then
|
||||
if self.body[i]:isInRange(-l,-t,w,h,s) and self.body[i].glowStrength > 0.0 then
|
||||
has_glow = true
|
||||
self.body[i]:drawGlow()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
light_world:drawBlur("alpha", self.glowBlur, self.glowMap, self.glowMap2, l, t, w, h, s)
|
||||
util.drawCanvasToCanvas(self.glowMap, self.render_buffer, {blendmode = "additive"})
|
||||
if has_glow then
|
||||
light_world:drawBlur("alpha", self.glowBlur, self.glowMap, self.glowMap2, l, t, w, h, s)
|
||||
util.drawCanvasToCanvas(self.glowMap, self.render_buffer, {blendmode = "additive"})
|
||||
end
|
||||
end
|
||||
-- draw refraction
|
||||
function light_world:drawRefraction(l,t,w,h,s)
|
||||
@ -199,7 +208,7 @@ function light_world:drawRefraction(l,t,w,h,s)
|
||||
self.refractionMap:clear()
|
||||
util.drawto(self.refractionMap, l, t, s, function()
|
||||
for i = 1, #self.body do
|
||||
if self.body[i]:isInRange(l,t,w,h,s) then
|
||||
if self.body[i]:isInRange(-l,-t,w,h,s) then
|
||||
self.body[i]:drawRefraction()
|
||||
end
|
||||
end
|
||||
@ -217,7 +226,7 @@ function light_world:drawReflection(l,t,w,h,s)
|
||||
self.reflectionMap:clear(0, 0, 0)
|
||||
util.drawto(self.reflectionMap, l, t, s, function()
|
||||
for i = 1, #self.body do
|
||||
if self.body[i]:isInRange(l,t,w,h,s) then
|
||||
if self.body[i]:isInRange(-l,-t,w,h,s) then
|
||||
self.body[i]:drawReflection()
|
||||
end
|
||||
end
|
||||
@ -263,8 +272,15 @@ function light_world:newAnimationGrid(...) return self:newBody("animation", ...)
|
||||
function light_world:newCircle(...) return self:newBody("circle", ...) end
|
||||
function light_world:newPolygon(...) return self:newBody("polygon", ...) end
|
||||
function light_world:newImage(...) return self:newBody("image", ...) end
|
||||
function light_world:newRefraction(...) return self:newBody("refraction", ...) end
|
||||
function light_world:newReflection(normal, ...) return self:newBody("reflection", ...) end
|
||||
|
||||
function light_world:newRefraction(...)
|
||||
self.disableRefraction = false
|
||||
return self:newBody("refraction", ...)
|
||||
end
|
||||
function light_world:newReflection(normal, ...)
|
||||
self.disableReflection = false
|
||||
return self:newBody("reflection", ...)
|
||||
end
|
||||
|
||||
-- new body
|
||||
function light_world:newBody(type, ...)
|
||||
|
@ -9,7 +9,6 @@ light.shadowShader = love.graphics.newShader(_PACKAGE.."/shaders/shadow.glsl")
|
||||
function light:init(x, y, r, g, b, range)
|
||||
self.direction = 0
|
||||
self.angle = math.pi * 2.0
|
||||
self.range = 0
|
||||
self.x = x or 0
|
||||
self.y = y or 0
|
||||
self.z = 1
|
||||
|
@ -28,27 +28,30 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
|
||||
vec4 pixelColor = Texel(texture, texture_coords);
|
||||
vec4 shadowColor = Texel(shadowMap, texture_coords);
|
||||
|
||||
//if the light is a slice and the pixel is not inside
|
||||
if(lightAngle > 0.0 && not_in_slice(pixel_coords)) {
|
||||
return vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec3 normal;
|
||||
if(pixelColor.a > 0.0) {
|
||||
//if on the normal map ie there is normal map data
|
||||
//so get the normal data
|
||||
if(invert_normal) {
|
||||
normal = normalize(vec3(pixelColor.r, 1 - pixelColor.g, pixelColor.b) * 2.0 - 1.0);
|
||||
} else {
|
||||
normal = normalize(pixelColor.rgb * 2.0 - 1.0);
|
||||
}
|
||||
} else {
|
||||
// not on the normal map so it is the floor with a normal point strait up
|
||||
normal = vec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
float dist = distance(lightPosition, vec3(pixel_coords, normal.b));
|
||||
float dist = distance(lightPosition, vec3(pixel_coords, 1.0));
|
||||
//if the pixel is within this lights range
|
||||
if(dist < lightRange) {
|
||||
if(dist > lightRange) {
|
||||
//not in range draw in shadows
|
||||
return vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}else{
|
||||
//if the light is a slice and the pixel is not inside
|
||||
if(lightAngle > 0.0 && not_in_slice(pixel_coords)) {
|
||||
return vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec3 normal;
|
||||
if(pixelColor.a > 0.0) {
|
||||
//if on the normal map ie there is normal map data
|
||||
//so get the normal data
|
||||
if(invert_normal) {
|
||||
normal = normalize(vec3(pixelColor.r, 1 - pixelColor.g, pixelColor.b) * 2.0 - 1.0);
|
||||
} else {
|
||||
normal = normalize(pixelColor.rgb * 2.0 - 1.0);
|
||||
}
|
||||
} else {
|
||||
// not on the normal map so it is the floor with a normal point strait up
|
||||
normal = vec3(0.0, 0.0, 1.0);
|
||||
}
|
||||
//calculater attenuation of light based on the distance
|
||||
float att = clamp((1.0 - dist / lightRange) / lightSmooth, 0.0, 1.0);
|
||||
// if not on the normal map draw attenuated shadows
|
||||
@ -73,9 +76,6 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
|
||||
//return the light that is effected by the normal and attenuation
|
||||
return vec4(diff * att, 1.0);
|
||||
}
|
||||
} else {
|
||||
//not in range draw in shadows
|
||||
return vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
4
main.lua
4
main.lua
@ -8,6 +8,7 @@
|
||||
|
||||
require "lib/postshader"
|
||||
local LightWorld = require "lib"
|
||||
local ProFi = require 'examples.vendor.ProFi'
|
||||
|
||||
exf = {}
|
||||
exf.current = nil
|
||||
@ -166,6 +167,9 @@ function exf.clear()
|
||||
end
|
||||
|
||||
function exf.resume()
|
||||
ProFi:stop()
|
||||
ProFi:writeReport( 'light_world_profiling_report.txt' )
|
||||
|
||||
load = nil
|
||||
love.update = exf.update
|
||||
love.draw = exf.draw
|
||||
|
Loading…
Reference in New Issue
Block a user