diff --git a/app/lib/surface/Layer.coffee b/app/lib/surface/Layer.coffee index 2afb0bf48..d640a813b 100644 --- a/app/lib/surface/Layer.coffee +++ b/app/lib/surface/Layer.coffee @@ -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 diff --git a/app/lib/surface/WebGLLayer.coffee b/app/lib/surface/WebGLLayer.coffee index a5684f450..32f5098e2 100644 --- a/app/lib/surface/WebGLLayer.coffee +++ b/app/lib/surface/WebGLLayer.coffee @@ -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,8 +179,13 @@ module.exports = class WebGLLayer extends CocoClass spriteBuilder = new SpriteBuilder(thangType, {colorConfig: colorConfig}) for containerGlobalName in _.keys(containersToRender) containerKey = @renderGroupingKey(thangType, containerGlobalName, colorConfig) - container = spriteBuilder.buildContainerFromStore(containerGlobalName) - frame = spriteSheetBuilder.addFrame(container, null, @resolutionFactor * (thangType.get('scale') or 1)) + 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) getContainersForAnimation: (thangType, animation) -> @@ -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.") diff --git a/test/app/lib/surface/WebGLLayer.spec.coffee b/test/app/lib/surface/WebGLLayer.spec.coffee index 9ec8d8a03..ec33a8e46 100644 --- a/test/app/lib/surface/WebGLLayer.spec.coffee +++ b/test/app/lib/surface/WebGLLayer.spec.coffee @@ -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) \ No newline at end of file