├── .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 |
--------------------------------------------------------------------------------