Extended Filmloop

Here is another script trying to solve the problems which arise when one is using a #filmloop. How to pause a #filmloop? How to affect the speed of its performance? How to make a #filmloop to be played (for instance) in 1.5 seconds? The answers of these and many other questions are here!

Show code

-------------------------------------------------
-- PROPERTIES
-------------------------------------------------
on ___________________________PROPERTIES
end

property _id
property _cnt
property _blend
property _tempo
property _frame
property _sprite
property _paused
property _markers
property _reversed
property _callbacks
property _maxframes
property _lastframe
property _framecount
property _blendLevels
property _channelcount
property _useTime
property _time
property _delay
property _lastMS


-------------------------------------------------
-- SYSTEM EVENT HANDLERS
-------------------------------------------------
on ___________________________SYSTEM_EVENT_HANDLERS
end
on isOkToAttach( me, aSpriteType, aSpriteNum )
  ok = FALSE  
  if ( aSpriteType = #graphic ) then
    if ( [ #filmLoop, #movie ].getPos( sprite( aSpriteNum ).member.type ) > 0 ) then
      ok = TRUE
    end if
  end if  
  return( ok )  
end isOkToAttach

on getPropertyDescriptionList( me )
  pdl = propList()
  pdl.addProp( #_id,       [ #format:#symbol,  #default:symbol( "loop" && _player.currentSpriteNum ), #comment:"Loop ID:" ] )
  pdl.addProp( #_reversed, [ #format:#boolean, #default:FALSE, #comment:"Reversed?" ] )
  pdl.addProp( #_tempo,    [ #format:#integer, #default:100,  #range:[#min:10, #max:100], #comment:"Speed (100 = the movie tempo)" ] )
  pdl.addProp( #_useTime,  [ #format:#boolean, #default:TRUE, #comment:"Use Time?" ] )
  pdl.addProp( #_time,     [ #format:#integer, #default:1000, #comment:"Time to play (in milliseconds):" ] )
  pdl.addProp( #_paused,   [ #format:#boolean, #default:TRUE, #comment:"Paused on start?" ] )
  pdl.addProp( #_blend,    [ #format:#integer, #default:255, #range:[#min:0, #max:255], #comment:"Blend Level:" ])
  return pdl
end getPropertyDescriptionList

on beginSprite( me )
  _sprite = sprite( me.spritenum )
  m = _sprite.member
  _cnt = 0
  _frame = 1
  _maxframes = 1
  _lastframe = 0
  _blendLevels = list()
  _markers = propList()
  _callbacks = propList()
  tell _sprite
    _framecount = _movie.lastFrame
    _channelcount = _movie.lastChannel
    repeat with i = 1 to _channelcount
      _blendLevels.append( sprite(i).blendLevel )
    end repeat
  end tell
  me.speed( _tempo )
  me.blendLevel( _blend )
  if( _movie.actorList.getPos( me ) = 0 ) then
    _movie.actorList.append( me )
  end if
  _useTime = ( _useTime = TRUE )
  _time = integer( max( 10, _time ) )
  _delay = integer( _time / float( _framecount ) )
  _lastMS = _system.milliseconds
  sendAllSprites( #loopReady, [ #sender:me, #args:[ #id:_id, #framecount:_framecount, #currentframe:_frame, #reversed:_reversed, #paused:_paused ] ] )
end beginSprite

on endSprite( me )
  if( _movie.actorList.getPos( me ) > 0 ) then
    _movie.actorList.deleteOne( me )
  end if
end endSprite

on stepFrame( me )
  if( _useTime ) then
    me._calculateTime()
  else
    me._calculateCurrentFrame()
  end if
  if( not _paused ) then
    if( not voidP( _callbacks[ #update ] ) ) then
      call( _callbacks.update.handler, _callbacks.update.object, [ #id:_id, #frame:_frame ] )
    end if
    if( not voidP( _callbacks[ #marker ] ) ) then
      pos = _markers.getPos( _frame )
      if( pos > 0 ) then
        if( _frame <>_lastframe ) then
          call( _callbacks.marker.handler, _callbacks.marker.object, [ #id:_id, #marker:_markers.getPropAt( pos ) ] )
          _lastframe = _frame
        end if
      else
        _lastframe = 0
      end if
    end if
  end if
  tell _sprite
    repeat with i = 1 to _channelcount
      sprite( i ).blendLevel = integer( _blendLevels[i] * ( _blend/ 256.0 ) ) 
    end repeat
    _movie.go( _frame )
  end tell 
end stepFrame


-------------------------------------------------
-- PUBLIC METHODS
-------------------------------------------------
on ___________________________PUBLIC_METHODS
end

on play( me )
  _paused = FALSE
end play

on stop( me )
  _paused = TRUE
end stop

on go( me, val )
  if( ilk( val ) <> #string and ilk( val ) <> #integer ) then me._debug( "This method receives integers and strings only." )
  if( ilk( val ) = #string ) then
    if ( voidP( _markers[ val ] ) ) then
      me._debug( "Bad marker name." )
    else
      _frame = _markers[ val ]
    end if
  end if
  if( ilk( val ) = #integer ) then
    if( val < 1 or val > _framecount ) then
      me._debug( "Bad frame number." )
    else
      _frame = val
    end if
  end if
  if( not voidP( _callbacks[ #update ] ) ) then
    call( _callbacks.update.handler, _callbacks.update.object, [ #id:_id, #frame:_frame ] )
  end if
end go

on goToAndStop( me, val )
  me.go( val )
  _paused = TRUE
end goToAndStop 

on addMarker( me, aname, aframe )
  f = 0
  if( ilk( aname ) <> #string ) then f = me._debug( "Bad marker name." )
  if( ilk( aframe ) <> #integer or ( aframe < 1 or aframe > _framecount ) ) then f = me._debug( "Bad frame number." )
  if( not voidP( _markers[ aname ] ) ) then f = me._debug( "This marker name alredy exists." )
  if( _markers.getPos( aframe ) > 0 ) then f = me._debug( "A marker already exists on this frame." )
  if( f = 0 ) then _markers.addProp( aname, aframe )
end addMarker

on removeMarker( me, aname )
  _markers.deleteProp( aname )
end removeMarker

on clearMarkers( me )
  _markers.deleteAll()
end clearMarkers

on addCallback( me, event, ahandler, aobject )
  if( [#update, #marker].getPos( event ) = 0 ) then me._debug( "Bad event name." )
  if( ilk( ahandler ) <> #symbol ) then me._debug( "Bad handler name." )
  if( ( ilk( aobject ) <> #instance and ilk( aobject ) <> #script ) or aobject.handlers().getPos( ahandler ) = 0 ) then me._debug( "Bad object." )
  _callbacks[ event ] = [ #handler:ahandler, #object:aobject ]
end addCallback

on removeCallback( me, event )
  if( [#update, #marker].getPos( event ) = 0 ) then me._debug( "Bad event name." )
  _callbacks.deleteProp( event )
end removeCallback

on clearCallbacks( me )
  _callbacks.deleteAll()
end clearCallbacks


-------------------------------------------------
-- GETTERS / SETTERS
-------------------------------------------------
on ___________________________GETTERS_SETTERS
end

on speed( me, val )
  if voidP( val ) then return 100 / float( _maxframes )
  val = max( 1, min( val, 100 ) )
  _maxframes = integer( 100 / float( val ) )
  _cnt = 0
end speed

on time( me, val )
  if voidP( val ) then return _time
  _time = val
  _delay = integer( _time / float( _framecount ) )
  _lastMS = _system.milliseconds
end time

on paused( me, val )
  if voidP( val ) then return _paused
  _paused = ( val = true )
end paused

on progress( me, val )
  if voidP( val ) then return _frame / float( _framecount )
  _frame = integer( _framecount * val )
end progress

on blendLevel( me, val )
  if voidP( val ) then return  _blend
  _blend = max( 0, min( val, 255 ) )
end blendLevel

on loop( me )
  return _sprite.member.loop
end loop

on crop( me )
  return  _sprite.member.crop
end crop

on center( me, val )
  return  _sprite.member.center
end center

on reversed( me, val )
  if voidP( val ) then return _reversed
  _reversed = ( val = TRUE )
end setRate


-------------------------------------------------
-- PRIVATE METHODS
-------------------------------------------------
on ___________________________PRIVATE_METHODS
end
on _calculateTime( me )
  if( _paused ) then return
  if( _system.milliseconds >= _lastMS + _delay ) then
    if( not _reversed ) then
      if( _frame < _framecount ) then
        _frame = _frame + 1
      else
        _frame = 1
      end if 
    else
      if( _frame > 1 ) then
        _frame = _frame - 1
      else
        _frame = _framecount
      end if
    end if
    _lastMS = _system.milliseconds
  end if
end _calculateTime

on _calculateCurrentFrame( me )
  if( _paused ) then return
  _cnt = _cnt + 1
  if( _cnt = _maxframes ) then
    if( not _reversed ) then
      if( _frame < _framecount ) then
        _frame = _frame + 1
      else
        _frame = 1
      end if 
    else
      if( _frame > 1 ) then
        _frame = _frame - 1
      else
        _frame = _framecount
      end if
    end if
    _cnt = 0
  end if
end _calculateCurrentFrame

on _debug( me, msg )
  if( _system.environmentPropList.runMode contains "author" ) then
    _player.alert( msg )
  else
    trace( msg )
  end if
  return 1
end _debug

on ___________________________END_XLOOP
end

An example of adding a marker and a callback handler:

Show code

property loopA
property loopB

on loopReady( me, event )
case( event.args.id ) of
#loop1:
loopA = event.sender
loopA.addMarker( "end", 12 )
loopA.addCallback( #update, #updateSlider, me )
loopA.addCallback( #marker, #stopOnEnd, me )
#loop2:
loopB = event.sender
loopB.addCallback( #update, #updateSlider, me )
end case
end loopReady

on stopOnEnd( me, args )
loopA.stop()
loopA.removeCallback( #marker )
sprite("INSTRUCTION").visible = TRUE
end stopOnEnd

Below is a demonstration of how the script works:

Extended Filmloop demo
 
Comments

No comments yet.

Leave a Reply