/ld27

To get this branch, use:
bzr branch http://9ix.org/bzr/ld27

« back to all changes in this revision

Viewing changes to zoetrope/core/app.lua

  • Committer: Josh C
  • Date: 2013-08-25 02:04:52 UTC
  • Revision ID: josh@9ix.org-20130825020452-py8fijli8m5te5gv
improve performance with (sketchy, experimental) sprite batches

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
-- Class: App 
 
2
-- An app is where all the magic happens. :) It contains a 
1
3
-- view, the group where all major action happens, as well as the
2
4
-- meta view, which persists across views. Only one app may run at
3
5
-- a time.
7
7
-- An app's job is to get things up and running -- most of its logic
8
8
-- lives in its onRun handler, but for a simple app, you can also
9
9
-- use the onUpdate handler instead of writing a custom <View>.
10
 
--
 
10
-- 
11
11
-- Once an app has begun running, it may be accessed globally via
12
12
-- <the>.app.
13
13
--
28
28
        -- Property: name
29
29
        -- This is shown in the window title bar.
30
30
        name = 'Zoetrope',
31
 
 
 
31
        
32
32
        -- Property: icon
33
33
        -- A path to an image to use as the window icon (a 32x32 PNG is recommended).
34
 
        -- This doesn't affect the actual executable's icon in the taskbar or dock.
 
34
        -- This doesn't affect the actual executable's icon in the taskbar or dock. 
35
35
 
36
36
        -- Property: fps
37
37
        -- Maximum frames per second requested. In practice, your
38
38
        -- FPS may vary from frame to frame. Every event handler (e.g. onUpdate)
39
39
        -- is passed the exact elapsed time in seconds.
40
40
        fps = 60,
41
 
 
 
41
        
42
42
        -- Property: timeScale
43
43
        -- Multiplier for elapsed time; 1.0 is normal, 0 is completely frozen.
44
44
        timeScale = 1,
45
 
 
 
45
        
46
46
        -- Property: active
47
47
        -- If false, nothing receives update-related events, including the meta view.
48
48
        -- These events specifically are onStartFrame, onUpdate, and onEndFrame.
52
52
        -- Should the app automatically set its active property to false when its
53
53
        -- window loses focus?
54
54
        deactivateOnBlur = true,
55
 
 
 
55
        
56
56
        -- Property: view
57
57
        -- The current <View>. When the app is running, this is also accessible
58
58
        -- globally via <the>.view. In order to switch views, you must set this
99
99
                obj = self:extend(obj)
100
100
 
101
101
                -- set icon if possible
102
 
 
 
102
                
103
103
                if self.icon then
104
 
                        love.window.setIcon(Cached:image(self.icon))
 
104
                        love.graphics.setIcon(Cached:image(self.icon))
105
105
                end
106
 
 
 
106
        
107
107
                -- view containers
108
108
 
109
 
                obj.meta = obj.meta or View:new()
110
 
                obj.view = obj.view or View:new()
111
 
 
 
109
                obj.meta = obj.meta or Group:new()
 
110
                obj.view = obj.view or View:new()               
 
111
                
112
112
                -- input
113
113
 
114
114
                if love.keyboard then
136
136
 
137
137
                -- screen dimensions and state
138
138
 
139
 
    local w, h, flags = love.window.getMode()
140
 
    if not obj.width then obj.width = w end
141
 
    if not obj.height then obj.height = h end
142
 
    obj.windowflags = flags
143
 
                obj.fullscreen = obj.windowflags.fullscreen
 
139
                obj.width, obj.height, obj.fullscreen = love.graphics.getMode()
144
140
 
145
141
                -- housekeeping
146
 
 
 
142
                
147
143
                the.app = obj
148
144
                if obj.onNew then obj:onNew() end
149
145
                return obj
154
150
        --
155
151
        -- Arguments:
156
152
        --              none
157
 
        --
 
153
        -- 
158
154
        -- Returns:
159
155
        --              nothing
160
156
 
168
164
                -- attach debug console
169
165
 
170
166
                if DEBUG then
171
 
                        debugger.init()
 
167
                        self.console = DebugConsole:new()
 
168
                        self.meta:add(self.console)
172
169
                end
173
170
 
174
171
                -- set up callbacks
175
 
 
176
 
                love.window.setTitle(self.name)
 
172
                
 
173
                love.graphics.setCaption(self.name)
177
174
                love.update = function (elapsed) self:update(elapsed) end
178
175
                love.draw = function() self:draw() end
179
 
                love.focus = function (value) self:onFocus(value) end
 
176
                love.focus = function (value) self:onFocus(value) end   
180
177
 
