WebGLLayer now recycles previous sprite sheets, speeding up rendering additional thang types or animations.

This commit is contained in:
Scott Erickson 2014-09-18 14:36:05 -07:00
parent cc76458942
commit a99cdfb957
3 changed files with 78 additions and 8 deletions

View file

@ -34,7 +34,6 @@ layerProperties = {
@layerPriority = options.layerPriority ? 0
@transformStyle = options.transform ? layerClassProperties.TRANSFORM_CHILD
@camera = options.camera
console.debug @toString(), 'needs a camera.' unless @camera
@updateLayerOrder = _.bind(@updateLayerOrder, @)
@updateLayerOrder = _.throttle @updateLayerOrder, 1000 / 30 # Don't call multiple times in one frame; 30 FPS is probably good enough
Backbone.Mediator.subscribe(channel, @[func], @) for channel, func of @subscriptions

View file

@ -146,6 +146,7 @@ module.exports = class WebGLLayer extends CocoClass
return
@spriteSheet = builder.spriteSheet
@spriteSheet.resolutionFactor = @resolutionFactor
oldLayer = @spriteContainer
@spriteContainer = new SpriteContainerLayer(@spriteSheet, @layerOptions)
for cocoSprite in @cocoSprites
@ -178,6 +179,11 @@ module.exports = class WebGLLayer extends CocoClass
spriteBuilder = new SpriteBuilder(thangType, {colorConfig: colorConfig})
for containerGlobalName in _.keys(containersToRender)
containerKey = @renderGroupingKey(thangType, containerGlobalName, colorConfig)
if @spriteSheet?.resolutionFactor is @resolutionFactor and containerKey in @spriteSheet.getAnimations()
container = new createjs.Sprite(@spriteSheet)
container.gotoAndStop(containerKey)
frame = spriteSheetBuilder.addFrame(container)
else
container = spriteBuilder.buildContainerFromStore(containerGlobalName)
frame = spriteSheetBuilder.addFrame(container, null, @resolutionFactor * (thangType.get('scale') or 1))
spriteSheetBuilder.addAnimation(containerKey, [frame], false)
@ -202,6 +208,22 @@ module.exports = class WebGLLayer extends CocoClass
for animationName, actions of animationGroups
renderAll = _.any actions, (action) -> action.frames is undefined
scale = actions[0].scale or thangType.get('scale') or 1
actionKeys = (@renderGroupingKey(thangType, action.name, colorConfig) for action in actions)
if @spriteSheet?.resolutionFactor is @resolutionFactor and _.all(actionKeys, (key) => key in @spriteSheet.getAnimations())
framesNeeded = _.uniq(_.flatten((@spriteSheet.getAnimation(key)).frames for key in actionKeys))
framesMap = {}
for frame in framesNeeded
sprite = new createjs.Sprite(@spriteSheet)
sprite.gotoAndStop(frame)
framesMap[frame] = spriteSheetBuilder.addFrame(sprite)
for key, index in actionKeys
action = actions[index]
frames = (framesMap[f] for f in @spriteSheet.getAnimation(key).frames)
next = @nextForAction(action)
spriteSheetBuilder.addAnimation(key, frames, next)
continue
mc = spriteBuilder.buildMovieClip(animationName, null, null, null, {'temp':0})
if renderAll
@ -223,11 +245,7 @@ module.exports = class WebGLLayer extends CocoClass
frames = (framesMap[parseInt(frame)] for frame in action.frames.split(','))
else
frames = _.values(framesMap).sort()
next = true
next = action.goesTo if action.goesTo
next = false if action.loops is false
next = @nextForAction(action)
spriteSheetBuilder.addAnimation(name, frames, next)
containerActions = []
@ -245,6 +263,12 @@ module.exports = class WebGLLayer extends CocoClass
name = @renderGroupingKey(thangType, action.name, colorConfig)
spriteSheetBuilder.addAnimation(name, [frame], false)
nextForAction: (action) ->
next = true
next = action.goesTo if action.goesTo
next = false if action.loops is false
return next
renderRasterImage: (thangType, spriteSheetBuilder) ->
unless thangType.rasterImage
console.error("Cannot render the WebGLLayer SpriteSheet until the raster image for <#{thangType.get('name')}> is loaded.")

View file

@ -3,6 +3,7 @@ CocoSprite = require 'lib/surface/CocoSprite'
ThangType = require 'models/ThangType'
treeThangType = new ThangType(require 'test/app/fixtures/tree1.thang.type')
ogreMunchkinThangType = new ThangType(require 'test/app/fixtures/ogre-munchkin-m.thang.type')
SpriteBuilder = require 'lib/sprites/SpriteBuilder'
describe 'WebGLLayer', ->
layer = null
@ -118,3 +119,49 @@ describe 'WebGLLayer', ->
thangType2.trigger('raster-image-loaded', thangType2)
expect(layer.numThingsLoading).toBe(0)
expect(layer._renderNewSpriteSheet).toHaveBeenCalled()
it 'recycles *containers* from previous sprite sheets, rather than building repeatedly from raw vector data', ->
treeThangType.set('renderStrategy', 'container')
sprite = new CocoSprite(treeThangType)
layer.addCocoSprite(sprite)
spyOn(SpriteBuilder.prototype, 'buildContainerFromStore').and.callThrough()
for i in _.range(2)
sheet = layer.renderNewSpriteSheet()
expect(SpriteBuilder.prototype.buildContainerFromStore.calls.count()).toBe(1)
it '*does not* recycle *containers* from previous sprite sheets when the resolutionFactor has changed', ->
treeThangType.set('renderStrategy', 'container')
sprite = new CocoSprite(treeThangType)
layer.addCocoSprite(sprite)
spyOn(SpriteBuilder.prototype, 'buildContainerFromStore').and.callThrough()
for i in _.range(2)
layer.resolutionFactor *= 1.1
sheet = layer.renderNewSpriteSheet()
expect(SpriteBuilder.prototype.buildContainerFromStore.calls.count()).toBe(2)
it 'recycles *animations* from previous sprite sheets, rather than building repeatedly from raw vector data', ->
ogreMunchkinThangType.set('renderStrategy', 'spriteSheet')
sprite = new CocoSprite(ogreMunchkinThangType)
layer.addCocoSprite(sprite)
numFrameses = []
spyOn(SpriteBuilder.prototype, 'buildMovieClip').and.callThrough()
for i in _.range(2)
sheet = layer.renderNewSpriteSheet()
numFrameses.push(sheet.getNumFrames())
# this process should not have created any new frames
expect(numFrameses[0]).toBe(numFrameses[1])
# one movie clip made for each raw animation: move (3), attack, die
expect(SpriteBuilder.prototype.buildMovieClip.calls.count()).toBe(5)
it '*does not* recycles *animations* from previous sprite sheets when the resolutionFactor has changed', ->
ogreMunchkinThangType.set('renderStrategy', 'spriteSheet')
sprite = new CocoSprite(ogreMunchkinThangType)
layer.addCocoSprite(sprite)
spyOn(SpriteBuilder.prototype, 'buildMovieClip').and.callThrough()
for i in _.range(2)
layer.resolutionFactor *= 1.1
sheet = layer.renderNewSpriteSheet()
expect(SpriteBuilder.prototype.buildMovieClip.calls.count()).toBe(10)