2014-09-19 18:46:02 -04:00
# ##
* SpriteStage ( WebGL Canvas )
* * Land texture
* * Ground - based selection / target marks , range radii
* * Walls / obstacles
* * Paths and target pieces ( and ghosts ? )
* * Normal Thangs , bots , wizards ( z - indexing based on World - determined sprite . thang . pos . z / y , mainly , instead of sprite - map - determined sprite . z , which we rename to . . . something )
* * Above - thang marks ( blood , highlight ) and health bars
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
* Stage ( Regular Canvas )
* * Camera border
* * surfaceTextLayer ( speech , names )
* * screenLayer
* * * Letterbox
* * * * Letterbox top and bottom
* * * FPS display , maybe grid axis labels , coordinate hover
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
* * Grid lines - - somewhere - - we will figure it out , do not really need it at first
# ##
2014-09-12 19:33:01 -04:00
SpriteBuilder = require ' lib/sprites/SpriteBuilder '
2014-11-28 20:49:41 -05:00
CocoClass = require ' core/CocoClass '
2014-09-19 17:56:40 -04:00
SegmentedSprite = require ' ./SegmentedSprite '
SingularSprite = require ' ./SingularSprite '
2015-10-12 19:47:48 -04:00
ThangType = require ' models/ThangType '
2014-09-16 18:36:59 -04:00
2014-09-19 17:56:40 -04:00
NEVER_RENDER_ANYTHING = false # set to true to test placeholders
2014-09-19 16:50:14 -04:00
2014-09-19 18:46:02 -04:00
module.exports = LayerAdapter = class LayerAdapter extends CocoClass
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
# Intermediary between a Surface Stage and a top-level static normal Container or hot-swapped WebGL SpriteContainer.
# It handles zooming in different ways and, if webGL, creating and assigning spriteSheets.
2014-09-16 18:36:59 -04:00
2014-09-19 18:46:02 -04:00
@TRANSFORM_SURFACE: ' surface ' # Layer moves/scales/zooms with the Surface of the World
@TRANSFORM_SURFACE_TEXT: ' surface_text ' # Layer moves with the Surface but is size-independent
2014-09-26 16:02:01 -04:00
@TRANSFORM_SCREEN: ' screen ' # Layer stays fixed to the screen
2014-09-12 19:33:01 -04:00
2014-09-19 18:46:02 -04:00
# WebGL properties
2014-09-12 19:33:01 -04:00
actionRenderState: null
needToRerender: false
toRenderBundles: null
willRender: false
2014-09-16 18:36:59 -04:00
buildAutomatically: true
buildAsync: true
2014-09-12 19:33:01 -04:00
resolutionFactor: SPRITE_RESOLUTION_FACTOR
2014-09-16 18:36:59 -04:00
numThingsLoading: 0
2014-09-28 17:00:48 -04:00
lanks: null
2014-09-16 18:36:59 -04:00
spriteSheet: null
2014-09-19 18:46:02 -04:00
container: null
2014-09-24 15:08:55 -04:00
customGraphics: null
2014-09-19 18:46:02 -04:00
subscriptions:
' camera:zoom-updated ' : ' onZoomUpdated '
constructor: (options) ->
2014-09-17 18:47:25 -04:00
super ( )
2014-09-19 18:46:02 -04:00
options ? = { }
@name = options . name ? ' Unnamed '
2014-09-24 21:42:04 -04:00
@defaultSpriteType = if @ name is ' Default ' then ' segmented ' else ' singular '
2014-09-24 15:08:55 -04:00
@customGraphics = { }
2014-09-19 18:46:02 -04:00
@layerPriority = options . layerPriority ? 0
2014-09-26 16:02:01 -04:00
@transformStyle = options . transform ? LayerAdapter . TRANSFORM_SURFACE
2014-09-19 18:46:02 -04:00
@camera = options . camera
@updateLayerOrder = _ . throttle @ updateLayerOrder , 1000 / 30 # Don't call multiple times in one frame; 30 FPS is probably good enough
@webGL = ! ! options . webGL
if @ webGL
@initializing = true
@spriteSheet = @ _renderNewSpriteSheet ( false ) # builds an empty spritesheet
@container = new createjs . SpriteContainer ( @ spriteSheet )
@actionRenderState = { }
@toRenderBundles = [ ]
2014-09-28 17:00:48 -04:00
@lanks = [ ]
2014-09-19 18:46:02 -04:00
@initializing = false
else
@container = new createjs . Container ( )
toString: -> " <Layer #{ @ layerPriority } : #{ @ name } > "
#- Layer ordering
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
updateLayerOrder: ->
2014-10-10 22:20:00 -04:00
return if @ destroyed
2014-09-19 18:46:02 -04:00
@ container . sortChildren @ layerOrderComparator
layerOrderComparator: (a, b) ->
# Optimize
alp = a . layerPriority or 0
blp = b . layerPriority or 0
return alp - blp if alp isnt blp
# TODO: remove this z stuff
az = a . z or 1000
bz = b . z or 1000
2014-09-28 17:00:48 -04:00
if aLank = a . lank
if aThang = aLank . thang
2014-09-19 18:46:02 -04:00
aPos = aThang . pos
2014-11-23 22:40:50 -05:00
if aThang . health < 0 and aThang . pos . z <= aThang . depth / 2
# Nice for not being knee deep in the dead, just not nice for ogres flying behind trees when exploded
2014-09-19 18:46:02 -04:00
- - az
2014-09-28 17:00:48 -04:00
if bLank = b . lank
if bThang = bLank . thang
2014-09-19 18:46:02 -04:00
bPos = bThang . pos
2014-11-23 19:06:28 -05:00
if bThang . health < 0 and bThang . pos . z <= bThang . depth / 2
2014-09-19 18:46:02 -04:00
- - bz
if az is bz
return 0 unless aPos and bPos
return ( bPos . y - aPos . y ) or ( bPos . x - aPos . x )
return az - bz
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
#- Zoom updating
onZoomUpdated: (e) ->
return unless e . camera is @ camera
2014-09-26 16:02:01 -04:00
if @ transformStyle in [ LayerAdapter . TRANSFORM_SURFACE , LayerAdapter . TRANSFORM_SURFACE_TEXT ]
2014-09-19 18:46:02 -04:00
change = @ container . scaleX / e . zoom
@container.scaleX = @container.scaleY = e . zoom
2014-09-26 14:07:01 -04:00
if @ webGL
@ container . scaleX *= @ camera . canvasScaleFactorX
@ container . scaleY *= @ camera . canvasScaleFactorY
2014-09-19 18:46:02 -04:00
@container.regX = e . surfaceViewport . x
@container.regY = e . surfaceViewport . y
if @ transformStyle is LayerAdapter . TRANSFORM_SURFACE_TEXT
for child in @ container . children
2014-10-21 13:59:05 -04:00
continue if child . skipScaling
2014-09-19 18:46:02 -04:00
child . scaleX *= change
child . scaleY *= change
#- Container-like child functions
addChild: (children...) ->
2014-09-24 15:08:55 -04:00
@ container . addChild children . . .
if @ transformStyle is LayerAdapter . TRANSFORM_SURFACE_TEXT
2014-09-19 18:46:02 -04:00
for child in children
2014-10-21 13:59:05 -04:00
continue if child . skipScaling
2014-09-26 18:57:24 -04:00
child . scaleX /= @ container . scaleX
child . scaleY /= @ container . scaleY
2014-09-19 18:46:02 -04:00
removeChild: (children...) ->
2014-09-24 15:08:55 -04:00
@ container . removeChild children . . .
2014-09-19 18:46:02 -04:00
# TODO: Do we actually need to scale children that were removed?
2014-09-24 15:08:55 -04:00
if @ transformStyle is LayerAdapter . TRANSFORM_SURFACE_TEXT
2014-09-19 18:46:02 -04:00
for child in children
2014-09-26 18:57:24 -04:00
child . scaleX *= @ container . scaleX
child . scaleY *= @ container . scaleY
2014-09-19 18:46:02 -04:00
#- Adding, removing children for WebGL layers.
2014-10-10 22:20:00 -04:00
2014-09-28 17:00:48 -04:00
addLank: (lank) ->
lank.options.resolutionFactor = @ resolutionFactor
lank.layer = @
@ listenTo ( lank , ' action-needs-render ' , @ onActionNeedsRender )
@ lanks . push lank
2015-12-18 16:26:47 -05:00
lank . thangType . initPrerenderedSpriteSheets ( ) unless currentView . getQueryVariable ' jitSpritesheets '
2015-10-13 19:43:56 -04:00
prerenderedSpriteSheet = lank . thangType . getPrerenderedSpriteSheet ( lank . options . colorConfig , @ defaultSpriteType )
prerenderedSpriteSheet ? . markToLoad ( )
2014-09-28 17:00:48 -04:00
@ loadThangType ( lank . thangType )
@ addDefaultActionsToRender ( lank )
@ setSpriteToLank ( lank )
2014-09-19 18:46:02 -04:00
@ updateLayerOrder ( )
2014-09-28 17:00:48 -04:00
lank . addHealthBar ( )
2014-09-19 18:46:02 -04:00
2014-09-28 17:00:48 -04:00
removeLank: (lank) ->
@ stopListening ( lank )
2014-10-03 15:06:04 -04:00
lank.layer = null
2014-09-28 17:00:48 -04:00
@ container . removeChild lank . sprite
@lanks = _ . without @ lanks , lank
2014-09-16 18:36:59 -04:00
2014-09-19 18:46:02 -04:00
#- Loading network resources dynamically
2014-10-10 22:20:00 -04:00
2014-09-16 18:36:59 -04:00
loadThangType: (thangType) ->
if not thangType . isFullyLoaded ( )
thangType . setProjection null
thangType . fetch ( ) unless thangType . loading
@ numThingsLoading ++
@ listenToOnce ( thangType , ' sync ' , @ somethingLoaded )
else if thangType . get ( ' raster ' ) and not thangType . loadedRaster
thangType . loadRasterImage ( )
@ listenToOnce ( thangType , ' raster-image-loaded ' , @ somethingLoaded )
@ numThingsLoading ++
2015-10-13 19:43:56 -04:00
else if prerenderedSpriteSheet = thangType . getPrerenderedSpriteSheetToLoad ( )
2015-10-14 17:48:43 -04:00
startedLoading = prerenderedSpriteSheet . loadImage ( )
return if not startedLoading
2015-10-13 19:43:56 -04:00
@ listenToOnce ( prerenderedSpriteSheet , ' image-loaded ' , -> @ somethingLoaded ( thangType ) )
@ numThingsLoading ++
2014-09-16 18:36:59 -04:00
somethingLoaded: (thangType) ->
@ numThingsLoading - -
@ loadThangType ( thangType ) # might need to load the raster image object
2014-09-28 17:00:48 -04:00
for lank in @ lanks
if lank . thangType is thangType
@ addDefaultActionsToRender ( lank )
2014-09-16 18:36:59 -04:00
@ renderNewSpriteSheet ( )
2014-09-19 18:46:02 -04:00
#- Adding to the list of things we need to render
2014-10-10 22:20:00 -04:00
2014-09-28 17:00:48 -04:00
onActionNeedsRender: (lank, action) ->
@ upsertActionToRender ( lank . thangType , action . name , lank . options . colorConfig )
2014-09-19 18:46:02 -04:00
2014-09-28 17:00:48 -04:00
addDefaultActionsToRender: (lank) ->
2014-09-17 18:47:25 -04:00
needToRender = false
2014-09-28 17:00:48 -04:00
if lank . thangType . get ( ' raster ' )
@ upsertActionToRender ( lank . thangType )
2014-09-12 19:33:01 -04:00
else
2014-09-28 17:00:48 -04:00
for action in _ . values ( lank . thangType . getActions ( ) )
2015-10-12 19:47:48 -04:00
continue unless _ . any ThangType . defaultActions , (prefix) -> _ . string . startsWith ( action . name , prefix )
2014-09-28 17:00:48 -04:00
@ upsertActionToRender ( lank . thangType , action . name , lank . options . colorConfig )
2014-09-16 18:36:59 -04:00
2014-09-12 19:33:01 -04:00
upsertActionToRender: (thangType, actionName, colorConfig) ->
groupKey = @ renderGroupingKey ( thangType , actionName , colorConfig )
2014-09-17 18:47:25 -04:00
return false if @ actionRenderState [ groupKey ] isnt undefined
2014-09-12 19:33:01 -04:00
@ actionRenderState [ groupKey ] = ' need-to-render '
@ toRenderBundles . push ( { thangType: thangType , actionName: actionName , colorConfig: colorConfig } )
2014-09-17 18:47:25 -04:00
return true if @ willRender or not @ buildAutomatically
2014-09-16 18:36:59 -04:00
@willRender = _ . defer => @ renderNewSpriteSheet ( )
2014-09-17 18:47:25 -04:00
return true
2014-09-24 13:55:33 -04:00
2014-09-24 15:08:55 -04:00
addCustomGraphic: (key, graphic, bounds) ->
return false if @ customGraphics [ key ]
@ customGraphics [ key ] = { graphic: graphic , bounds: new createjs . Rectangle ( bounds . . . ) }
return true if @ willRender or not @ buildAutomatically
@ _renderNewSpriteSheet ( false )
2014-09-19 18:46:02 -04:00
#- Rendering sprite sheets
2014-10-10 22:20:00 -04:00
2014-09-12 19:33:01 -04:00
renderNewSpriteSheet: ->
@willRender = false
2014-09-16 18:36:59 -04:00
return if @ numThingsLoading
@ _renderNewSpriteSheet ( )
2014-10-10 22:20:00 -04:00
2014-09-16 18:36:59 -04:00
_renderNewSpriteSheet: (async) ->
2014-10-02 20:38:50 -04:00
@ asyncBuilder . stopAsync ( ) if @ asyncBuilder
2014-10-03 13:44:02 -04:00
@asyncBuilder = null
2014-10-10 22:20:00 -04:00
2014-09-16 18:36:59 -04:00
async ? = @ buildAsync
2014-09-12 19:33:01 -04:00
builder = new createjs . SpriteSheetBuilder ( )
groups = _ . groupBy ( @ toRenderBundles , ( (bundle) -> @ renderGroupingKey ( bundle . thangType , ' ' , bundle . colorConfig ) ) , @ )
2014-09-18 14:56:49 -04:00
2014-09-19 16:50:14 -04:00
# The first frame is always the 'loading', ie placeholder, image.
placeholder = @ createPlaceholder ( )
2014-09-24 13:55:33 -04:00
dimension = @ resolutionFactor * SPRITE_PLACEHOLDER_WIDTH
2014-09-19 16:50:14 -04:00
placeholder . setBounds ( 0 , 0 , dimension , dimension )
builder . addFrame ( placeholder )
2014-10-10 22:20:00 -04:00
2014-09-24 15:08:55 -04:00
# Add custom graphics
2014-09-24 21:47:10 -04:00
extantGraphics = if @ spriteSheet ? . resolutionFactor is @ resolutionFactor then @ spriteSheet . getAnimations ( ) else [ ]
2014-09-24 15:08:55 -04:00
for key , graphic of @ customGraphics
2014-09-24 21:47:10 -04:00
if key in extantGraphics
graphic = new createjs . Sprite ( @ spriteSheet )
graphic . gotoAndStop ( key )
frame = builder . addFrame ( graphic )
else
frame = builder . addFrame ( graphic . graphic , graphic . bounds , @ resolutionFactor )
2014-09-24 15:08:55 -04:00
builder . addAnimation ( key , [ frame ] , false )
2014-10-10 22:20:00 -04:00
2014-09-24 15:08:55 -04:00
# Render ThangTypes
2014-09-19 16:50:14 -04:00
groups = { } if NEVER_RENDER_ANYTHING
2014-09-12 19:33:01 -04:00
for bundleGrouping in _ . values ( groups )
thangType = bundleGrouping [ 0 ] . thangType
colorConfig = bundleGrouping [ 0 ] . colorConfig
actionNames = ( bundle . actionName for bundle in bundleGrouping )
args = [ thangType , colorConfig , actionNames , builder ]
if thangType . get ( ' raw ' )
2014-09-24 21:42:04 -04:00
if ( thangType . get ( ' spriteType ' ) or @ defaultSpriteType ) is ' segmented '
2014-09-19 18:46:02 -04:00
@ renderSegmentedThangType ( args . . . )
2014-09-12 19:33:01 -04:00
else
2014-09-19 18:46:02 -04:00
@ renderSingularThangType ( args . . . )
2014-09-12 19:33:01 -04:00
else
2014-09-19 18:46:02 -04:00
@ renderRasterThangType ( thangType , builder )
2014-10-10 22:20:00 -04:00
2014-09-16 18:36:59 -04:00
if async
2014-10-02 20:38:50 -04:00
try
builder . buildAsync ( )
catch e
@ resolutionFactor *= 0.9
2015-12-18 16:26:47 -05:00
#console.log " Rerendering sprite sheet didn't fit, going down to resolutionFactor", @resolutionFactor, "async", async
2014-10-02 20:38:50 -04:00
return @ _renderNewSpriteSheet ( async )
2014-09-16 18:36:59 -04:00
builder . on ' complete ' , @ onBuildSpriteSheetComplete , @ , true , builder
2014-10-02 20:38:50 -04:00
@asyncBuilder = builder
2014-09-16 18:36:59 -04:00
else
2014-09-17 18:47:25 -04:00
sheet = builder . build ( )
2014-09-24 15:08:55 -04:00
@ onBuildSpriteSheetComplete ( { async : async } , builder )
2014-09-17 18:47:25 -04:00
return sheet
2014-10-10 22:20:00 -04:00
2014-09-16 18:36:59 -04:00
onBuildSpriteSheetComplete: (e, builder) ->
2014-10-03 13:44:02 -04:00
return if @ initializing or @ destroyed
2014-10-02 20:38:50 -04:00
@asyncBuilder = null
2014-10-10 22:20:00 -04:00
2014-09-17 20:08:24 -04:00
if builder . spriteSheet . _images . length > 1
2014-10-02 20:38:50 -04:00
total = 0
# get a rough estimate of how much smaller the spritesheet needs to be
for image , index in builder . spriteSheet . _images
total += image . height / builder . maxHeight
2015-12-18 16:26:47 -05:00
@ resolutionFactor /= ( Math . max ( 1.25 , Math . sqrt ( total ) ) )
#console.log "#{@name} rerendering new sprite sheet with resolutionFactor", @resolutionFactor, "async", e.async
2014-09-24 15:08:55 -04:00
@ _renderNewSpriteSheet ( e . async )
2014-09-17 20:08:24 -04:00
return
2014-10-10 22:20:00 -04:00
2014-09-17 18:47:25 -04:00
@spriteSheet = builder . spriteSheet
2014-09-18 17:36:05 -04:00
@spriteSheet.resolutionFactor = @ resolutionFactor
2014-10-10 22:20:00 -04:00
oldLayer = @ container
2014-09-19 18:46:02 -04:00
@container = new createjs . SpriteContainer ( @ spriteSheet )
2014-09-28 17:00:48 -04:00
for lank in @ lanks
console . log ' zombie sprite found on layer ' , @ name if lank . destroyed
continue if lank . destroyed
@ setSpriteToLank ( lank )
2014-09-17 18:47:25 -04:00
for prop in [ ' scaleX ' , ' scaleY ' , ' regX ' , ' regY ' ]
2014-09-19 18:46:02 -04:00
@ container [ prop ] = oldLayer [ prop ]
2014-09-17 18:47:25 -04:00
if parent = oldLayer . parent
index = parent . getChildIndex ( oldLayer )
parent . removeChildAt ( index )
2014-09-19 18:46:02 -04:00
parent . addChildAt ( @ container , index )
@ camera ? . updateZoom ( true )
@ updateLayerOrder ( )
2014-09-28 17:00:48 -04:00
for lank in @ lanks
lank.options.resolutionFactor = @ resolutionFactor
lank . updateScale ( )
lank . updateRotation ( )
2014-09-17 18:47:25 -04:00
@ trigger ' new-spritesheet '
2014-10-10 22:20:00 -04:00
2014-09-28 17:00:48 -04:00
resetSpriteSheet: ->
@ removeLank ( lank ) for lank in @ lanks . slice ( 0 )
@toRenderBundles = [ ]
@actionRenderState = { }
@initializing = true
@spriteSheet = @ _renderNewSpriteSheet ( false ) # builds an empty spritesheet
@initializing = false
2014-09-17 18:47:25 -04:00
2014-09-19 18:46:02 -04:00
#- Placeholder
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
createPlaceholder: ->
2014-10-10 22:20:00 -04:00
# TODO: Experiment with this. Perhaps have rectangles if default layer is obstacle or floor,
2014-09-19 18:46:02 -04:00
# and different colors for different layers.
g = new createjs . Graphics ( )
g . setStrokeStyle ( 5 )
2014-09-26 19:15:44 -04:00
color = {
' Land ' : [ 0 , 50 , 0 ]
' Ground ' : [ 230 , 230 , 230 ]
' Obstacle ' : [ 20 , 70 , 20 ]
' Path ' : [ 200 , 100 , 200 ]
' Default ' : [ 64 , 64 , 64 ]
' Floating ' : [ 100 , 100 , 200 ]
} [ @ name ] or [ 0 , 0 , 0 ]
g . beginStroke ( createjs . Graphics . getRGB ( color . . . ) )
color . push 0.7
g . beginFill ( createjs . Graphics . getRGB ( color . . . ) )
width = @ resolutionFactor * SPRITE_PLACEHOLDER_WIDTH
bounds = [ 0 , 0 , width , width ]
if @ name in [ ' Default ' , ' Ground ' , ' Floating ' , ' Path ' ]
g . drawEllipse ( bounds . . . )
else
g . drawRect ( bounds . . . )
2014-09-19 18:46:02 -04:00
new createjs . Shape ( g )
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
#- Rendering containers for segmented thang types
renderSegmentedThangType: (thangType, colorConfig, actionNames, spriteSheetBuilder) ->
2015-10-14 17:33:26 -04:00
prerenderedSpriteSheet = thangType . getPrerenderedSpriteSheet ( colorConfig , ' segmented ' )
2015-10-14 17:48:43 -04:00
if prerenderedSpriteSheet and not prerenderedSpriteSheet . loadedImage
return
2016-08-22 14:45:37 -04:00
else if prerenderedSpriteSheet
animations = prerenderedSpriteSheet . spriteSheet . _animations
renderedActions = _ . zipObject ( animations , _ . times ( animations . length , -> true ) )
2015-10-12 19:47:48 -04:00
containersToRender = thangType . getContainersForActions ( actionNames )
2015-12-18 16:26:47 -05:00
#console.log 'render segmented', thangType.get('name'), actionNames, colorConfig, 'because we do not have prerendered sprite sheet?', prerenderedSpriteSheet
2014-09-12 19:33:01 -04:00
spriteBuilder = new SpriteBuilder ( thangType , { colorConfig: colorConfig } )
2015-10-12 19:47:48 -04:00
for containerGlobalName in containersToRender
2014-09-12 19:33:01 -04:00
containerKey = @ renderGroupingKey ( thangType , containerGlobalName , colorConfig )
2014-09-18 17:36:05 -04:00
if @ spriteSheet ? . resolutionFactor is @ resolutionFactor and containerKey in @ spriteSheet . getAnimations ( )
container = new createjs . Sprite ( @ spriteSheet )
container . gotoAndStop ( containerKey )
frame = spriteSheetBuilder . addFrame ( container )
2016-08-22 14:45:37 -04:00
else if prerenderedSpriteSheet and renderedActions [ containerGlobalName ]
2015-10-14 17:33:26 -04:00
container = new createjs . Sprite ( prerenderedSpriteSheet . spriteSheet )
container . gotoAndStop ( containerGlobalName )
scale = @ resolutionFactor / ( prerenderedSpriteSheet . get ( ' resolutionFactor ' ) or 1 )
frame = spriteSheetBuilder . addFrame ( container , null , scale )
2014-09-18 17:36:05 -04:00
else
container = spriteBuilder . buildContainerFromStore ( containerGlobalName )
frame = spriteSheetBuilder . addFrame ( container , null , @ resolutionFactor * ( thangType . get ( ' scale ' ) or 1 ) )
2014-09-12 19:33:01 -04:00
spriteSheetBuilder . addAnimation ( containerKey , [ frame ] , false )
2014-09-19 18:46:02 -04:00
#- Rendering sprite sheets for singular thang types
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
renderSingularThangType: (thangType, colorConfig, actionNames, spriteSheetBuilder) ->
2015-10-14 17:33:26 -04:00
prerenderedSpriteSheet = thangType . getPrerenderedSpriteSheet ( colorConfig , ' singular ' )
prerenderedFramesMap = { }
if prerenderedSpriteSheet
2015-10-14 17:48:43 -04:00
if not prerenderedSpriteSheet . loadedImage
return
2015-10-14 17:33:26 -04:00
scale = @ resolutionFactor / ( prerenderedSpriteSheet . get ( ' resolutionFactor ' ) or 1 )
for frame , i in prerenderedSpriteSheet . spriteSheet . _frames
sprite = new createjs . Sprite ( prerenderedSpriteSheet . spriteSheet )
sprite . gotoAndStop ( i )
prerenderedFramesMap [ i ] = spriteSheetBuilder . addFrame ( sprite , null , scale )
2015-12-18 16:26:47 -05:00
#else
# console.log ' Rerendering singular thang type', thangType.get('name'), thangType.get('spriteType'), colorConfig, actionNames
2015-10-14 17:33:26 -04:00
2014-09-12 19:33:01 -04:00
actionObjects = _ . values ( thangType . getActions ( ) )
animationActions = [ ]
for a in actionObjects
continue unless a . animation
continue unless a . name in actionNames
animationActions . push ( a )
2014-10-10 22:20:00 -04:00
2014-09-12 19:33:01 -04:00
spriteBuilder = new SpriteBuilder ( thangType , { colorConfig: colorConfig } )
2014-10-10 22:20:00 -04:00
2014-09-12 19:33:01 -04:00
animationGroups = _ . groupBy animationActions , (action) -> action . animation
for animationName , actions of animationGroups
renderAll = _ . any actions , (action) -> action . frames is undefined
scale = actions [ 0 ] . scale or thangType . get ( ' scale ' ) or 1
2014-10-10 22:20:00 -04:00
2014-09-18 17:36:05 -04:00
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 )
2015-10-14 17:33:26 -04:00
next = thangType . nextForAction ( action )
2014-09-18 17:36:05 -04:00
spriteSheetBuilder . addAnimation ( key , frames , next )
continue
2014-10-10 22:20:00 -04:00
2015-10-14 17:33:26 -04:00
if prerenderedSpriteSheet
for action in actions
name = @ renderGroupingKey ( thangType , action . name , colorConfig )
prerenderedFrames = prerenderedSpriteSheet . get ( ' animations ' ) ? [ action . name ] ? . frames
continue if not prerenderedFrames
frames = ( prerenderedFramesMap [ frame ] for frame in prerenderedFrames )
next = thangType . nextForAction ( action )
spriteSheetBuilder . addAnimation ( name , frames , next )
continue
2014-09-12 19:33:01 -04:00
mc = spriteBuilder . buildMovieClip ( animationName , null , null , null , { ' temp ' : 0 } )
2014-10-10 22:20:00 -04:00
2014-09-12 19:33:01 -04:00
if renderAll
res = spriteSheetBuilder . addMovieClip ( mc , null , scale * @ resolutionFactor )
frames = spriteSheetBuilder . _animations [ ' temp ' ] . frames
framesMap = _ . zipObject _ . range ( frames . length ) , frames
else
framesMap = { }
framesToRender = _ . uniq ( _ . flatten ( ( a . frames . split ( ' , ' ) for a in actions ) ) )
for frame in framesToRender
frame = parseInt ( frame )
f = _ . bind ( mc . gotoAndStop , mc , frame )
framesMap [ frame ] = spriteSheetBuilder . addFrame ( mc , null , scale * @ resolutionFactor , f )
2014-10-10 22:20:00 -04:00
2014-09-12 19:33:01 -04:00
for action in actions
name = @ renderGroupingKey ( thangType , action . name , colorConfig )
2014-10-10 22:20:00 -04:00
2014-09-12 19:33:01 -04:00
if action . frames
frames = ( framesMap [ parseInt ( frame ) ] for frame in action . frames . split ( ' , ' ) )
else
2014-10-03 12:51:07 -04:00
frames = _ . sortBy ( _ . values ( framesMap ) )
2015-10-14 17:33:26 -04:00
next = thangType . nextForAction ( action )
2014-10-10 22:20:00 -04:00
spriteSheetBuilder . addAnimation ( name , frames , next )
2014-09-12 19:33:01 -04:00
containerActions = [ ]
for a in actionObjects
continue unless a . container
continue unless a . name in actionNames
containerActions . push ( a )
2014-10-10 22:20:00 -04:00
2014-09-12 19:33:01 -04:00
containerGroups = _ . groupBy containerActions , (action) -> action . container
for containerName , actions of containerGroups
2015-10-14 17:33:26 -04:00
if prerenderedSpriteSheet
for action in actions
name = @ renderGroupingKey ( thangType , action . name , colorConfig )
prerenderedFrames = prerenderedSpriteSheet . get ( ' animations ' ) ? [ action . name ] ? . frames
continue if not prerenderedFrames
frame = prerenderedFramesMap [ prerenderedFrames [ 0 ] ]
spriteSheetBuilder . addAnimation ( name , [ frame ] , false )
continue
2014-09-12 19:33:01 -04:00
container = spriteBuilder . buildContainerFromStore ( containerName )
scale = actions [ 0 ] . scale or thangType . get ( ' scale ' ) or 1
frame = spriteSheetBuilder . addFrame ( container , null , scale * @ resolutionFactor )
for action in actions
name = @ renderGroupingKey ( thangType , action . name , colorConfig )
2014-10-10 22:20:00 -04:00
spriteSheetBuilder . addAnimation ( name , [ frame ] , false )
2014-09-19 18:46:02 -04:00
#- Rendering frames for raster thang types
2014-10-10 22:20:00 -04:00
2014-09-19 18:46:02 -04:00
renderRasterThangType: (thangType, spriteSheetBuilder) ->
2014-09-12 19:33:01 -04:00
unless thangType . rasterImage
2014-09-19 17:59:29 -04:00
console . error ( " Cannot render the LayerAdapter SpriteSheet until the raster image for < #{ thangType . get ( ' name ' ) } > is loaded. " )
2014-10-10 22:20:00 -04:00
2015-12-04 18:50:07 -05:00
# hack for IE9, otherwise width/height are not set
$img = $ ( thangType . rasterImage [ 0 ] )
$ ( ' body ' ) . append ( $img )
2014-09-12 19:33:01 -04:00
bm = new createjs . Bitmap ( thangType . rasterImage [ 0 ] )
scale = thangType . get ( ' scale ' ) or 1
frame = spriteSheetBuilder . addFrame ( bm , null , scale )
2014-09-16 18:36:59 -04:00
spriteSheetBuilder . addAnimation ( @ renderGroupingKey ( thangType ) , [ frame ] , false )
2015-12-04 18:50:07 -05:00
$img . remove ( )
2014-10-10 22:20:00 -04:00
2014-09-28 17:00:48 -04:00
#- Distributing new Segmented/Singular/RasterSprites to Lanks
2014-09-16 18:36:59 -04:00
2014-09-28 17:00:48 -04:00
setSpriteToLank: (lank) ->
if not lank . thangType . isFullyLoaded ( )
2014-09-16 18:36:59 -04:00
# just give a placeholder
sprite = new createjs . Sprite ( @ spriteSheet )
2014-09-26 15:17:46 -04:00
sprite . gotoAndStop ( 0 )
2014-09-25 13:47:53 -04:00
sprite.placeholder = true
2014-09-26 15:17:46 -04:00
sprite.regX = @ resolutionFactor * SPRITE_PLACEHOLDER_WIDTH / 2
sprite.regY = @ resolutionFactor * SPRITE_PLACEHOLDER_WIDTH
sprite.baseScaleX = sprite.baseScaleY = sprite.scaleX = sprite.scaleY = 10 / ( @ resolutionFactor * SPRITE_PLACEHOLDER_WIDTH )
2014-10-10 22:20:00 -04:00
2014-09-28 17:00:48 -04:00
else if lank . thangType . get ( ' raster ' )
2014-09-16 18:36:59 -04:00
sprite = new createjs . Sprite ( @ spriteSheet )
2014-09-28 17:00:48 -04:00
scale = lank . thangType . get ( ' scale ' ) or 1
reg = lank . getOffset ' registration '
2014-09-26 14:33:07 -04:00
sprite.regX = - reg . x * scale
sprite.regY = - reg . y * scale
2014-09-28 17:00:48 -04:00
sprite . gotoAndStop ( @ renderGroupingKey ( lank . thangType ) )
2014-09-25 16:12:47 -04:00
sprite.baseScaleX = sprite.baseScaleY = 1
2014-10-10 22:20:00 -04:00
2014-09-16 18:36:59 -04:00
else
2014-09-28 17:00:48 -04:00
SpriteClass = if ( lank . thangType . get ( ' spriteType ' ) or @ defaultSpriteType ) is ' segmented ' then SegmentedSprite else SingularSprite
prefix = @ renderGroupingKey ( lank . thangType , null , lank . options . colorConfig ) + ' . '
sprite = new SpriteClass ( @ spriteSheet , lank . thangType , prefix , @ resolutionFactor )
2014-09-16 18:36:59 -04:00
2014-09-28 17:00:48 -04:00
sprite.lank = lank
2014-09-24 19:53:38 -04:00
sprite.camera = @ camera
2014-09-28 17:00:48 -04:00
sprite.layerPriority = lank . thang ? . layerPriority ? lank . thangType . get ' layerPriority '
sprite.name = lank . thang ? . spriteName or lank . thangType . get ' name '
lank . setSprite ( sprite )
lank . update ( true )
2014-09-19 18:46:02 -04:00
@ container . addChild ( sprite )
2014-12-20 16:39:40 -05:00
lank . updateScale true if lank . thangType . get ' matchWorldDimensions ' # Otherwise it's at the wrong scale for some reason.
2014-09-19 18:46:02 -04:00
renderGroupingKey: (thangType, grouping, colorConfig) ->
key = thangType . get ( ' slug ' )
2014-10-18 21:18:12 -04:00
for colorKey , colorValue of colorConfig ? { }
key += " ( #{ colorKey } : #{ colorValue . hue } , #{ colorValue . saturation } , #{ colorValue . lightness } ) "
2014-09-19 18:46:02 -04:00
key += ' . ' + grouping if grouping
key
destroy: ->
child . destroy ? ( ) for child in @ container . children
2014-10-03 13:44:02 -04:00
@ asyncBuilder . stopAsync ( ) if @ asyncBuilder
2014-10-10 22:20:00 -04:00
super ( )