181
178
                if self.onRun then self:onRun() end
182
 
                self._nextFrameTime = love.timer.getTime()
 
179
                self._nextFrameTime = love.timer.getMicroTime()
183
180
        end,
184
 
 
 
181
        
185
182
        -- Method: quit
186
183
        -- Quits the application immediately.
187
184
        --
203
200
        --
204
201
        -- Returns:
205
202
        --              nothing
206
 
 
 
203
        
207
204
        useSysCursor = function (self, value)
208
205
                if STRICT then
209
206
                        assert(value == true or value == false,
231
228
                        assert(not self.fullscreen, 'asked to enter fullscreen when already in fullscreen')
232
229
                end
233
230
 
234
 
                local modes = love.window.getFullscreenModes()
 
231
                local modes = love.graphics.getModes()
235
232
 
236
233
                if not hint then
237
234
                        if self.width * 9 == self.height * 16 then
249
246
                for _, mode in pairs(modes) do
250
247
                        mode.area = mode.width * mode.height
251
248
 
252
 
                        if (mode.area > bestMode.area) and
 
249
                        if (mode.area > bestMode.area) and 
253
250
                           ((hint == 'letterbox' and mode.width == self.width) or
254
251
                            (hint == 'pillar' and mode.height == self.height)) then
255
252
                                        bestMode = mode
259
256
                -- if we found a match, switch to it
260
257
 
261
258
                if bestMode.width then
262
 
                        love.window.setMode(bestMode.width, bestMode.height, {fullscreen = true})
 
259
                        love.graphics.setMode(bestMode.width, bestMode.height, true)
263
260
                        self.fullscreen = true
264
261
 
265
262
                        -- and adjust inset and scissor
287
284
                if STRICT then
288
285
                        assert(self.fullscreen, 'asked to exit fullscreen when already out of fullscreen')
289
286
                end
290
 
 
291
 
                love.window.setMode(self.width, self.height, {fullscreen = false})
 
287
        
 
288
                love.graphics.setMode(self.width, self.height, false)
292
289
                love.graphics.setScissor(0, 0, self.width, self.height)
293
290
                self.fullscreen = false
294
291
                self.inset.x = 0
338
335
        --
339
336
        -- Arguments:
340
337
        --              sprite - sprite to add
341
 
        --
 
338
        -- 
342
339
        -- Returns:
343
 
        --              sprite added
 
340
        --              nothing
344
341
 
345
342
        add = function (self, sprite)
346
 
                return self.view:add(sprite)
 
343
                self.view:add(sprite)
347
344
        end,
348
345
 
349
346
        -- Method: remove
368
365
                elapsed = elapsed * self.timeScale
369
366
 
370
367
                -- sync the.view with our current view
371
 
 
 
368
                
372
369
                local view = self.view
373
370
                if the.view ~= view then the.view = view end
374
371
 
384
381
 
385
382
                -- update everyone
386
383
                -- all update events bubble up from child to parent
387
 
                -- (we consider the meta view a little
 
384
                -- (we consider the meta view a little 
388
385
 
389
386
                view:startFrame(elapsed)
390
387
                self.meta:startFrame(elapsed)
391
388
                if self.onStartFrame then self:onStartFrame(elapsed) end
392
 
 
393
 
                view:update(elapsed)
 
389
                
 
390
                view:update(elapsed)    
394
391
                self.meta:update(elapsed)
395
392
                if self.onUpdate then self:onUpdate(elapsed) end
396
393
 
398
395
                self.meta:endFrame(elapsed)
399
396
                if self.onEndFrame then self:onEndFrame(elapsed) end
400
397
        end,
401
 
 
 
398
        
402
399
        draw = function (self)
403
 
drawStart = love.timer.getTime()
 
400
drawStart = love.timer.getMicroTime()
404
401
                local inset = self.inset.x ~= 0 or self.inset.y ~= 0
405
402
 
406
403
                if inset then love.graphics.translate(self.inset.x, self.inset.y) end
410
407
 
411
408
                -- sleep off any unneeded time to keep up at our FPS
412
409
 
413
 
                local now = love.timer.getTime()
 
410
                local now = love.timer.getMicroTime()
414
411
the.drawTook = now - drawStart
415
412
                if self._nextFrameTime < now then
416
413
                        self._nextFrameTime = now
440
437
                        result = result .. 'inactive'
441
438
                end
442
439
 
443
 
                return result .. ', ' .. tostring(self.fps) .. ' fps, ' .. self.view:count(true) .. ' sprites)'
 
440
                return result .. ', ' .. self.fps .. ' fps, ' .. self.view:count(true) .. ' sprites)'
444
441
        end
445
442
}