├── .gitignore ├── Background.png ├── luven ├── lights │ ├── cone.png │ ├── round.png │ └── rectangle.png └── luven.lua ├── conf.lua ├── LICENSE ├── README.md ├── main.lua ├── dev ├── inspect.lua └── profi.lua ├── ProfilingReport.txt └── LuvenProfile.txt /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | LuvenProfile.txt 4 | -------------------------------------------------------------------------------- /Background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halsten-dev/Luven/HEAD/Background.png -------------------------------------------------------------------------------- /luven/lights/cone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halsten-dev/Luven/HEAD/luven/lights/cone.png -------------------------------------------------------------------------------- /luven/lights/round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halsten-dev/Luven/HEAD/luven/lights/round.png -------------------------------------------------------------------------------- /luven/lights/rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halsten-dev/Luven/HEAD/luven/lights/rectangle.png -------------------------------------------------------------------------------- /conf.lua: -------------------------------------------------------------------------------- 1 | function love.conf(t) 2 | t.window.title = "Luven - Exemple" 3 | t.window.width = 1280 4 | t.window.height = 720 5 | t.window.display = 3 6 | t.window.highdpi = false 7 | t.window.vsync = 1 8 | t.window.msaa = 0 9 | t.gammacorrect = false 10 | 11 | t.console = true 12 | end 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Lionel Leeser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Luven 2 | Minimalist lighting system for [Löve2D](https://love2d.org/) 3 | 4 | # Luven's Public Link 5 | Löve2D Forums : https://love2d.org/forums/viewtopic.php?f=5&t=86402 6 | 7 | # Luven's Wiki 8 | https://github.com/halsten-dev/Luven/wiki 9 | 10 | # Luven's License 11 | MIT License 12 | 13 | Copyright (c) 2019 Lionel Leeser 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | -- main.lua 2 | -- Example for using luven.lua 3 | 4 | Luven = require "luven/luven" 5 | Inspect = require "dev/inspect" 6 | Profi = require "dev/profi" 7 | 8 | local zoom = 2 9 | local image = nil 10 | local moveSpeed = 150 11 | 12 | local lightId = 0 13 | local lightId2 = 0 14 | 15 | local power = 0.25 16 | 17 | function love.load() 18 | love.graphics.setDefaultFilter("nearest", "nearest") 19 | -- Profi:start() 20 | image = love.graphics.newImage("Background.png") 21 | 22 | Luven.init() 23 | Luven.setAmbientLightColor({ 0.1, 0.1, 0.1 }) 24 | Luven.camera:init(love.graphics.getWidth() / 2, love.graphics.getHeight() / 2) 25 | Luven.camera:setScale(zoom) 26 | 27 | lightId = Luven.addFlickeringLight(600, 400, { min = { 0.8, 0.0, 0.8, 0.8 }, max = { 1.0, 0.0, 1.0, 1.0 } }, { min = 0.25, max = 0.27 }, { min = 0.12, max = 0.2 }) 28 | lightId2 = Luven.addFlickeringLight(700, 400, { min = { 0.8, 0.0, 0.8, 0.8 }, max = { 1.0, 0.0, 1.0, 1.0 } }, { min = 0.25, max = 0.7 }, { min = 0.12, max = 0.2 }, Luven.lightShapes.cone) 29 | Luven.addNormalLight(700, 500, { 0.9, 1, 0 }, 1, Luven.lightShapes.cone, 0) 30 | end -- function 31 | 32 | function love.update(dt) 33 | Luven.update(dt) 34 | 35 | local vx, vy = 0, 0 36 | 37 | if (love.keyboard.isDown("w")) then 38 | vy = vy - moveSpeed * dt 39 | end -- if 40 | 41 | if (love.keyboard.isDown("s")) then 42 | vy = vy + moveSpeed * dt 43 | end -- if 44 | 45 | if (love.keyboard.isDown("a")) then 46 | vx = vx - moveSpeed * dt 47 | end -- if 48 | 49 | if (love.keyboard.isDown("d")) then 50 | vx = vx + moveSpeed * dt 51 | end -- if 52 | 53 | Luven.camera:move(vx, vy) 54 | 55 | Luven.setLightRotation(lightId2, Luven.getLightRotation(lightId2) + 1 * dt) 56 | end -- function 57 | 58 | function love.keypressed(key) 59 | if (key == "space") then 60 | Luven.camera:setShake(0.7, 5.5) 61 | end -- if 62 | 63 | if (key == "m") then 64 | power = power + 0.05 65 | Luven.setLightPower(lightId, power) 66 | end -- if 67 | 68 | if (key == "n") then 69 | power = power - 0.05 70 | Luven.setLightPower(lightId, power) 71 | end -- if 72 | 73 | if (key == "l") then 74 | lightId = Luven.addNormalLight(Luven.camera.x, Luven.camera.y, { 1.0, 1.0 , 1.0 }, 0.05) 75 | end -- if 76 | 77 | if (key == "z") then 78 | Luven.addFlashingLight(Luven.camera.x, Luven.camera.y, { 1.0, 0.0, 0.0 }, 1, 3) 79 | end 80 | 81 | if (key == "f") then 82 | --Luven.addFlashingLight(Luven.camera.x, Luven.camera.y, { 1.0, 0.0, 0.0 }, 1, 3) 83 | Luven.camera:setFade(3, { 1, 0, 0, 1 }, function() Luven.camera:setFade(3, { 0, 0, 0, 0 }) end) 84 | end -- if 85 | 86 | if (key == "g") then 87 | --Luven.addFlashingLight(Luven.camera.x, Luven.camera.y, { 1.0, 0.0, 0.0 }, 1, 3) 88 | Luven.camera:setFade(3, { 0, 0, 0, 0 }) 89 | end -- if 90 | end -- function 91 | 92 | function love.draw() 93 | Luven.drawBegin() 94 | 95 | love.graphics.draw(image, 0, 0, 0, 0.5, 0.5) 96 | 97 | Luven.drawEnd() 98 | 99 | love.graphics.print("Current FPS: " .. tostring(love.timer.getFPS()), 10, 10) 100 | love.graphics.print("Number of lights: " .. tostring(Luven.getLightCount()), 10, 30) 101 | 102 | Luven.camera:draw() 103 | end -- function 104 | 105 | function love.quit() 106 | Luven.dispose() 107 | -- Profi:stop() 108 | -- Profi:writeReport("LuvenProfile.txt") 109 | end -- function 110 | -------------------------------------------------------------------------------- /dev/inspect.lua: -------------------------------------------------------------------------------- 1 | local inspect ={ 2 | _VERSION = 'inspect.lua 3.1.0', 3 | _URL = 'http://github.com/kikito/inspect.lua', 4 | _DESCRIPTION = 'human-readable representations of tables', 5 | _LICENSE = [[ 6 | MIT LICENSE 7 | 8 | Copyright (c) 2013 Enrique García Cota 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a 11 | copy of this software and associated documentation files (the 12 | "Software"), to deal in the Software without restriction, including 13 | without limitation the rights to use, copy, modify, merge, publish, 14 | distribute, sublicense, and/or sell copies of the Software, and to 15 | permit persons to whom the Software is furnished to do so, subject to 16 | the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included 19 | in all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | ]] 29 | } 30 | 31 | local tostring = tostring 32 | 33 | inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) 34 | inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) 35 | 36 | local function rawpairs(t) 37 | return next, t, nil 38 | end 39 | 40 | -- Apostrophizes the string if it has quotes, but not aphostrophes 41 | -- Otherwise, it returns a regular quoted string 42 | local function smartQuote(str) 43 | if str:match('"') and not str:match("'") then 44 | return "'" .. str .. "'" 45 | end 46 | return '"' .. str:gsub('"', '\\"') .. '"' 47 | end 48 | 49 | -- \a => '\\a', \0 => '\\0', 31 => '\31' 50 | local shortControlCharEscapes = { 51 | ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", 52 | ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" 53 | } 54 | local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031 55 | for i=0, 31 do 56 | local ch = string.char(i) 57 | if not shortControlCharEscapes[ch] then 58 | shortControlCharEscapes[ch] = "\\"..i 59 | longControlCharEscapes[ch] = string.format("\\%03d", i) 60 | end 61 | end 62 | 63 | local function escape(str) 64 | return (str:gsub("\\", "\\\\") 65 | :gsub("(%c)%f[0-9]", longControlCharEscapes) 66 | :gsub("%c", shortControlCharEscapes)) 67 | end 68 | 69 | local function isIdentifier(str) 70 | return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) 71 | end 72 | 73 | local function isSequenceKey(k, sequenceLength) 74 | return type(k) == 'number' 75 | and 1 <= k 76 | and k <= sequenceLength 77 | and math.floor(k) == k 78 | end 79 | 80 | local defaultTypeOrders = { 81 | ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, 82 | ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 83 | } 84 | 85 | local function sortKeys(a, b) 86 | local ta, tb = type(a), type(b) 87 | 88 | -- strings and numbers are sorted numerically/alphabetically 89 | if ta == tb and (ta == 'string' or ta == 'number') then return a < b end 90 | 91 | local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] 92 | -- Two default types are compared according to the defaultTypeOrders table 93 | if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] 94 | elseif dta then return true -- default types before custom ones 95 | elseif dtb then return false -- custom types after default ones 96 | end 97 | 98 | -- custom types are sorted out alphabetically 99 | return ta < tb 100 | end 101 | 102 | -- For implementation reasons, the behavior of rawlen & # is "undefined" when 103 | -- tables aren't pure sequences. So we implement our own # operator. 104 | local function getSequenceLength(t) 105 | local len = 1 106 | local v = rawget(t,len) 107 | while v ~= nil do 108 | len = len + 1 109 | v = rawget(t,len) 110 | end 111 | return len - 1 112 | end 113 | 114 | local function getNonSequentialKeys(t) 115 | local keys, keysLength = {}, 0 116 | local sequenceLength = getSequenceLength(t) 117 | for k,_ in rawpairs(t) do 118 | if not isSequenceKey(k, sequenceLength) then 119 | keysLength = keysLength + 1 120 | keys[keysLength] = k 121 | end 122 | end 123 | table.sort(keys, sortKeys) 124 | return keys, keysLength, sequenceLength 125 | end 126 | 127 | local function countTableAppearances(t, tableAppearances) 128 | tableAppearances = tableAppearances or {} 129 | 130 | if type(t) == 'table' then 131 | if not tableAppearances[t] then 132 | tableAppearances[t] = 1 133 | for k,v in rawpairs(t) do 134 | countTableAppearances(k, tableAppearances) 135 | countTableAppearances(v, tableAppearances) 136 | end 137 | countTableAppearances(getmetatable(t), tableAppearances) 138 | else 139 | tableAppearances[t] = tableAppearances[t] + 1 140 | end 141 | end 142 | 143 | return tableAppearances 144 | end 145 | 146 | local copySequence = function(s) 147 | local copy, len = {}, #s 148 | for i=1, len do copy[i] = s[i] end 149 | return copy, len 150 | end 151 | 152 | local function makePath(path, ...) 153 | local keys = {...} 154 | local newPath, len = copySequence(path) 155 | for i=1, #keys do 156 | newPath[len + i] = keys[i] 157 | end 158 | return newPath 159 | end 160 | 161 | local function processRecursive(process, item, path, visited) 162 | if item == nil then return nil end 163 | if visited[item] then return visited[item] end 164 | 165 | local processed = process(item, path) 166 | if type(processed) == 'table' then 167 | local processedCopy = {} 168 | visited[item] = processedCopy 169 | local processedKey 170 | 171 | for k,v in rawpairs(processed) do 172 | processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) 173 | if processedKey ~= nil then 174 | processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) 175 | end 176 | end 177 | 178 | local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) 179 | if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field 180 | setmetatable(processedCopy, mt) 181 | processed = processedCopy 182 | end 183 | return processed 184 | end 185 | 186 | 187 | 188 | ------------------------------------------------------------------- 189 | 190 | local Inspector = {} 191 | local Inspector_mt = {__index = Inspector} 192 | 193 | function Inspector:puts(...) 194 | local args = {...} 195 | local buffer = self.buffer 196 | local len = #buffer 197 | for i=1, #args do 198 | len = len + 1 199 | buffer[len] = args[i] 200 | end 201 | end 202 | 203 | function Inspector:down(f) 204 | self.level = self.level + 1 205 | f() 206 | self.level = self.level - 1 207 | end 208 | 209 | function Inspector:tabify() 210 | self:puts(self.newline, string.rep(self.indent, self.level)) 211 | end 212 | 213 | function Inspector:alreadyVisited(v) 214 | return self.ids[v] ~= nil 215 | end 216 | 217 | function Inspector:getId(v) 218 | local id = self.ids[v] 219 | if not id then 220 | local tv = type(v) 221 | id = (self.maxIds[tv] or 0) + 1 222 | self.maxIds[tv] = id 223 | self.ids[v] = id 224 | end 225 | return tostring(id) 226 | end 227 | 228 | function Inspector:putKey(k) 229 | if isIdentifier(k) then return self:puts(k) end 230 | self:puts("[") 231 | self:putValue(k) 232 | self:puts("]") 233 | end 234 | 235 | function Inspector:putTable(t) 236 | if t == inspect.KEY or t == inspect.METATABLE then 237 | self:puts(tostring(t)) 238 | elseif self:alreadyVisited(t) then 239 | self:puts('') 240 | elseif self.level >= self.depth then 241 | self:puts('{...}') 242 | else 243 | if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end 244 | 245 | local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t) 246 | local mt = getmetatable(t) 247 | 248 | self:puts('{') 249 | self:down(function() 250 | local count = 0 251 | for i=1, sequenceLength do 252 | if count > 0 then self:puts(',') end 253 | self:puts(' ') 254 | self:putValue(t[i]) 255 | count = count + 1 256 | end 257 | 258 | for i=1, nonSequentialKeysLength do 259 | local k = nonSequentialKeys[i] 260 | if count > 0 then self:puts(',') end 261 | self:tabify() 262 | self:putKey(k) 263 | self:puts(' = ') 264 | self:putValue(t[k]) 265 | count = count + 1 266 | end 267 | 268 | if type(mt) == 'table' then 269 | if count > 0 then self:puts(',') end 270 | self:tabify() 271 | self:puts(' = ') 272 | self:putValue(mt) 273 | end 274 | end) 275 | 276 | if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing } 277 | self:tabify() 278 | elseif sequenceLength > 0 then -- array tables have one extra space before closing } 279 | self:puts(' ') 280 | end 281 | 282 | self:puts('}') 283 | end 284 | end 285 | 286 | function Inspector:putValue(v) 287 | local tv = type(v) 288 | 289 | if tv == 'string' then 290 | self:puts(smartQuote(escape(v))) 291 | elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or 292 | tv == 'cdata' or tv == 'ctype' then 293 | self:puts(tostring(v)) 294 | elseif tv == 'table' then 295 | self:putTable(v) 296 | else 297 | self:puts('<', tv, ' ', self:getId(v), '>') 298 | end 299 | end 300 | 301 | ------------------------------------------------------------------- 302 | 303 | function inspect.inspect(root, options) 304 | options = options or {} 305 | 306 | local depth = options.depth or math.huge 307 | local newline = options.newline or '\n' 308 | local indent = options.indent or ' ' 309 | local process = options.process 310 | 311 | if process then 312 | root = processRecursive(process, root, {}, {}) 313 | end 314 | 315 | local inspector = setmetatable({ 316 | depth = depth, 317 | level = 0, 318 | buffer = {}, 319 | ids = {}, 320 | maxIds = {}, 321 | newline = newline, 322 | indent = indent, 323 | tableAppearances = countTableAppearances(root) 324 | }, Inspector_mt) 325 | 326 | inspector:putValue(root) 327 | 328 | return table.concat(inspector.buffer) 329 | end 330 | 331 | setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) 332 | 333 | return inspect 334 | 335 | -------------------------------------------------------------------------------- /ProfilingReport.txt: -------------------------------------------------------------------------------- 1 | ############################################################################################################### 2 | ##### ProFi, a lua profiler. This profile was generated on: Sam 23 fév 19:28:45 2019 3 | ##### ProFi is created by Luke Perkin 2012 under the MIT Licence, www.locofilm.co.uk 4 | ##### Version 1.3. Get the most recent version at this gist: https://gist.github.com/2838755 5 | ############################################################################################################### 6 | 7 | | TOTAL TIME = 3,555272 8 | | FILE : FUNCTION : LINE : TIME : RELATIVE : CALLED | 9 | | [string "boot.lua"] : anonymous : 493 : 3,287 : 92,46% : 1107 | 10 | | main.lua : draw : 65 : 0,377 : 10,60% : 1106 | 11 | | luven.lua : drawBegin : 326 : 0,165 : 4,64% : 1106 | 12 | | main.lua : update : 27 : 0,120 : 3,37% : 1106 | 13 | | luven.lua : drawEnd : 336 : 0,117 : 3,29% : 1106 | 14 | | luven.lua : set : 108 : 0,071 : 1,99% : 1106 | 15 | | luven.lua : update : 299 : 0,038 : 1,07% : 1106 | 16 | | luven.lua : unset : 114 : 0,021 : 0,59% : 1106 | 17 | | luven.lua : init : 263 : 0,019 : 0,54% : 1 | 18 | | [string "wrap_Event.lua"] : poll : 25 : 0,011 : 0,31% : 1107 | 19 | | luven.lua : move : 123 : 0,010 : 0,27% : 1106 | 20 | | luven.lua : cameraDraw : 83 : 0,009 : 0,26% : 1106 | 21 | | luven.lua : cameraUpdate : 77 : 0,009 : 0,26% : 1106 | 22 | | luven.lua : generateFlicker : 244 : 0,008 : 0,22% : 21 | 23 | | luven.lua : randomFloat : 236 : 0,007 : 0,19% : 105 | 24 | | [string "wrap_RandomGenerator.lua"] : random : 33 : 0,001 : 0,02% : 105 | 25 | | luven.lua : addFlickeringLight : 396 : 0,001 : 0,02% : 1 | 26 | | luven.lua : addNormalLight : 364 : 0,000 : 0,00% : 1 | 27 | | [string "wrap_Graphics.lua"] : anonymous : 339 : 0,000 : 0,00% : 1 | 28 | | [string "boot.lua"] : anonymous : 158 : 0,000 : 0,00% : 15 | 29 | | luven.lua : assertRangeNumber : 42 : 0,000 : 0,00% : 9 | 30 | | luven.lua : dispose : 344 : 0,000 : 0,00% : 1 | 31 | | luven.lua : assertPositiveNumber : 35 : 0,000 : 0,00% : 7 | 32 | | luven.lua : assertType : 51 : 0,000 : 0,00% : 7 | 33 | | luven.lua : init : 99 : 0,000 : 0,00% : 1 | 34 | | luven.lua : registerLight : 207 : 0,000 : 0,00% : 2 | 35 | | [string "boot.lua"] : anonymous : 152 : 0,000 : 0,00% : 6 | 36 | | luven.lua : removeLight : 468 : 0,000 : 0,00% : 2 | 37 | | luven.lua : clearTable : 240 : 0,000 : 0,00% : 3 | 38 | | [string "boot.lua"] : anonymous : 206 : 0,000 : 0,00% : 1 | 39 | | main.lua : anonymous : 51 : 0,000 : 0,00% : 5 | 40 | | [string "boot.lua"] : anonymous : 149 : 0,000 : 0,00% : 3 | 41 | | [string "wrap_Graphics.lua"] : getLanguageTarget : 300 : 0,000 : 0,00% : 2 | 42 | | [string "wrap_Graphics.lua"] : isVertexCode : 324 : 0,000 : 0,00% : 1 | 43 | | luven.lua : getNextId : 221 : 0,000 : 0,00% : 2 | 44 | | [string "wrap_Graphics.lua"] : isPixelCode : 328 : 0,000 : 0,00% : 1 | 45 | | [string "boot.lua"] : anonymous : 212 : 0,000 : 0,00% : 1 | 46 | | luven.lua : setAmbientLightColor : 291 : 0,000 : 0,00% : 1 | 47 | | dev/profi.lua : shouldReturn : 199 : 0,000 : 0,00% : 1 | 48 | | [string "boot.lua"] : anonymous : 209 : 0,000 : 0,00% : 1 | 49 | | luven.lua : setScale : 132 : 0,000 : 0,00% : 1 | 50 | | [C] : push : -1 : 0,000 : 0,00% : 1106 | 51 | | [C] : setTransformation : -1 : 0,000 : 0,00% : 1106 | 52 | | [C] : applyTransform : -1 : 0,000 : 0,00% : 1106 | 53 | | dev/profi.lua : startHooks : 234 : 0,000 : 0,00% : 0 | 54 | | [C] : cameraGetViewMatrix : -1 : 0,000 : 0,00% : 1106 | 55 | | [C] : sleep : -1 : 0,000 : 0,00% : 1106 | 56 | | [C] : present : -1 : 0,000 : 0,00% : 1106 | 57 | | [string "boot.lua"] : anonymous : 146 : 0,000 : 0,00% : 5 | 58 | | dev/profi.lua : stop : 85 : 0,000 : 0,00% : 1 | 59 | | main.lua : quit : 76 : 0,000 : 0,00% : 1 | 60 | | luven.lua : cameraGetViewMatrix : 91 : 0,000 : 0,00% : 1106 | 61 | | [C] : print : -1 : 0,000 : 0,00% : 1106 | 62 | | [C] : tostring : -1 : 0,000 : 0,00% : 1106 | 63 | | [C] : setShader : -1 : 0,000 : 0,00% : 2212 | 64 | | [C] : clear : -1 : 0,000 : 0,00% : 1106 | 65 | | [C] : draw : -1 : 0,000 : 0,00% : 1106 | 66 | | [C] : getFPS : -1 : 0,000 : 0,00% : 1106 | 67 | | [C] : pop : -1 : 0,000 : 0,00% : 1106 | 68 | | [C] : getBackgroundColor : -1 : 0,000 : 0,00% : 1106 | 69 | | [C] : xpcall : -1 : 0,000 : 0,00% : 1107 | 70 | | [C] : isActive : -1 : 0,000 : 0,00% : 1106 | 71 | | [string "wrap_Graphics.lua"] : createShaderStageCode : 305 : 0,000 : 0,00% : 1 | 72 | | [C] : isGammaCorrect : -1 : 0,000 : 0,00% : 1 | 73 | | [C] : getSupported : -1 : 0,000 : 0,00% : 1 | 74 | | [C] : upper : -1 : 0,000 : 0,00% : 1 | 75 | | [C] : send : -1 : 0,000 : 0,00% : 1161 | 76 | | [C] : createShaderStageCode : -1 : 0,000 : 0,00% : 1 | 77 | | [C] : getHeight : -1 : 0,000 : 0,00% : 1107 | 78 | | [C] : match : -1 : 0,000 : 0,00% : 4 | 79 | | [C] : type : -1 : 0,000 : 0,00% : 23 | 80 | | [C] : getTime : -1 : 0,000 : 0,00% : 2 | 81 | | [C] : newShader : -1 : 0,000 : 0,00% : 1 | 82 | | dev/profi.lua : start : 67 : 0,000 : 0,00% : 0 | 83 | | [C] : getWidth : -1 : 0,000 : 0,00% : 1109 | 84 | | [C] : newImage : -1 : 0,000 : 0,00% : 1 | 85 | | [C] : origin : -1 : 0,000 : 0,00% : 1106 | 86 | | [C] : newTransform : -1 : 0,000 : 0,00% : 1 | 87 | | [string "wrap_Math.lua"] : random : 37 : 0,000 : 0,00% : 105 | 88 | | dev/profi.lua : stopHooks : 238 : 0,000 : 0,00% : 1 | 89 | | [C] : yield : -1 : 0,000 : 0,00% : 1107 | 90 | | [string "boot.lua"] : anonymous : 639 : 0,000 : 0,00% : 0 | 91 | | [C] : pump : -1 : 0,000 : 0,00% : 1107 | 92 | | [C] : isDown : -1 : 0,000 : 0,00% : 4424 | 93 | | [C] : (for generator) : -1 : 0,000 : 0,00% : 1139 | 94 | | [C] : pairs : -1 : 0,000 : 0,00% : 4 | 95 | | [string "boot.lua"] : anonymous : 487 : 0,000 : 0,00% : 0 | 96 | | main.lua : load : 14 : 0,000 : 0,00% : 0 | 97 | | [string "wrap_RandomGenerator.lua"] : random : 75 : 0,000 : 0,00% : 105 | 98 | | [C] : step : -1 : 0,000 : 0,00% : 1107 | 99 | | [C] : __index : -1 : 0,000 : 0,00% : 105 | 100 | | [C] : tonumber : -1 : 0,000 : 0,00% : 105 | 101 | | [C] : random : -1 : 0,000 : 0,00% : 105 | 102 | | [C] : sethook : -1 : 0,000 : 0,00% : 1 | 103 | -------------------------------------------------------------------------------- /LuvenProfile.txt: -------------------------------------------------------------------------------- 1 | ############################################################################################################### 2 | ##### ProFi, a lua profiler. This profile was generated on: Lun 11 mar 05:57:01 2019 3 | ##### ProFi is created by Luke Perkin 2012 under the MIT Licence, www.locofilm.co.uk 4 | ##### Version 1.3. Get the most recent version at this gist: https://gist.github.com/2838755 5 | ############################################################################################################### 6 | 7 | | TOTAL TIME = 7,131932 8 | | FILE : FUNCTION : LINE : TIME : RELATIVE : CALLED | 9 | | [string "boot.lua"] : anonymous : 493 : 6,838 : 95,88% : 4448 | 10 | | main.lua : draw : 88 : 1,885 : 26,42% : 4447 | 11 | | luven/luven.lua : drawBegin : 392 : 0,929 : 13,02% : 4447 | 12 | | luven/luven.lua : drawLights : 256 : 0,678 : 9,51% : 4447 | 13 | | main.lua : update : 32 : 0,667 : 9,35% : 4447 | 14 | | luven/luven.lua : update : 364 : 0,317 : 4,45% : 4447 | 15 | | luven/luven.lua : drawEnd : 400 : 0,283 : 3,96% : 4447 | 16 | | luven/luven.lua : drawEffects : 168 : 0,236 : 3,31% : 4447 | 17 | | luven/luven.lua : set : 153 : 0,171 : 2,40% : 4447 | 18 | | luven/luven.lua : cameraUpdate : 109 : 0,128 : 1,79% : 4447 | 19 | | luven/luven.lua : getLastEnabledLightIndex : 248 : 0,057 : 0,80% : 4447 | 20 | | luven/luven.lua : unset : 164 : 0,053 : 0,74% : 4447 | 21 | | luven/luven.lua : lerp : 69 : 0,049 : 0,69% : 8400 | 22 | | luven/luven.lua : generateFlicker : 298 : 0,044 : 0,61% : 158 | 23 | | luven/luven.lua : randomFloat : 290 : 0,038 : 0,53% : 790 | 24 | | [string "wrap_Event.lua"] : poll : 25 : 0,032 : 0,45% : 4448 | 25 | | luven/luven.lua : getLightCount : 423 : 0,030 : 0,42% : 4447 | 26 | | luven/luven.lua : move : 183 : 0,027 : 0,38% : 4447 | 27 | | luven/luven.lua : getLightRotation : 621 : 0,027 : 0,37% : 4447 | 28 | | luven/luven.lua : setLightRotation : 597 : 0,026 : 0,37% : 4447 | 29 | | luven/luven.lua : init : 314 : 0,007 : 0,09% : 1 | 30 | | luven/luven.lua : registerLightShape : 345 : 0,006 : 0,08% : 3 | 31 | | [string "wrap_RandomGenerator.lua"] : random : 33 : 0,004 : 0,06% : 790 | 32 | | luven/luven.lua : addFlickeringLight : 483 : 0,001 : 0,01% : 2 | 33 | | luven/luven.lua : dispose : 410 : 0,000 : 0,00% : 1 | 34 | | luven/luven.lua : assertPositiveNumber : 35 : 0,000 : 0,00% : 23 | 35 | | luven/luven.lua : addNormalLight : 441 : 0,000 : 0,00% : 1 | 36 | | luven/luven.lua : assertType : 51 : 0,000 : 0,00% : 15 | 37 | | luven/luven.lua : assertRangeNumber : 42 : 0,000 : 0,00% : 15 | 38 | | luven/luven.lua : init : 144 : 0,000 : 0,00% : 1 | 39 | | luven/luven.lua : clearTable : 294 : 0,000 : 0,00% : 5 | 40 | | main.lua : anonymous : 58 : 0,000 : 0,00% : 3 | 41 | | luven/luven.lua : removeLight : 574 : 0,000 : 0,00% : 3 | 42 | | main.lua : fadeAction : 79 : 0,000 : 0,00% : 1 | 43 | | luven/luven.lua : assertLightShape : 58 : 0,000 : 0,00% : 3 | 44 | | dev/profi.lua : shouldReturn : 199 : 0,000 : 0,00% : 1 | 45 | | luven/luven.lua : getNextId : 279 : 0,000 : 0,00% : 3 | 46 | | luven/luven.lua : setFade : 204 : 0,000 : 0,00% : 2 | 47 | | [string "boot.lua"] : anonymous : 149 : 0,000 : 0,00% : 1 | 48 | | luven/luven.lua : setAmbientLightColor : 340 : 0,000 : 0,00% : 1 | 49 | | [string "boot.lua"] : anonymous : 212 : 0,000 : 0,00% : 1 | 50 | | [string "boot.lua"] : anonymous : 206 : 0,000 : 0,00% : 1 | 51 | | [string "boot.lua"] : anonymous : 152 : 0,000 : 0,00% : 1 | 52 | | luven/luven.lua : setScale : 192 : 0,000 : 0,00% : 1 | 53 | | [C] : setBlendMode : -1 : 0,000 : 0,00% : 17788 | 54 | | [C] : lgDraw : -1 : 0,000 : 0,00% : 17788 | 55 | | [C] : draw : -1 : 0,000 : 0,00% : 4447 | 56 | | [C] : getColor : -1 : 0,000 : 0,00% : 8894 | 57 | | [C] : lgSetColor : -1 : 0,000 : 0,00% : 17788 | 58 | | dev/profi.lua : startHooks : 234 : 0,000 : 0,00% : 0 | 59 | | [C] : present : -1 : 0,000 : 0,00% : 4447 | 60 | | [C] : getFPS : -1 : 0,000 : 0,00% : 4447 | 61 | | main.lua : quit : 101 : 0,000 : 0,00% : 1 | 62 | | [string "boot.lua"] : anonymous : 146 : 0,000 : 0,00% : 3 | 63 | | [C] : release : -1 : 0,000 : 0,00% : 1 | 64 | | dev/profi.lua : stop : 85 : 0,000 : 0,00% : 1 | 65 | | [C] : pop : -1 : 0,000 : 0,00% : 4447 | 66 | | [C] : sleep : -1 : 0,000 : 0,00% : 4447 | 67 | | [C] : setColor : -1 : 0,000 : 0,00% : 8894 | 68 | | [C] : rectangle : -1 : 0,000 : 0,00% : 4447 | 69 | | [C] : tostring : -1 : 0,000 : 0,00% : 8894 | 70 | | [C] : print : -1 : 0,000 : 0,00% : 8894 | 71 | | [C] : setCanvas : -1 : 0,000 : 0,00% : 8894 | 72 | | [C] : isDown : -1 : 0,000 : 0,00% : 17788 | 73 | | [C] : setTransformation : -1 : 0,000 : 0,00% : 4447 | 74 | | [C] : pairs : -1 : 0,000 : 0,00% : 6 | 75 | | [C] : newTransform : -1 : 0,000 : 0,00% : 1 | 76 | | [string "wrap_Math.lua"] : random : 37 : 0,000 : 0,00% : 790 | 77 | | [C] : __index : -1 : 0,000 : 0,00% : 790 | 78 | | [string "wrap_RandomGenerator.lua"] : random : 75 : 0,000 : 0,00% : 790 | 79 | | [C] : random : -1 : 0,000 : 0,00% : 790 | 80 | | [C] : newCanvas : -1 : 0,000 : 0,00% : 1 | 81 | | [C] : getHeight : -1 : 0,000 : 0,00% : 8899 | 82 | | [C] : getTime : -1 : 0,000 : 0,00% : 2 | 83 | | [C] : type : -1 : 0,000 : 0,00% : 53 | 84 | | dev/profi.lua : start : 67 : 0,000 : 0,00% : 0 | 85 | | [C] : getWidth : -1 : 0,000 : 0,00% : 8898 | 86 | | [C] : newImage : -1 : 0,000 : 0,00% : 4 | 87 | | [C] : applyTransform : -1 : 0,000 : 0,00% : 4447 | 88 | | [C] : tonumber : -1 : 0,000 : 0,00% : 790 | 89 | | [C] : step : -1 : 0,000 : 0,00% : 4448 | 90 | | [C] : origin : -1 : 0,000 : 0,00% : 4447 | 91 | | [C] : isActive : -1 : 0,000 : 0,00% : 4447 | 92 | | [C] : getBackgroundColor : -1 : 0,000 : 0,00% : 4447 | 93 | | [C] : push : -1 : 0,000 : 0,00% : 4447 | 94 | | [C] : clear : -1 : 0,000 : 0,00% : 8894 | 95 | | main.lua : load : 17 : 0,000 : 0,00% : 0 | 96 | | dev/profi.lua : stopHooks : 238 : 0,000 : 0,00% : 1 | 97 | | [C] : pump : -1 : 0,000 : 0,00% : 4448 | 98 | | [string "boot.lua"] : anonymous : 487 : 0,000 : 0,00% : 0 | 99 | | [C] : (for generator) : -1 : 0,000 : 0,00% : 4455 | 100 | | [string "boot.lua"] : anonymous : 639 : 0,000 : 0,00% : 0 | 101 | | [C] : xpcall : -1 : 0,000 : 0,00% : 4448 | 102 | | [C] : yield : -1 : 0,000 : 0,00% : 4448 | 103 | | [C] : sethook : -1 : 0,000 : 0,00% : 1 | 104 | -------------------------------------------------------------------------------- /dev/profi.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | ProFi v1.3, by Luke Perkin 2012. MIT Licence http://www.opensource.org/licenses/mit-license.php. 3 | 4 | Example: 5 | ProFi = require 'ProFi' 6 | ProFi:start() 7 | some_function() 8 | another_function() 9 | coroutine.resume( some_coroutine ) 10 | ProFi:stop() 11 | ProFi:writeReport( 'MyProfilingReport.txt' ) 12 | 13 | API: 14 | *Arguments are specified as: type/name/default. 15 | ProFi:start( string/once/nil ) 16 | ProFi:stop() 17 | ProFi:checkMemory( number/interval/0, string/note/'' ) 18 | ProFi:writeReport( string/filename/'ProFi.txt' ) 19 | ProFi:reset() 20 | ProFi:setHookCount( number/hookCount/0 ) 21 | ProFi:setGetTimeMethod( function/getTimeMethod/os.clock ) 22 | ProFi:setInspect( string/methodName, number/levels/1 ) 23 | ]] 24 | 25 | ----------------------- 26 | -- Locals: 27 | ----------------------- 28 | 29 | local ProFi = {} 30 | local onDebugHook, sortByDurationDesc, sortByCallCount, getTime 31 | local DEFAULT_DEBUG_HOOK_COUNT = 0 32 | local FORMAT_HEADER_LINE = "| %-50s: %-40s: %-20s: %-12s: %-12s: %-12s|\n" 33 | local FORMAT_OUTPUT_LINE = "| %s: %-12s: %-12s: %-12s|\n" 34 | local FORMAT_INSPECTION_LINE = "> %s: %-12s\n" 35 | local FORMAT_TOTALTIME_LINE = "| TOTAL TIME = %f\n" 36 | local FORMAT_MEMORY_LINE = "| %-20s: %-16s: %-16s| %s\n" 37 | local FORMAT_HIGH_MEMORY_LINE = "H %-20s: %-16s: %-16sH %s\n" 38 | local FORMAT_LOW_MEMORY_LINE = "L %-20s: %-16s: %-16sL %s\n" 39 | local FORMAT_TITLE = "%-50.50s: %-40.40s: %-20s" 40 | local FORMAT_LINENUM = "%4i" 41 | local FORMAT_TIME = "%04.3f" 42 | local FORMAT_RELATIVE = "%03.2f%%" 43 | local FORMAT_COUNT = "%7i" 44 | local FORMAT_KBYTES = "%7i Kbytes" 45 | local FORMAT_MBYTES = "%7.1f Mbytes" 46 | local FORMAT_MEMORY_HEADER1 = "\n=== HIGH & LOW MEMORY USAGE ===============================\n" 47 | local FORMAT_MEMORY_HEADER2 = "=== MEMORY USAGE ==========================================\n" 48 | local FORMAT_BANNER = [[ 49 | ############################################################################################################### 50 | ##### ProFi, a lua profiler. This profile was generated on: %s 51 | ##### ProFi is created by Luke Perkin 2012 under the MIT Licence, www.locofilm.co.uk 52 | ##### Version 1.3. Get the most recent version at this gist: https://gist.github.com/2838755 53 | ############################################################################################################### 54 | 55 | ]] 56 | 57 | ----------------------- 58 | -- Public Methods: 59 | ----------------------- 60 | 61 | --[[ 62 | Starts profiling any method that is called between this and ProFi:stop(). 63 | Pass the parameter 'once' to so that this methodis only run once. 64 | Example: 65 | ProFi:start( 'once' ) 66 | ]] 67 | function ProFi:start( param ) 68 | if param == 'once' then 69 | if self:shouldReturn() then 70 | return 71 | else 72 | self.should_run_once = true 73 | end 74 | end 75 | self.has_started = true 76 | self.has_finished = false 77 | self:resetReports( self.reports ) 78 | self:startHooks() 79 | self.startTime = getTime() 80 | end 81 | 82 | --[[ 83 | Stops profiling. 84 | ]] 85 | function ProFi:stop() 86 | if self:shouldReturn() then 87 | return 88 | end 89 | self.stopTime = getTime() 90 | self:stopHooks() 91 | self.has_finished = true 92 | end 93 | 94 | function ProFi:checkMemory( interval, note ) 95 | local time = getTime() 96 | local interval = interval or 0 97 | if self.lastCheckMemoryTime and time < self.lastCheckMemoryTime + interval then 98 | return 99 | end 100 | self.lastCheckMemoryTime = time 101 | local memoryReport = { 102 | ['time'] = time; 103 | ['memory'] = collectgarbage('count'); 104 | ['note'] = note or ''; 105 | } 106 | table.insert( self.memoryReports, memoryReport ) 107 | self:setHighestMemoryReport( memoryReport ) 108 | self:setLowestMemoryReport( memoryReport ) 109 | end 110 | 111 | --[[ 112 | Writes the profile report to a file. 113 | Param: [filename:string:optional] defaults to 'ProFi.txt' if not specified. 114 | ]] 115 | function ProFi:writeReport( filename ) 116 | if #self.reports > 0 or #self.memoryReports > 0 then 117 | filename = filename or 'ProFi.txt' 118 | self:sortReportsWithSortMethod( self.reports, self.sortMethod ) 119 | self:writeReportsToFilename( filename ) 120 | print( string.format("[ProFi]\t Report written to %s", filename) ) 121 | end 122 | end 123 | 124 | --[[ 125 | Resets any profile information stored. 126 | ]] 127 | function ProFi:reset() 128 | self.reports = {} 129 | self.reportsByTitle = {} 130 | self.memoryReports = {} 131 | self.highestMemoryReport = nil 132 | self.lowestMemoryReport = nil 133 | self.has_started = false 134 | self.has_finished = false 135 | self.should_run_once = false 136 | self.lastCheckMemoryTime = nil 137 | self.hookCount = self.hookCount or DEFAULT_DEBUG_HOOK_COUNT 138 | self.sortMethod = self.sortMethod or sortByDurationDesc 139 | self.inspect = nil 140 | end 141 | 142 | --[[ 143 | Set how often a hook is called. 144 | See http://pgl.yoyo.org/luai/i/debug.sethook for information. 145 | Param: [hookCount:number] if 0 ProFi counts every time a function is called. 146 | if 2 ProFi counts every other 2 function calls. 147 | ]] 148 | function ProFi:setHookCount( hookCount ) 149 | self.hookCount = hookCount 150 | end 151 | 152 | --[[ 153 | Set how the report is sorted when written to file. 154 | Param: [sortType:string] either 'duration' or 'count'. 155 | 'duration' sorts by the time a method took to run. 156 | 'count' sorts by the number of times a method was called. 157 | ]] 158 | function ProFi:setSortMethod( sortType ) 159 | if sortType == 'duration' then 160 | self.sortMethod = sortByDurationDesc 161 | elseif sortType == 'count' then 162 | self.sortMethod = sortByCallCount 163 | end 164 | end 165 | 166 | --[[ 167 | By default the getTime method is os.clock (CPU time), 168 | If you wish to use other time methods pass it to this function. 169 | Param: [getTimeMethod:function] 170 | ]] 171 | function ProFi:setGetTimeMethod( getTimeMethod ) 172 | getTime = getTimeMethod 173 | end 174 | 175 | --[[ 176 | Allows you to inspect a specific method. 177 | Will write to the report a list of methods that 178 | call this method you're inspecting, you can optionally 179 | provide a levels parameter to traceback a number of levels. 180 | Params: [methodName:string] the name of the method you wish to inspect. 181 | [levels:number:optional] the amount of levels you wish to traceback, defaults to 1. 182 | ]] 183 | function ProFi:setInspect( methodName, levels ) 184 | if self.inspect then 185 | self.inspect.methodName = methodName 186 | self.inspect.levels = levels or 1 187 | else 188 | self.inspect = { 189 | ['methodName'] = methodName; 190 | ['levels'] = levels or 1; 191 | } 192 | end 193 | end 194 | 195 | ----------------------- 196 | -- Implementations methods: 197 | ----------------------- 198 | 199 | function ProFi:shouldReturn( ) 200 | return self.should_run_once and self.has_finished 201 | end 202 | 203 | function ProFi:getFuncReport( funcInfo ) 204 | local title = self:getTitleFromFuncInfo( funcInfo ) 205 | local funcReport = self.reportsByTitle[ title ] 206 | if not funcReport then 207 | funcReport = self:createFuncReport( funcInfo ) 208 | self.reportsByTitle[ title ] = funcReport 209 | table.insert( self.reports, funcReport ) 210 | end 211 | return funcReport 212 | end 213 | 214 | function ProFi:getTitleFromFuncInfo( funcInfo ) 215 | local name = funcInfo.name or 'anonymous' 216 | local source = funcInfo.short_src or 'C_FUNC' 217 | local linedefined = funcInfo.linedefined or 0 218 | linedefined = string.format( FORMAT_LINENUM, linedefined ) 219 | return string.format(FORMAT_TITLE, source, name, linedefined) 220 | end 221 | 222 | function ProFi:createFuncReport( funcInfo ) 223 | local name = funcInfo.name or 'anonymous' 224 | local source = funcInfo.source or 'C Func' 225 | local linedefined = funcInfo.linedefined or 0 226 | local funcReport = { 227 | ['title'] = self:getTitleFromFuncInfo( funcInfo ); 228 | ['count'] = 0; 229 | ['timer'] = 0; 230 | } 231 | return funcReport 232 | end 233 | 234 | function ProFi:startHooks() 235 | debug.sethook( onDebugHook, 'cr', self.hookCount ) 236 | end 237 | 238 | function ProFi:stopHooks() 239 | debug.sethook() 240 | end 241 | 242 | function ProFi:sortReportsWithSortMethod( reports, sortMethod ) 243 | if reports then 244 | table.sort( reports, sortMethod ) 245 | end 246 | end 247 | 248 | function ProFi:writeReportsToFilename( filename ) 249 | local file, err = io.open( filename, 'w' ) 250 | assert( file, err ) 251 | self:writeBannerToFile( file ) 252 | if #self.reports > 0 then 253 | self:writeProfilingReportsToFile( self.reports, file ) 254 | end 255 | if #self.memoryReports > 0 then 256 | self:writeMemoryReportsToFile( self.memoryReports, file ) 257 | end 258 | file:close() 259 | end 260 | 261 | function ProFi:writeProfilingReportsToFile( reports, file ) 262 | local totalTime = self.stopTime - self.startTime 263 | local totalTimeOutput = string.format(FORMAT_TOTALTIME_LINE, totalTime) 264 | file:write( totalTimeOutput ) 265 | local header = string.format( FORMAT_HEADER_LINE, "FILE", "FUNCTION", "LINE", "TIME", "RELATIVE", "CALLED" ) 266 | file:write( header ) 267 | for i, funcReport in ipairs( reports ) do 268 | local timer = string.format(FORMAT_TIME, funcReport.timer) 269 | local count = string.format(FORMAT_COUNT, funcReport.count) 270 | local relTime = string.format(FORMAT_RELATIVE, (funcReport.timer / totalTime) * 100 ) 271 | local outputLine = string.format(FORMAT_OUTPUT_LINE, funcReport.title, timer, relTime, count ) 272 | file:write( outputLine ) 273 | if funcReport.inspections then 274 | self:writeInpsectionsToFile( funcReport.inspections, file ) 275 | end 276 | end 277 | end 278 | 279 | function ProFi:writeMemoryReportsToFile( reports, file ) 280 | file:write( FORMAT_MEMORY_HEADER1 ) 281 | self:writeHighestMemoryReportToFile( file ) 282 | self:writeLowestMemoryReportToFile( file ) 283 | file:write( FORMAT_MEMORY_HEADER2 ) 284 | for i, memoryReport in ipairs( reports ) do 285 | local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_MEMORY_LINE ) 286 | file:write( outputLine ) 287 | end 288 | end 289 | 290 | function ProFi:writeHighestMemoryReportToFile( file ) 291 | local memoryReport = self.highestMemoryReport 292 | local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_HIGH_MEMORY_LINE ) 293 | file:write( outputLine ) 294 | end 295 | 296 | function ProFi:writeLowestMemoryReportToFile( file ) 297 | local memoryReport = self.lowestMemoryReport 298 | local outputLine = self:formatMemoryReportWithFormatter( memoryReport, FORMAT_LOW_MEMORY_LINE ) 299 | file:write( outputLine ) 300 | end 301 | 302 | function ProFi:formatMemoryReportWithFormatter( memoryReport, formatter ) 303 | local time = string.format(FORMAT_TIME, memoryReport.time) 304 | local kbytes = string.format(FORMAT_KBYTES, memoryReport.memory) 305 | local mbytes = string.format(FORMAT_MBYTES, memoryReport.memory/1024) 306 | local outputLine = string.format(formatter, time, kbytes, mbytes, memoryReport.note) 307 | return outputLine 308 | end 309 | 310 | function ProFi:writeBannerToFile( file ) 311 | local banner = string.format(FORMAT_BANNER, os.date()) 312 | file:write( banner ) 313 | end 314 | 315 | function ProFi:writeInpsectionsToFile( inspections, file ) 316 | local inspectionsList = self:sortInspectionsIntoList( inspections ) 317 | file:write('\n==^ INSPECT ^======================================================================================================== COUNT ===\n') 318 | for i, inspection in ipairs( inspectionsList ) do 319 | local line = string.format(FORMAT_LINENUM, inspection.line) 320 | local title = string.format(FORMAT_TITLE, inspection.source, inspection.name, line) 321 | local count = string.format(FORMAT_COUNT, inspection.count) 322 | local outputLine = string.format(FORMAT_INSPECTION_LINE, title, count ) 323 | file:write( outputLine ) 324 | end 325 | file:write('===============================================================================================================================\n\n') 326 | end 327 | 328 | function ProFi:sortInspectionsIntoList( inspections ) 329 | local inspectionsList = {} 330 | for k, inspection in pairs(inspections) do 331 | inspectionsList[#inspectionsList+1] = inspection 332 | end 333 | table.sort( inspectionsList, sortByCallCount ) 334 | return inspectionsList 335 | end 336 | 337 | function ProFi:resetReports( reports ) 338 | for i, report in ipairs( reports ) do 339 | report.timer = 0 340 | report.count = 0 341 | report.inspections = nil 342 | end 343 | end 344 | 345 | function ProFi:shouldInspect( funcInfo ) 346 | return self.inspect and self.inspect.methodName == funcInfo.name 347 | end 348 | 349 | function ProFi:getInspectionsFromReport( funcReport ) 350 | local inspections = funcReport.inspections 351 | if not inspections then 352 | inspections = {} 353 | funcReport.inspections = inspections 354 | end 355 | return inspections 356 | end 357 | 358 | function ProFi:getInspectionWithKeyFromInspections( key, inspections ) 359 | local inspection = inspections[key] 360 | if not inspection then 361 | inspection = { 362 | ['count'] = 0; 363 | } 364 | inspections[key] = inspection 365 | end 366 | return inspection 367 | end 368 | 369 | function ProFi:doInspection( inspect, funcReport ) 370 | local inspections = self:getInspectionsFromReport( funcReport ) 371 | local levels = 5 + inspect.levels 372 | local currentLevel = 5 373 | while currentLevel < levels do 374 | local funcInfo = debug.getinfo( currentLevel, 'nS' ) 375 | if funcInfo then 376 | local source = funcInfo.short_src or '[C]' 377 | local name = funcInfo.name or 'anonymous' 378 | local line = funcInfo.linedefined 379 | local key = source..name..line 380 | local inspection = self:getInspectionWithKeyFromInspections( key, inspections ) 381 | inspection.source = source 382 | inspection.name = name 383 | inspection.line = line 384 | inspection.count = inspection.count + 1 385 | currentLevel = currentLevel + 1 386 | else 387 | break 388 | end 389 | end 390 | end 391 | 392 | function ProFi:onFunctionCall( funcInfo ) 393 | local funcReport = ProFi:getFuncReport( funcInfo ) 394 | funcReport.callTime = getTime() 395 | funcReport.count = funcReport.count + 1 396 | if self:shouldInspect( funcInfo ) then 397 | self:doInspection( self.inspect, funcReport ) 398 | end 399 | end 400 | 401 | function ProFi:onFunctionReturn( funcInfo ) 402 | local funcReport = ProFi:getFuncReport( funcInfo ) 403 | if funcReport.callTime then 404 | funcReport.timer = funcReport.timer + (getTime() - funcReport.callTime) 405 | end 406 | end 407 | 408 | function ProFi:setHighestMemoryReport( memoryReport ) 409 | if not self.highestMemoryReport then 410 | self.highestMemoryReport = memoryReport 411 | else 412 | if memoryReport.memory > self.highestMemoryReport.memory then 413 | self.highestMemoryReport = memoryReport 414 | end 415 | end 416 | end 417 | 418 | function ProFi:setLowestMemoryReport( memoryReport ) 419 | if not self.lowestMemoryReport then 420 | self.lowestMemoryReport = memoryReport 421 | else 422 | if memoryReport.memory < self.lowestMemoryReport.memory then 423 | self.lowestMemoryReport = memoryReport 424 | end 425 | end 426 | end 427 | 428 | ----------------------- 429 | -- Local Functions: 430 | ----------------------- 431 | 432 | getTime = os.clock 433 | 434 | onDebugHook = function( hookType ) 435 | local funcInfo = debug.getinfo( 2, 'nS' ) 436 | if hookType == "call" then 437 | ProFi:onFunctionCall( funcInfo ) 438 | elseif hookType == "return" then 439 | ProFi:onFunctionReturn( funcInfo ) 440 | end 441 | end 442 | 443 | sortByDurationDesc = function( a, b ) 444 | return a.timer > b.timer 445 | end 446 | 447 | sortByCallCount = function( a, b ) 448 | return a.count > b.count 449 | end 450 | 451 | ----------------------- 452 | -- Return Module: 453 | ----------------------- 454 | 455 | ProFi:reset() 456 | return ProFi -------------------------------------------------------------------------------- /luven/luven.lua: -------------------------------------------------------------------------------- 1 | local luven = { 2 | _VERSION = 'Luven v1.4', 3 | _URL = 'https://github.com/chicogamedev/Luven', 4 | _DESCRIPTION = 'A minimalist light engine for Löve2D', 5 | _CONTRIBUTORS = 'Lionel Leeser, Pedro Gimeno (Help with camera), Brandon Blanker Lim-it', 6 | _LICENSE = [[ 7 | MIT License 8 | 9 | Copyright (c) 2020 Lionel Leeser 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | ]] 29 | } 30 | 31 | -- /////////////////////////////////////////////// 32 | -- /// Luven error management local functions 33 | -- /////////////////////////////////////////////// 34 | 35 | local function assertPositiveNumber(functionName, parameterName, parameterValue, level) 36 | level = level or 3 37 | if ((type(parameterValue) ~= "number") or (parameterValue < 0)) then 38 | error(functionName .. "\n parameter : " .. parameterName .. ", expected positive number.", level) 39 | end 40 | end 41 | 42 | local function assertRangeNumber(functionName, parameterName, parameterValue, min, max, level) 43 | min = min or 0 44 | max = max or 1 45 | level = level or 3 46 | if ((type(parameterValue) ~= "number") or (parameterValue < min) or (parameterValue > max)) then 47 | error(functionName .. "\n parameter : " .. parameterName .. ", expected range number between " .. min .. " and " .. max .. ".", level) 48 | end 49 | end 50 | 51 | local function assertType(functionName, parameterName, parameterValue, parameterType, level) 52 | level = level or 3 53 | if (type(parameterValue) ~= parameterType) then 54 | error(functionName .. "\n parameter : " .. parameterName .. ", expected type ".. parameterType .. ".", level) 55 | end 56 | end 57 | 58 | local function assertLightShape(newShapeName, level) 59 | level = level or 3 60 | if (luven.lightShapes[newShapeName] ~= nil) then 61 | error("The light shapes : " .. newShapeName .. " already exists, please set another name.") 62 | end 63 | end 64 | 65 | -- /////////////////////////////////////////////// 66 | -- /// Math functions 67 | -- /////////////////////////////////////////////// 68 | 69 | local function lerp(a, b, x) 70 | return a + (b - a)*x 71 | end 72 | 73 | -- /////////////////////////////////////////////// 74 | -- /// Aliases 75 | -- /////////////////////////////////////////////// 76 | 77 | local lg = love.graphics 78 | local lgDraw = lg.draw 79 | local lgSetColor = lg.setColor 80 | 81 | -- /////////////////////////////////////////////// 82 | -- /// Luven camera 83 | -- /////////////////////////////////////////////// 84 | 85 | luven.camera = {} 86 | 87 | luven.camera.x = 0 88 | luven.camera.y = 0 89 | luven.camera.scaleX = 1 90 | luven.camera.scaleY = 1 91 | luven.camera.rotation = 0 92 | luven.camera.transform = nil 93 | 94 | luven.camera.shakeDuration = 0 95 | luven.camera.shakeMagnitude = 0 96 | 97 | luven.camera.fading = false 98 | luven.camera.fadeDuration = 0 99 | luven.camera.fadeTimer = 0 100 | luven.camera.fadeColor = { 0, 0, 0, 0 } 101 | luven.camera.startFadeColor = nil 102 | luven.camera.endFadeColor = nil 103 | luven.camera.fadeAction = nil 104 | 105 | luven.camera.useTarget = false 106 | luven.camera.moveTarget = { x = 0, y = 0 } 107 | luven.camera.moveSmooth = { x = 0, y = 0 } 108 | 109 | -- ////////////////////////////// 110 | -- /// Camera local functions 111 | -- ////////////////////////////// 112 | 113 | local function cameraUpdate(dt) 114 | local lc = luven.camera 115 | 116 | if (lc.shakeDuration > 0) then 117 | lc.shakeDuration = lc.shakeDuration - dt 118 | end 119 | 120 | if (lc.fading) then 121 | lc.fadeTimer = lc.fadeTimer + dt 122 | lc.fadeColor = { 123 | lerp(lc.startFadeColor[1], lc.endFadeColor[1], lc.fadeTimer / lc.fadeDuration), 124 | lerp(lc.startFadeColor[2], lc.endFadeColor[2], lc.fadeTimer / lc.fadeDuration), 125 | lerp(lc.startFadeColor[3], lc.endFadeColor[3], lc.fadeTimer / lc.fadeDuration), 126 | lerp(lc.startFadeColor[4], lc.endFadeColor[4], lc.fadeTimer / lc.fadeDuration) 127 | } 128 | 129 | if (lc.fadeTimer >= lc.fadeDuration) then 130 | lc.fadeTimer = 0 131 | lc.fading = false 132 | 133 | if (lc.fadeAction ~= nil) then 134 | lc.fadeAction() 135 | end 136 | end 137 | end 138 | 139 | if (lc.useTarget) then 140 | lc.x = lerp(lc.x, lc.moveTarget.x, lc.moveSmooth.x) 141 | lc.y = lerp(lc.y, lc.moveTarget.y, lc.moveSmooth.y) 142 | end 143 | end 144 | 145 | -- ////////////////////////////// 146 | -- /// Camera accessible functions 147 | -- ////////////////////////////// 148 | 149 | function luven.camera:init(x, y) 150 | local functionName = "luven.camera:init(x, y)" 151 | assertType(functionName, "x", x, "number") 152 | assertType(functionName, "y", y, "number") 153 | self.transform = love.math.newTransform(x, y) 154 | self.x = x 155 | self.y = y 156 | self.moveTarget.x = x 157 | self.moveTarget.y = y 158 | end 159 | 160 | function luven.camera:set() 161 | local dx, dy = 0, 0 162 | if (luven.camera.shakeDuration > 0) then 163 | dx = love.math.random(-luven.camera.shakeMagnitude, luven.camera.shakeMagnitude) 164 | dy = love.math.random(-luven.camera.shakeMagnitude, luven.camera.shakeMagnitude) 165 | end 166 | lg.push() 167 | self.transform:setTransformation(lg.getWidth() / 2, lg.getHeight() / 2, self.rotation, self.scaleX, self.scaleY, self.x + dx, self.y + dy) 168 | lg.applyTransform(self.transform) 169 | end 170 | 171 | function luven.camera:unset() 172 | lg.pop() 173 | end 174 | 175 | function luven.camera:draw() 176 | local oldR, oldG, oldB, oldA = lg.getColor() 177 | 178 | -- Fade rectangle 179 | lg.setColor(self.fadeColor) 180 | lg.rectangle("fill", 0, 0, lg.getWidth(), lg.getHeight()) 181 | 182 | lg.setColor(oldR, oldG, oldB, oldA) 183 | end 184 | 185 | function luven.camera:setPosition(x, y) 186 | self.x = x 187 | self.y = y 188 | self.useTarget = false 189 | end 190 | 191 | function luven.camera:move(dx, dy) 192 | self.x = self.x + dx 193 | self.y = self.y + dy 194 | self.useTarget = false 195 | end 196 | 197 | function luven.camera:setMoveSmooth(x, y) 198 | y = y or x 199 | 200 | self.moveSmooth.x = x 201 | self.moveSmooth.y = y 202 | end 203 | 204 | function luven.camera:setMoveTarget(x, y) 205 | self.moveTarget.x = x 206 | self.moveTarget.y = y 207 | self.useTarget = true 208 | end 209 | 210 | function luven.camera:setRotation(dr) 211 | self.rotation = dr 212 | end 213 | 214 | function luven.camera:setScale(sx, sy) 215 | self.scaleX = sx or 1 216 | self.scaleY = sy or sx or 1 217 | end 218 | 219 | function luven.camera:setShake(duration, magnitude) 220 | self.shakeDuration = duration 221 | self.shakeMagnitude = magnitude 222 | end 223 | 224 | -- color : COLOR : { r, g, b, a } 225 | -- action : FUNCTION 226 | function luven.camera:setFade(duration, color, action) 227 | self.fadeDuration = duration 228 | self.fadeTimer = 0 229 | self.startFadeColor = self.fadeColor 230 | self.endFadeColor = color 231 | self.fadeAction = action 232 | self.fading = true 233 | end 234 | 235 | -- /////////////////////////////////////////////// 236 | -- /// Luven variables declarations 237 | -- /////////////////////////////////////////////// 238 | 239 | local NUM_LIGHTS = 500 240 | local lightsSize = 256 241 | 242 | local luvenPath = debug.getinfo(1,'S').source -- get Luven path 243 | luvenPath = string.sub(luvenPath, 2, string.len(luvenPath) - 9) -- 9 = luven.lua 244 | 245 | local lightTypes = { 246 | normal = 0, 247 | flickering = 1, 248 | flashing = 2 249 | } 250 | 251 | local currentLights = {} 252 | local useIntegratedCamera = true 253 | 254 | local ambientLightColor = { 0, 0, 0, 1 } 255 | 256 | local lastActiveLightIndex = 0 257 | 258 | local lightMap = nil 259 | 260 | -- /////////////////////////////////////////////// 261 | -- /// Luven light shapes 262 | -- /////////////////////////////////////////////// 263 | 264 | luven.lightShapes = {} 265 | 266 | -- /////////////////////////////////////////////// 267 | -- /// Luven utils local functions 268 | -- /////////////////////////////////////////////// 269 | 270 | local function drawLights() 271 | lg.setCanvas(lightMap) 272 | lg.setBlendMode("add") 273 | 274 | lg.clear(ambientLightColor) -- ambientLightColor 275 | 276 | local oldR, oldG, oldB, oldA = lg.getColor() 277 | 278 | -- lastActiveLightIndex updated in luven.update() 279 | for i = 1, #currentLights do 280 | local light = currentLights[i] 281 | if (light.enabled) then 282 | lgSetColor(light.color) 283 | lgDraw(light.shape.sprite, light.x, light.y, light.angle, light.scaleX * light.power, light.scaleY * light.power, light.shape.originX, light.shape.originY) 284 | end 285 | end 286 | 287 | lgSetColor(oldR, oldG, oldB, oldA) 288 | lg.setBlendMode("alpha") 289 | 290 | lg.setCanvas() 291 | end 292 | 293 | local function randomFloat(min, max) 294 | return min + love.math.random() * (max - min) 295 | end 296 | 297 | local function clearTable(table) 298 | for k, _ in pairs(table) do table[k]=nil end 299 | end 300 | 301 | local function generateFlicker(lightId) 302 | local light = currentLights[lightId] 303 | 304 | light.color[1] = randomFloat(light.colorRange.min[1], light.colorRange.max[1]) 305 | light.color[2] = randomFloat(light.colorRange.min[2], light.colorRange.max[2]) 306 | light.color[3] = randomFloat(light.colorRange.min[3], light.colorRange.max[3]) 307 | 308 | light.power = randomFloat(light.powerRange.min, light.powerRange.max) 309 | 310 | light.flickTimer = randomFloat(light.speedRange.min, light.speedRange.max) 311 | end 312 | 313 | -- /////////////////////////////////////////////// 314 | -- /// Luven general functions 315 | -- /////////////////////////////////////////////// 316 | 317 | function luven.init(screenWidth, screenHeight, useCamera) 318 | screenWidth = screenWidth or lg.getWidth() 319 | screenHeight = screenHeight or lg.getHeight() 320 | if (useCamera ~= nil) then 321 | useIntegratedCamera = useCamera 322 | else 323 | useIntegratedCamera = true 324 | end 325 | 326 | local functionName = "luven.init( [ screenWidth ], [ screenHeight ], [ useCamera ] )" 327 | assertPositiveNumber(functionName, "screenWidth", screenWidth) 328 | assertPositiveNumber(functionName, "screenHeight", screenHeight) 329 | assertType(functionName, "useCamera", useIntegratedCamera, "boolean") 330 | 331 | luven.registerLightShape("round", luvenPath .. "lights/round.png") 332 | luven.registerLightShape("rectangle", luvenPath .. "lights/rectangle.png") 333 | luven.registerLightShape("cone", luvenPath .. "lights/cone.png", 0) 334 | 335 | lightMap = lg.newCanvas(screenWidth, screenHeight) 336 | end 337 | 338 | -- param : color = { r, g, b, a (1) } (Values between 0 - 1) 339 | function luven.setAmbientLightColor(color) 340 | color[4] = color[4] or 1 341 | ambientLightColor = color 342 | end 343 | 344 | function luven.registerLightShape(name, spritePath, originX, originY) 345 | local functionName = "luven.registerLightShape( name, spritePath, [ originX ], [ originY ] )" 346 | assertLightShape(name) 347 | assertType(functionName, "spritePath", spritePath, "string") 348 | 349 | local lightSprite = lg.newImage(spritePath) 350 | originX = originX or (lightSprite:getWidth() / 2) 351 | originY = originY or (lightSprite:getHeight() / 2) 352 | 353 | assertPositiveNumber(functionName, "originX", originX) 354 | assertPositiveNumber(functionName, "originY", originY) 355 | 356 | luven.lightShapes[name] = { 357 | sprite = lightSprite, 358 | originX = originX, 359 | originY = originY 360 | } 361 | end 362 | 363 | function luven.update(dt) 364 | if (useIntegratedCamera) then 365 | cameraUpdate(dt) 366 | end 367 | 368 | for i = 1, #currentLights do 369 | local light = currentLights[i] 370 | if (light.enabled) then 371 | if (light.type == lightTypes.flickering) then 372 | if (light.flickTimer > 0) then 373 | light.flickTimer = light.flickTimer - dt 374 | else 375 | generateFlicker(light.id) 376 | end 377 | elseif (light.type == lightTypes.flashing) then 378 | light.timer = light.timer + dt 379 | if (light.power < light.maxPower) then 380 | light.power = (light.maxPower * light.timer) / light.speed 381 | else 382 | luven.removeLight(light.id) 383 | end 384 | end 385 | end 386 | end 387 | end 388 | 389 | function luven.drawBegin() 390 | if (useIntegratedCamera) then 391 | luven.camera:set() 392 | end 393 | 394 | drawLights() 395 | end 396 | 397 | function luven.drawEnd() 398 | if (useIntegratedCamera) then 399 | luven.camera:unset() 400 | end 401 | 402 | lg.setBlendMode("multiply", "premultiplied") 403 | lgDraw(lightMap) 404 | lg.setBlendMode("alpha") 405 | end 406 | 407 | function luven.removeAllLights() 408 | for _, v in ipairs(currentLights) do 409 | if (v.enabled) then 410 | luven.removeLight(v.id) 411 | end 412 | end 413 | end 414 | 415 | function luven.dispose() 416 | luven.removeAllLights() 417 | 418 | clearTable(currentLights) 419 | clearTable(luven.lightShapes) 420 | 421 | lightMap:release() 422 | end 423 | 424 | function luven.getLightCount() 425 | return #currentLights 426 | end 427 | 428 | -- /////////////////////////////////////////////// 429 | -- /// Luven utils functions 430 | -- /////////////////////////////////////////////// 431 | 432 | function luven.newColor(r, g, b, a) 433 | a = a or 1 434 | return { r, g, b, a } 435 | end 436 | 437 | function luven.newColorRange(minR, minG, minB, maxR, maxG, maxB, minA, maxA) 438 | minR = minR or 0 439 | minG = minG or 0 440 | minB = minB or 0 441 | maxR = maxR or 0 442 | maxG = maxG or 0 443 | maxB = maxB or 0 444 | minA = minA or 1 445 | maxA = maxA or 1 446 | return { min = { minR, minG, minB, minA }, max = { maxR, maxG, maxB, maxA } } 447 | end 448 | 449 | function luven.newNumberRange(minN, maxN) 450 | return { min = minN, max = maxN } 451 | end 452 | 453 | -- /////////////////////////////////////////////// 454 | -- /// Luven lights functions 455 | -- /////////////////////////////////////////////// 456 | 457 | -- param : color = { r, g, b } (values between 0 - 1) 458 | -- return : lightId 459 | function luven.addNormalLight(x, y, color, power, lightShape, angle, sx, sy) 460 | lightShape = lightShape or luven.lightShapes.round 461 | angle = angle or 0 462 | sx = sx or 1 463 | sy = sy or sx 464 | 465 | local functionName = "luven.addNormalLight(x, y, color, power, angle, sx, sy)" 466 | assertType(functionName, "x", x, "number") 467 | assertType(functionName, "y", y, "number") 468 | assertRangeNumber(functionName, "color[1]", color[1]) 469 | assertRangeNumber(functionName, "color[2]", color[2]) 470 | assertRangeNumber(functionName, "color[3]", color[3]) 471 | assertPositiveNumber(functionName, "power", power) 472 | assertType(functionName, "angle", angle, "number") 473 | assertPositiveNumber(functionName, "sx", sx) 474 | assertPositiveNumber(functionName, "sy", sy) 475 | 476 | local id = #currentLights + 1 477 | currentLights[id] = {} 478 | local light = currentLights[id] 479 | 480 | light.id = id 481 | light.x = x 482 | light.y = y 483 | light.angle = angle 484 | light.scaleX = sx 485 | light.scaleY = sy 486 | light.color = color 487 | light.power = power 488 | light.type = lightTypes.normal 489 | light.shape = lightShape 490 | 491 | light.enabled = true 492 | 493 | return light.id 494 | end 495 | 496 | -- params : colorRange = { min = { r, g, b }, max = { r, g, b }} 497 | -- powerRange = { min = n, max = n } 498 | -- speedRange = { min = n, max = n } 499 | -- return : lightId 500 | function luven.addFlickeringLight(x, y, colorRange, powerRange, speedRange, lightShape, angle, sx, sy) 501 | lightShape = lightShape or luven.lightShapes.round 502 | angle = angle or 0 503 | sx = sx or 1 504 | sy = sy or sx 505 | 506 | local functionName = "luven.addFlickeringLight(x, y, colorRange, powerRange, speedRange, angle, sx, sy)" 507 | assertType(functionName, "x", x, "number") 508 | assertType(functionName, "y", y, "number") 509 | assertRangeNumber(functionName, "colorRange.min[1]", colorRange.min[1]) 510 | assertRangeNumber(functionName, "colorRange.min[2]", colorRange.min[2]) 511 | assertRangeNumber(functionName, "colorRange.min[3]", colorRange.min[3]) 512 | assertRangeNumber(functionName, "colorRange.max[1]", colorRange.max[1]) 513 | assertRangeNumber(functionName, "colorRange.max[2]", colorRange.max[2]) 514 | assertRangeNumber(functionName, "colorRange.max[3]", colorRange.max[3]) 515 | assertPositiveNumber(functionName, "powerRange.min", powerRange.min) 516 | assertPositiveNumber(functionName, "powerRange.max", powerRange.max) 517 | assertPositiveNumber(functionName, "speedRange.min", speedRange.min) 518 | assertPositiveNumber(functionName, "speedRange.max", speedRange.max) 519 | assertType(functionName, "angle", angle, "number") 520 | assertPositiveNumber(functionName, "sx", sx) 521 | assertPositiveNumber(functionName, "sy", sy) 522 | 523 | local id = #currentLights + 1 524 | currentLights[id] = {} 525 | local light = currentLights[id] 526 | 527 | light.id = id 528 | light.x = x 529 | light.y = y 530 | light.angle = angle 531 | light.scaleX = sx 532 | light.scaleY = sy 533 | light.color = { 0, 0, 0 } 534 | light.power = 0 535 | light.type = lightTypes.flickering 536 | light.shape = lightShape 537 | 538 | light.flickTimer = 0 539 | light.colorRange = colorRange 540 | light.powerRange = powerRange 541 | light.speedRange = speedRange 542 | 543 | light.enabled = true 544 | 545 | generateFlicker(light.id) 546 | 547 | return light.id 548 | end 549 | 550 | function luven.addFlashingLight(x, y, color, maxPower, speed, lightShape, angle, sx, sy) 551 | lightShape = lightShape or luven.lightShapes.round 552 | angle = angle or 0 553 | sx = sx or 1 554 | sy = sy or sx 555 | 556 | local functionName = "luven.addFlashingLight(x, y, color, maxPower, speed, angle, sx, sy)" 557 | assertType(functionName, "x", x, "number") 558 | assertType(functionName, "y", y, "number") 559 | assertRangeNumber(functionName, "color[1]", color[1]) 560 | assertRangeNumber(functionName, "color[2]", color[2]) 561 | assertRangeNumber(functionName, "color[3]", color[3]) 562 | assertPositiveNumber(functionName, "maxPower", maxPower) 563 | assertPositiveNumber(functionName, "speed", speed) 564 | assertType(functionName, "angle", angle, "number") 565 | assertPositiveNumber(functionName, "sx", sx) 566 | assertPositiveNumber(functionName, "sy", sy) 567 | 568 | local id = #currentLights + 1 569 | currentLights[id] = {} 570 | local light = currentLights[id] 571 | 572 | light.id = id 573 | light.x = x 574 | light.y = y 575 | light.angle = angle 576 | light.scaleX = sx 577 | light.scaleY = sy 578 | light.color = color 579 | light.power = 0 580 | light.type = lightTypes.flashing 581 | light.shape = lightShape 582 | 583 | light.maxPower = maxPower 584 | light.speed = speed 585 | light.timer = 0 586 | 587 | light.enabled = true 588 | end 589 | 590 | function luven.removeLight(lightId) 591 | currentLights[lightId].enabled = false 592 | end 593 | 594 | function luven.moveLight(lightId, dx, dy) 595 | currentLights[lightId].x = currentLights[lightId].x + dx 596 | currentLights[lightId].y = currentLights[lightId].y + dy 597 | end 598 | 599 | function luven.setLightPower(lightId, p) 600 | currentLights[lightId].power = p 601 | end 602 | 603 | function luven.setLightPowerRange(lightId, r) 604 | currentLights[lightId].powerRange = r 605 | end 606 | 607 | -- param : color = { r, g, b } (values between 0 - 1) 608 | function luven.setLightColor(lightId, c) 609 | currentLights[lightId].color = c 610 | end 611 | 612 | function luven.setLightColorRange(lightId, r) 613 | currentLights[lightId].colorRange = r 614 | end 615 | 616 | function luven.setLightPosition(lightId, x, y) 617 | currentLights[lightId].x = x 618 | currentLights[lightId].y = y 619 | end 620 | 621 | function luven.setLightRotation(lightId, dr) 622 | currentLights[lightId].angle = dr 623 | end 624 | 625 | function luven.setLightSpeedRange(lightId, r) 626 | currentLights[lightId].speedRange = r 627 | end 628 | 629 | function luven.setLightScale(lightId, sx, sy) 630 | sx = sx or 1 631 | sy = sy or sx 632 | 633 | currentLights[lightId].scaleX = sx 634 | currentLights[lightId].scaleY = sy 635 | end 636 | 637 | function luven.getLightPower(lightId) 638 | return currentLights[lightId].power 639 | end 640 | 641 | function luven.getLightPowerRange(lightId) 642 | return currentLights[lightId].powerRange 643 | end 644 | 645 | function luven.getLightColor(lightId) 646 | return currentLights[lightId].color 647 | end 648 | 649 | function luven.getLightColorRange(lightId) 650 | return currentLights[lightId].colorRange 651 | end 652 | 653 | function luven.getLightPosition(lightId) 654 | return currentLights[lightId].x, currentLights[lightId].y 655 | end 656 | 657 | function luven.getLightRotation(lightId) 658 | return currentLights[lightId].angle 659 | end 660 | 661 | function luven.getLightSpeedRange(lightId) 662 | return currentLights[lightId].speedRange 663 | end 664 | 665 | function luven.getLightScale(lightId) 666 | return currentLights[lightId].scaleX, currentLights[lightId].scaleY 667 | end 668 | 669 | return luven 670 | --------------------------------------------------------------------------------