/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {
    import org.mangui.hls.constant.HLSAltAudioSwitchMode;
    import org.mangui.hls.constant.HLSMaxLevelCappingMode;
    import org.mangui.hls.constant.HLSSeekMode;

    public final class HLSSettings extends Object {

        /**
         * autoStartLoad
         *
         * if set to true,
         *      start level playlist and first fragments will be loaded automatically,
         *      after triggering of HlsEvent.MANIFEST_PARSED event
         * if set to false,
         *      an explicit API call (hls.startLoad()) will be needed
         *      to start quality level/fragment loading.
         *
         * Default is true
         */

        public static var autoStartLoad : Boolean = true;

        /**
         * capLevelToStage
         *
         * Limit levels usable in auto-quality by the stage dimensions (width and height).
         *      true - level width and height (defined in m3u8 playlist) will be compared with the player width and height (stage.stageWidth and stage.stageHeight).
         *             Max level will be set depending on the maxLevelCappingMode option.
         *      false - levels will not be limited. All available levels could be used in auto-quality mode taking only bandwidth into consideration.
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelToStage : Boolean = true;

        /**
         * maxLevelCappingMode
         *
         * Defines the max level capping mode to the one available in HLSMaxLevelCappingMode
         *      HLSMaxLevelCappingMode.DOWNSCALE - max capped level should be the one with the dimensions equal or greater than the stage dimensions (so the video will be downscaled)
         *      HLSMaxLevelCappingMode.UPSCALE - max capped level should be the one with the dimensions equal or lower than the stage dimensions (so the video will be upscaled)
         *
         * Default is HLSMaxLevelCappingMode.DOWNSCALE
         */
        public static var maxLevelCappingMode : String = HLSMaxLevelCappingMode.UPSCALE;

        // // // // // // /////////////////////////////////
        //
        // org.mangui.hls.stream.HLSNetStream
        //
        // // // // // // /////////////////////////////////
        /**
         * minBufferLength
         *
         * Defines minimum buffer length in seconds before playback can start, after seeking or buffer stalling.
         *
         * Default is -1 = auto
         */
        public static var minBufferLength : Number = -1;

        /**
         * minBufferLengthCapping
         *
         * Defines minimum buffer length capping value (max value) if minBufferLength is set to -1
         *
         * Default is -1 = no capping
         */
        public static var minBufferLengthCapping : Number = -1;

        /**
         * maxBufferLength
         *
         * Defines maximum buffer length in seconds.
         * (0 means infinite buffering)
         *
         * Default is 120
         */
        public static var maxBufferLength : Number = 120;

        /**
         * maxBackBufferLength
         *
         * Defines maximum back buffer length in seconds.
         * (0 means infinite back buffering)
         *
         * Default is 30
         */
        public static var maxBackBufferLength : Number = 30;

        /**
         * lowBufferLength
         *
         * Defines low buffer length in seconds.
         * When crossing down this threshold, HLS will switch to buffering state.
         *
         * Default is 3
         */
        public static var lowBufferLength : Number = 3;

        /**
         * mediaTimeUpdatePeriod
         *
         * time update period in ms
         * period at which HLSEvent.MEDIA_TIME will be triggered
         * Default is 100 ms
         */
        public static var mediaTimePeriod : int = 100;

        /**
         * fpsDroppedMonitoringPeriod
         *
         * dropped FPS Monitor Period in ms
         * period at which nb dropped FPS will be checked
         * Default is 5000 ms
         */
        public static var fpsDroppedMonitoringPeriod : int = 5000;

        /**
         * fpsDroppedMonitoringThreshold
         *
         * dropped FPS Threshold
         * every fpsDroppedMonitoringPeriod, dropped FPS will be compared to displayed FPS.
         * if during that period, ratio of (dropped FPS/displayed FPS) is greater or equal
         * than fpsDroppedMonitoringThreshold, HLSEvent.FPS_DROP event will be fired
         * Default is 0.2 (20%)
         */
        public static var fpsDroppedMonitoringThreshold : Number = 0.2;

		/**
		 * If the dropped FPS threshold is reached, should we nudge the playhead position
		 * forward slightly to try to kick start playback?
		 *
		 * Default is false
		 */
		public static var fpsDroppedNudgeEnabled : Boolean = false;

        /**
         * capLevelonFPSDrop
         *
         * Limit levels usable in auto-quality when FPS drop is detected
         * i.e. if frame drop is detected on level 5, auto level will be capped to level 4 a
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelonFPSDrop : Boolean = false;

        /**
         * smoothAutoSwitchonFPSDrop
         *
         * force a smooth level switch Limit when FPS drop is detected in auto-quality
         * i.e. if frame drop is detected on level 5, it will trigger an auto quality level switch
         * to level 4 for next fragment
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is active only if capLevelonFPSDrop==true
         *
         * Default is true
         */
        public static var smoothAutoSwitchonFPSDrop : Boolean = true;

        /**
         * switchDownOnLevelError
         *
         * if level loading fails, and if in auto mode, and we are not on lowest level
         * don't report Level loading error straight-away, try to switch down first
         *      true -  enabled
         *      false - disabled
         *
         * Default is true
         */
        public static var switchDownOnLevelError : Boolean = true;

        /**
         * seekMode
         *
         * Defines seek mode to one form available in HLSSeekMode class:
         *      HLSSeekMode.ACCURATE_SEEK - accurate seeking to exact requested position
         *      HLSSeekMode.KEYFRAME_SEEK - key-frame based seeking (seek to nearest key frame before requested seek position)
         *
         * Default is HLSSeekMode.KEYFRAME_SEEK
         */
        public static var seekMode : String = HLSSeekMode.KEYFRAME_SEEK;

        /**
         * keyLoadMaxRetry
         *
         * Max nb of retries for Key Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var keyLoadMaxRetry : int = 3;

        /**
         * keyLoadMaxRetryTimeout
         *
         * Maximum key retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on key request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until keyLoadMaxRetryTimeout is reached.
         *
         * Default is 64000.
         */
        public static var keyLoadMaxRetryTimeout : Number = 64000;

        /**
         * fragmentLoadMaxRetry
         *
         * Max number of retries for Fragment Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var fragmentLoadMaxRetry : int = 3;

        /**
         * fragmentLoadMaxRetryTimeout
         *
         * Maximum Fragment retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until fragmentLoadMaxRetryTimeout is reached.
         *
         * Default is 4000
         */
        public static var fragmentLoadMaxRetryTimeout : Number = 4000;

        /**
         * fragmentLoadSkipAfterMaxRetry
         *
         * control behaviour in case fragment load still fails after max retry timeout
         * if set to true, fragment will be skipped and next one will be loaded.
         * If set to false, an I/O Error will be raised.
         *
         * Default is true.
         */
        public static var fragmentLoadSkipAfterMaxRetry : Boolean = true;

        /**
         * maxSkippedFragments
         *
         * Maximum count of skipped fragments in a row before an I/O Error will be raised.
         *      0 - no skip (same as fragmentLoadSkipAfterMaxRetry = false)
         *      -1 - no limit for skipping, skip till the end of the playlist
         *
         * Default is -1.
         */
        public static var maxSkippedFragments : int = -1;

        /**
         * flushLiveURLCache
         *
         * If set to true, live playlist will be flushed from URL cache before reloading
         * (this is to workaround some cache issues with some combination of Flash Player / IE version)
         *
         * Default is false
         */
        public static var flushLiveURLCache : Boolean = false;

        /**
         * initialLiveManifestSize
         *
         * Number of segments needed to start playback of Live stream.
         *
         * Default is 2
         */
        public static var initialLiveManifestSize : uint = 2;

		/**
		 * liveStopLoadingOnPause
		 *
		 * Should live streams stop loading when paused?
		 *
		 * Default is true
		 */
		public static var liveStopLoadingOnPause : Boolean = true;

        /**
         * manifestLoadMaxRetry
         *
         * max nb of retries for Manifest Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         */
        public static var manifestLoadMaxRetry : int = 3;

        /**
         * manifestLoadMaxRetryTimeout
         *
         * Maximum Manifest retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until manifestLoadMaxRetryTimeout is reached.
         *
         * Default is 64000
         */
        public static var manifestLoadMaxRetryTimeout : Number = 64000;

        /**
         * manifestRedundantLoadmaxRetry
		 *
         * max nb of looping over the redundant streams.
         *   >0  means looping over the stream array 2 or more times
         *    0  means looping exactly once (no retries) - default behaviour
         *   -1  means infinite retry
         */
         public static var manifestRedundantLoadmaxRetry : int = 3;

        /**
         * startFromBitrate
         *
         * If greater than 0, specifies the preferred bitrate.
         * If -1, and startFromLevel is not specified, automatic start level selection will be used.
         * This parameter, if set, will take priority over startFromLevel.
         *
         * Default is -1
         */
        public static var startFromBitrate : Number = -1;

        /**
         * startFromLevel
         *
         * start level :
         *  from 0 to 1 : indicates the "normalized" preferred level. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, playback will start from level matching download bandwidth (determined from download of first segment)
         * -2 : playback will start from the first level appearing in Manifest (not sorted by bitrate)
         *
         * Default is -1
         */
        public static var startFromLevel : Number = -1;

        /**
         * autoStartMaxDuration
         *
         * max fragment loading duration in automatic start level selection mode (in ms)
         * -1 : max duration not capped
         * other : max duration is capped to avoid long playback starting time
         *
         * Default is -1
         */
        public static var autoStartMaxDuration : Number = -1;

        /**
         * seekFromLevel
         *
         * Seek level:
         *  from 0 to 1: indicates the "normalized" preferred bitrate. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, keep previous level matching previous download bandwidth
         *
         * Default is -1
         */
        public static var seekFromLevel : Number = -1;

		/**
		 * subtitlesAutoSelectDefault
		 *
		 * Should a subtitles track automatically be selected if it is flagged
		 * as DEFAULT=YES?
		 *
		 * Default is false
		 */
		public static var subtitlesAutoSelectDefault:Boolean = false;

        /**
         * subtitlesAutoSelect
         *
         * Should a subtitles track automatically be selected if it is flagged
         * as AUTOSELECT=YES and the language matches the current system locale?
		 * If true, these subtitles will always be selected in preference to
		 * default subtitles.
         *
         * Default is true
         */
        public static var subtitlesAutoSelect:Boolean = true;

        /**
         * subtitlesAutoSelectForced
         *
         * Should a subtitles track automatically be selected is it is flagged
         * as FORCED=YES? If true, forced subtitles will always be selected
		 * in preference to all others.
         *
         * Default is true
         */
        public static var subtitlesAutoSelectForced:Boolean = true;

        /**
         * subtitlesUseFlvTagForVod
         *
         * Should VOD subtitles be appended directly into the stream or handled
		 * using media time events?
         *
         * Default is false
         */
        public static var subtitlesUseFlvTagForVod:Boolean = false;

		/**
		 * altAudioSwitchMode
		 *
		 * Selects which method to use when switching between alternative audio
		 * streams.
		 *
		 * Default is HLSAltAudioSwitchMode.DEFAULT
		 */
		public static var altAudioSwitchMode:uint = HLSAltAudioSwitchMode.DEFAULT;

		/**
		 * When bandwidth availability increases, what is the maximum number
		 * of quality levels we can we switch up at a time?
		 *
		 * Default is uint.MAX_VALUE
		 */
		public static var maxUpSwitchLimit:uint = uint.MAX_VALUE;

		/**
		 * When bandwidth availability decreases, what is the maximum number
		 * of quality levels we can we switch down at a time?
		 *
		 * Default is uint.MAX_VALUE
		 */
		public static var maxDownSwitchLimit:uint = uint.MAX_VALUE;

		/**
		 * When decoding AES data, how much of the time available for each
		 * frame should be used for decryption?
		 *
		 * Default is 0.2
		 */
		public static var aesMaxFrameTime:Number = 0.2;

        /**
         * useHardwareVideoDecoder
         *
         * Use hardware video decoder:
         *  it will set NetStream.useHardwareDecoder
         *  refer to http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html#useHardwareDecoder
         *
         * Default is true
         */
        public static var useHardwareVideoDecoder : Boolean = true;

        /**
         * logInfo
         *
         * Defines whether INFO level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logInfo : Boolean = true;

        /**
         * logDebug
         *
         * Defines whether DEBUG level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug : Boolean = false;

        /**
         * logDebug2
         *
         * Defines whether DEBUG2 level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug2 : Boolean = false;

        /**
         * logWarn
         *
         * Defines whether WARN level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logWarn : Boolean = true;

        /**
         * logError
         *
         * Defines whether ERROR level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logError : Boolean = true;
    }
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mangui.hls {
    import org.mangui.hls.constant.HLSAltAudioSwitchMode;
    import org.mangui.hls.constant.HLSMaxLevelCappingMode;
    import org.mangui.hls.constant.HLSSeekMode;

    public final class HLSSettings extends Object {

        /**
         * autoStartLoad
         *
         * if set to true,
         *      start level playlist and first fragments will be loaded automatically,
         *      after triggering of HlsEvent.MANIFEST_PARSED event
         * if set to false,
         *      an explicit API call (hls.startLoad()) will be needed
         *      to start quality level/fragment loading.
         *
         * Default is true
         */

        public static var autoStartLoad : Boolean = true;

        /**
         * capLevelToStage
         *
         * Limit levels usable in auto-quality by the stage dimensions (width and height).
         *      true - level width and height (defined in m3u8 playlist) will be compared with the player width and height (stage.stageWidth and stage.stageHeight).
         *             Max level will be set depending on the maxLevelCappingMode option.
         *      false - levels will not be limited. All available levels could be used in auto-quality mode taking only bandwidth into consideration.
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelToStage : Boolean = true;

        /**
         * maxLevelCappingMode
         *
         * Defines the max level capping mode to the one available in HLSMaxLevelCappingMode
         *      HLSMaxLevelCappingMode.DOWNSCALE - max capped level should be the one with the dimensions equal or greater than the stage dimensions (so the video will be downscaled)
         *      HLSMaxLevelCappingMode.UPSCALE - max capped level should be the one with the dimensions equal or lower than the stage dimensions (so the video will be upscaled)
         *
         * Default is HLSMaxLevelCappingMode.DOWNSCALE
         */
        public static var maxLevelCappingMode : String = HLSMaxLevelCappingMode.UPSCALE;

        // // // // // // /////////////////////////////////
        //
        // org.mangui.hls.stream.HLSNetStream
        //
        // // // // // // /////////////////////////////////
        /**
         * minBufferLength
         *
         * Defines minimum buffer length in seconds before playback can start, after seeking or buffer stalling.
         *
         * Default is -1 = auto
         */
        public static var minBufferLength : Number = -1;

        /**
         * minBufferLengthCapping
         *
         * Defines minimum buffer length capping value (max value) if minBufferLength is set to -1
         *
         * Default is -1 = no capping
         */
        public static var minBufferLengthCapping : Number = -1;

        /**
         * maxBufferLength
         *
         * Defines maximum buffer length in seconds.
         * (0 means infinite buffering)
         *
         * Default is 120
         */
        public static var maxBufferLength : Number = 120;

        /**
         * maxBackBufferLength
         *
         * Defines maximum back buffer length in seconds.
         * (0 means infinite back buffering)
         *
         * Default is 30
         */
        public static var maxBackBufferLength : Number = 30;

        /**
         * lowBufferLength
         *
         * Defines low buffer length in seconds.
         * When crossing down this threshold, HLS will switch to buffering state.
         *
         * Default is 3
         */
        public static var lowBufferLength : Number = 3;

        /**
         * mediaTimeUpdatePeriod
         *
         * time update period in ms
         * period at which HLSEvent.MEDIA_TIME will be triggered
         * Default is 100 ms
         */
        public static var mediaTimePeriod : int = 100;

        /**
         * fpsDroppedMonitoringPeriod
         *
         * dropped FPS Monitor Period in ms
         * period at which nb dropped FPS will be checked
         * Default is 5000 ms
         */
        public static var fpsDroppedMonitoringPeriod : int = 5000;

        /**
         * fpsDroppedMonitoringThreshold
         *
         * dropped FPS Threshold
         * every fpsDroppedMonitoringPeriod, dropped FPS will be compared to displayed FPS.
         * if during that period, ratio of (dropped FPS/displayed FPS) is greater or equal
         * than fpsDroppedMonitoringThreshold, HLSEvent.FPS_DROP event will be fired
         * Default is 0.2 (20%)
         */
        public static var fpsDroppedMonitoringThreshold : Number = 0.2;

		/**
		 * If the dropped FPS threshold is reached, should we nudge the playhead position
		 * forward slightly to try to kick start playback?
		 *
		 * Default is false
		 */
		public static var fpsDroppedNudgeEnabled : Boolean = false;

        /**
         * capLevelonFPSDrop
         *
         * Limit levels usable in auto-quality when FPS drop is detected
         * i.e. if frame drop is detected on level 5, auto level will be capped to level 4 a
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is ignored in manual mode so all the levels could be selected manually.
         *
         * Default is false
         */
        public static var capLevelonFPSDrop : Boolean = false;

        /**
         * smoothAutoSwitchonFPSDrop
         *
         * force a smooth level switch Limit when FPS drop is detected in auto-quality
         * i.e. if frame drop is detected on level 5, it will trigger an auto quality level switch
         * to level 4 for next fragment
         *      true -  enabled
         *      false - disabled
         *
         * Note: this setting is active only if capLevelonFPSDrop==true
         *
         * Default is true
         */
        public static var smoothAutoSwitchonFPSDrop : Boolean = true;

        /**
         * switchDownOnLevelError
         *
         * if level loading fails, and if in auto mode, and we are not on lowest level
         * don't report Level loading error straight-away, try to switch down first
         *      true -  enabled
         *      false - disabled
         *
         * Default is true
         */
        public static var switchDownOnLevelError : Boolean = true;

        /**
         * seekMode
         *
         * Defines seek mode to one form available in HLSSeekMode class:
         *      HLSSeekMode.ACCURATE_SEEK - accurate seeking to exact requested position
         *      HLSSeekMode.KEYFRAME_SEEK - key-frame based seeking (seek to nearest key frame before requested seek position)
         *
         * Default is HLSSeekMode.KEYFRAME_SEEK
         */
        public static var seekMode : String = HLSSeekMode.KEYFRAME_SEEK;

        /**
         * keyLoadMaxRetry
         *
         * Max nb of retries for Key Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var keyLoadMaxRetry : int = 3;

        /**
         * keyLoadMaxRetryTimeout
         *
         * Maximum key retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on key request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until keyLoadMaxRetryTimeout is reached.
         *
         * Default is 64000.
         */
        public static var keyLoadMaxRetryTimeout : Number = 64000;

        /**
         * fragmentLoadMaxRetry
         *
         * Max number of retries for Fragment Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         *
         * Default is 3
         */
        public static var fragmentLoadMaxRetry : int = 3;

        /**
         * fragmentLoadMaxRetryTimeout
         *
         * Maximum Fragment retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until fragmentLoadMaxRetryTimeout is reached.
         *
         * Default is 4000
         */
        public static var fragmentLoadMaxRetryTimeout : Number = 4000;

        /**
         * fragmentLoadSkipAfterMaxRetry
         *
         * control behaviour in case fragment load still fails after max retry timeout
         * if set to true, fragment will be skipped and next one will be loaded.
         * If set to false, an I/O Error will be raised.
         *
         * Default is true.
         */
        public static var fragmentLoadSkipAfterMaxRetry : Boolean = true;

        /**
         * maxSkippedFragments
         *
         * Maximum count of skipped fragments in a row before an I/O Error will be raised.
         *      0 - no skip (same as fragmentLoadSkipAfterMaxRetry = false)
         *      -1 - no limit for skipping, skip till the end of the playlist
         *
         * Default is -1.
         */
        public static var maxSkippedFragments : int = -1;

        /**
         * flushLiveURLCache
         *
         * If set to true, live playlist will be flushed from URL cache before reloading
         * (this is to workaround some cache issues with some combination of Flash Player / IE version)
         *
         * Default is false
         */
        public static var flushLiveURLCache : Boolean = false;

        /**
         * initialLiveManifestSize
         *
         * Number of segments needed to start playback of Live stream.
         *
         * Default is 2
         */
        public static var initialLiveManifestSize : uint = 2;

		/**
		 * liveStopLoadingOnPause
		 *
		 * Should live streams stop loading when paused?
		 *
		 * Default is true
		 */
		public static var liveStopLoadingOnPause : Boolean = true;

        /**
         * manifestLoadMaxRetry
         *
         * max nb of retries for Manifest Loading in case I/O errors are met,
         *      0, means no retry, error will be triggered automatically
         *     -1 means infinite retry
         */
        public static var manifestLoadMaxRetry : int = 3;

        /**
         * manifestLoadMaxRetryTimeout
         *
         * Maximum Manifest retry timeout (in milliseconds) in case I/O errors are met.
         * Every fail on fragment request, player will exponentially increase the timeout to try again.
         * It starts waiting 1 second (1000ms), than 2, 4, 8, 16, until manifestLoadMaxRetryTimeout is reached.
         *
         * Default is 64000
         */
        public static var manifestLoadMaxRetryTimeout : Number = 64000;

        /**
         * manifestRedundantLoadmaxRetry
		 *
         * max nb of looping over the redundant streams.
         *   >0  means looping over the stream array 2 or more times
         *    0  means looping exactly once (no retries) - default behaviour
         *   -1  means infinite retry
         */
         public static var manifestRedundantLoadmaxRetry : int = 3;

        /**
         * startFromBitrate
         *
         * If greater than 0, specifies the preferred bitrate.
         * If -1, and startFromLevel is not specified, automatic start level selection will be used.
         * This parameter, if set, will take priority over startFromLevel.
         *
         * Default is -1
         */
        public static var startFromBitrate : Number = -1;

        /**
         * startFromLevel
         *
         * start level :
         *  from 0 to 1 : indicates the "normalized" preferred level. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, playback will start from level matching download bandwidth (determined from download of first segment)
         * -2 : playback will start from the first level appearing in Manifest (not sorted by bitrate)
         *
         * Default is -1
         */
        public static var startFromLevel : Number = -1;

        /**
         * autoStartMaxDuration
         *
         * max fragment loading duration in automatic start level selection mode (in ms)
         * -1 : max duration not capped
         * other : max duration is capped to avoid long playback starting time
         *
         * Default is -1
         */
        public static var autoStartMaxDuration : Number = -1;

        /**
         * seekFromLevel
         *
         * Seek level:
         *  from 0 to 1: indicates the "normalized" preferred bitrate. As such, if it is 0.5, the closest to the middle bitrate will be selected and used first.
         * -1 : automatic start level selection, keep previous level matching previous download bandwidth
         *
         * Default is -1
         */
        public static var seekFromLevel : Number = -1;

		/**
		 * subtitlesAutoSelectDefault
		 *
		 * Should a subtitles track automatically be selected if it is flagged
		 * as DEFAULT=YES?
		 *
		 * Default is false
		 */
		public static var subtitlesAutoSelectDefault:Boolean = false;

        /**
         * subtitlesAutoSelect
         *
         * Should a subtitles track automatically be selected if it is flagged
         * as AUTOSELECT=YES and the language matches the current system locale?
		 * If true, these subtitles will always be selected in preference to
		 * default subtitles.
         *
         * Default is true
         */
        public static var subtitlesAutoSelect:Boolean = true;

        /**
         * subtitlesAutoSelectForced
         *
         * Should a subtitles track automatically be selected is it is flagged
         * as FORCED=YES? If true, forced subtitles will always be selected
		 * in preference to all others.
         *
         * Default is true
         */
        public static var subtitlesAutoSelectForced:Boolean = true;

        /**
         * subtitlesUseFlvTagForVod
         *
         * Should VOD subtitles be appended directly into the stream or handled
		 * using media time events?
         *
         * Default is false
         */
        public static var subtitlesUseFlvTagForVod:Boolean = false;

		/**
		 * altAudioSwitchMode
		 *
		 * Selects which method to use when switching between alternative audio
		 * streams.
		 *
		 * Default is HLSAltAudioSwitchMode.DEFAULT
		 */
		public static var altAudioSwitchMode:uint = HLSAltAudioSwitchMode.DEFAULT;

		/**
		 * When bandwidth availability increases, what is the maximum number
		 * of quality levels we can we switch up at a time?
		 *
		 * Default is uint.MAX_VALUE
		 */
		public static var maxUpSwitchLimit:uint = uint.MAX_VALUE;

		/**
		 * When bandwidth availability decreases, what is the maximum number
		 * of quality levels we can we switch down at a time?
		 *
		 * Default is uint.MAX_VALUE
		 */
		public static var maxDownSwitchLimit:uint = uint.MAX_VALUE;

		/**
		 * When decoding AES data, how much of the time available for each
		 * frame should be used for decryption?
		 *
		 * Default is 0.2
		 */
		public static var aesMaxFrameTime:Number = 0.2;

        /**
         * useHardwareVideoDecoder
         *
         * Use hardware video decoder:
         *  it will set NetStream.useHardwareDecoder
         *  refer to http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html#useHardwareDecoder
         *
         * Default is false
         */
        public static var useHardwareVideoDecoder : Boolean = false;

        /**
         * logInfo
         *
         * Defines whether INFO level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logInfo : Boolean = true;

        /**
         * logDebug
         *
         * Defines whether DEBUG level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug : Boolean = false;

        /**
         * logDebug2
         *
         * Defines whether DEBUG2 level log messages will will appear in the console
         *
         * Default is false
         */
        public static var logDebug2 : Boolean = false;

        /**
         * logWarn
         *
         * Defines whether WARN level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logWarn : Boolean = true;

        /**
         * logError
         *
         * Defines whether ERROR level log messages will will appear in the console
         *
         * Default is true
         */
        public static var logError : Boolean = true;
    }
}

Set default value for useHardwareVideoDecoder to false


package aerys.minko.render.geometry.stream
{
	import aerys.minko.type.Signal;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexFormat;

	public interface IVertexStream
	{
		function get format() 			: VertexFormat;
		function get numVertices()		: uint;

		function get changed()			: Signal;
		function get boundsChanged()	: Signal;

		function disposeLocalData(waitForUpload : Boolean = true) : void;
		function deleteVertexByIndex(index : uint) : Boolean;
		function getStreamByComponent(component : VertexComponent) : VertexStream;
		function dispose() : void;
	}
}

package aerys.minko.render.geometry.stream
{
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexFormat;
	import aerys.minko.type.Signal;

	public interface IVertexStream
	{
		function get format() 			: VertexFormat;
		function get numVertices()		: uint;

		function get changed()			: Signal;
		function get boundsChanged()	: Signal;

		function get(index 		: uint,
					 component 	: VertexComponent 	= null,
					 offset 	: uint 				= 0) : Number;

		function set(index 		: uint,
					 value 		: Number,
					 component 	: VertexComponent 	= null,
					 offset 	: uint 				= 0) : void;

		function deleteVertex(index : uint) : IVertexStream;
		function duplicateVertex(index : uint) : IVertexStream;

		function disposeLocalData(waitForUpload : Boolean = true) : void;
		function getStreamByComponent(component : VertexComponent) : VertexStream;
		function dispose() : void;
	}
}

add get(), set(), duplicateVertex() and deleteVertex() to the IVertexStream interface


//
// $Id: $

package flash.net
{

import flash.errors.IOError;

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;

import flash.utils.ByteArray;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;

public class Socket extends EventDispatcher
    implements IDataInput, IDataOutput
{
    public function Socket (host :String = null, port :int = 0)
    {
        if (_theSocket != null) {
            throw new Error("You may not create Sockets");
        }
        _theSocket = this;

        _state = ST_VIRGIN;
        Thane.requestHeartbeat(heartbeat);

        if (host != null && port > 0) {
            connect(host, port);
        }
    }

    public function connect (host: String, port: int) :void
    {
        if (!host) {
            throw new IOError("No host specified in connect()");
        }

        if (_state == ST_WAITING) {
            return;
        }

        if (_state == ST_CONNECTED) {
            close();
        }

        _host = host;
        _port = port;

        _state = ST_WAITING;
        trace("Socket:connect() switching to ST_WAITING...");
    }

    public function close () :void
    {
        if (_state != ST_CONNECTED) {
            throw new IOError("Socket was not open");
        }
        nb_disconnect();
    }

    protected function heartbeat () :void
    {
        if (_theSocket == null) {
            return;
        }
        switch(_state) {
        case ST_VIRGIN:
            break;

        case ST_CONNECTED:
            _oBuf.position = _oPos;
            var wrote :int = 0;

            var read :int = nb_read(_iBuf);
            if (_oPos < _oBuf.length) {
                wrote = nb_write(_oBuf);
            }
            if (read > 0 || wrote > 0) {
                trace("Socket:heartbeat() read " + read + ", wrote " + wrote);
            }

            _iBuf = massageBuffer(_iBuf);
            _oBuf = massageBuffer(_oBuf);

            _oPos = _oBuf.position;

            if (read > 0) {
                _bytesTotal += read;
                dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA));
            }

            break;

        case ST_WAITING:
            switch(nb_connect(_host, _port)) {
            case -1:
                dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
                _state = ST_VIRGIN;
                break;
            case 0:
                trace("Socket:heartbeat() trying to connect...");
                break;
            case 1:
                trace("Socket:heartbeat() connected!");
                _state = ST_CONNECTED;
                dispatchEvent(new Event(Event.CONNECT));
                break;
            }
        }
    }

    private native function nb_disconnect() :void;

    /** Returns -1 for error, 0 for keep trying, 1 for success. */
    private native function nb_connect (host :String, port :int) :int;

    /** Returns -1 for error, else the number of bytes read. */
    private native function nb_read (iBuf :ByteArray) :int;

    /** Returns -1 for error, else the number of bytes written. */
    private native function nb_write (oBuf :ByteArray) :int;

    public function flush () :void
    {
        // TODO: we should probably respect flush somehow...
    }

	public function get endian(): String
    {
        return _iBuf.endian;
    }

	public function set endian(type: String) :void
    {
        _iBuf.endian = type;
        _oBuf.endian = type;
    }

    public function get bytesAvailable () :uint
    {
        return _iBuf.bytesAvailable;
    }

    public function set objectEncoding (encoding :uint) :void
    {
        if (encoding != ObjectEncoding.AMF3) {
            throw new Error("Only AMF3 supported");
        }
    }

    public function get objectEncoding () :uint
    {
        return ObjectEncoding.AMF3;
    }

    // IDataInput
    public function readBytes(bytes :ByteArray, offset :uint=0, length :uint=0) :void
    {
        return _iBuf.readBytes(bytes, offset, length);
    }

    public function readBoolean() :Boolean
    {
        return _iBuf.readBoolean();
    }

    public function readByte() :int
    {
        return _iBuf.readByte();
    }

    public function readUnsignedByte() :uint
    {
        return _iBuf.readUnsignedByte();
    }

    public function readShort() :int
    {
        return _iBuf.readShort();
    }

    public function readUnsignedShort() :uint
    {
        return _iBuf.readUnsignedShort();
    }

    public function readInt() :int
    {
        return _iBuf.readInt();
    }

    public function readUnsignedInt() :uint
    {
        return _iBuf.readUnsignedInt();
    }

    public function readFloat() :Number
    {
        return _iBuf.readFloat();
    }

    public function readDouble() :Number
    {
        return _iBuf.readDouble();
    }

    public function readUTF() :String
    {
        return _iBuf.readUTF();
    }

    public function readUTFBytes(length :uint) :String
    {
        return _iBuf.readUTFBytes(length);
    }

    // IDataOutput
    public function writeBytes(bytes :ByteArray, offset :uint = 0, length :uint = 0) :void
    {
        _oBuf.writeBytes(bytes, offset, length);
    }

    public function writeBoolean(value :Boolean) :void
    {
        _oBuf.writeBoolean(value);
    }

    public function writeByte(value :int) :void
    {
        _oBuf.writeByte(value);
    }

    public function writeShort(value :int) :void
    {
        _oBuf.writeShort(value);
    }

    public function writeInt(value :int) :void
    {
        _oBuf.writeInt(value);
    }

    public function writeUnsignedInt(value :uint) :void
    {
        _oBuf.writeUnsignedInt(value);
    }

    public function writeFloat(value :Number) :void
    {
        _oBuf.writeFloat(value);
    }

    public function writeDouble(value :Number) :void
    {
        _oBuf.writeDouble(value);
    }

    public function writeUTF(value :String) :void
    {
        _oBuf.writeUTF(value);
    }

    public function writeUTFBytes(value :String) :void
    {
        _oBuf.writeUTFBytes(value);
    }

    // AMF3 bits
    public function readObject () :*
    {
        return AMF3Decoder.decode(this);
    }

    public function writeObject (object :*) :void
    {
        AMF3Encoder.encode(this, object);
    }

    protected function massageBuffer (buffer :ByteArray) :ByteArray
    {
        // we only switch buffers if we're wasting 25% and at least 64k
        if (buffer.position < 0x10000 || 4*buffer.position < buffer.length) {
            return buffer;
        }

        var newBuffer :ByteArray = new ByteArray();

        if (buffer.bytesAvailable > 0) {
            buffer.readBytes(newBuffer, 0, buffer.bytesAvailable);
        }
        return newBuffer;
    }

    private var _state :int;
    private var _host :String;
    private var _port :int;

    private var _iBuf :ByteArray = new ByteArray();
    private var _oBuf :ByteArray = new ByteArray();

    // we have to keep our own position in oBuf because writing changes it (?!)
    private var _oPos :int = 0;

    private var _bytesTotal :int = 0;

    private static var _theSocket :Socket = null;

    private static const ST_VIRGIN :int = 1;
    private static const ST_WAITING :int = 2;
    private static const ST_CONNECTED :int = 3;
}
}

//
// $Id: $

package flash.net
{

import flash.errors.IOError;

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;

import flash.utils.ByteArray;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;

public class Socket extends EventDispatcher
    implements IDataInput, IDataOutput
{
    public function Socket (host :String = null, port :int = 0)
    {
        if (_theSocket != null) {
            throw new Error("You may not create Sockets");
        }
        _theSocket = this;

        _state = ST_VIRGIN;
        Thane.requestHeartbeat(heartbeat);

        if (host != null && port > 0) {
            connect(host, port);
        }
    }

    public function connect (host: String, port: int) :void
    {
        if (!host) {
            throw new IOError("No host specified in connect()");
        }

        if (_state == ST_WAITING) {
            return;
        }

        if (_state == ST_CONNECTED) {
            close();
        }

        _host = host;
        _port = port;

        _state = ST_WAITING;
//        trace("Socket:connect() switching to ST_WAITING...");
    }

    public function close () :void
    {
        if (_state != ST_CONNECTED) {
            throw new IOError("Socket was not open");
        }
        nb_disconnect();
    }

    protected function heartbeat () :void
    {
        if (_theSocket == null) {
            return;
        }
        switch(_state) {
        case ST_VIRGIN:
            break;

        case ST_CONNECTED:
            _oBuf.position = _oPos;
            var wrote :int = 0;

            var read :int = nb_read(_iBuf);
            if (_oPos < _oBuf.length) {
                wrote = nb_write(_oBuf);
            }
            if (read > 0 || wrote > 0) {
//                trace("Socket:heartbeat() read " + read + ", wrote " + wrote);
            }

            _iBuf = massageBuffer(_iBuf);
            _oBuf = massageBuffer(_oBuf);

            _oPos = _oBuf.position;

            if (read > 0) {
                _bytesTotal += read;
                dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA));
            }

            break;

        case ST_WAITING:
            switch(nb_connect(_host, _port)) {
            case -1:
                dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));
                _state = ST_VIRGIN;
                break;
            case 0:
//                trace("Socket:heartbeat() trying to connect...");
                break;
            case 1:
//                trace("Socket:heartbeat() connected!");
                _state = ST_CONNECTED;
                dispatchEvent(new Event(Event.CONNECT));
                break;
            }
        }
    }

    private native function nb_disconnect() :void;

    /** Returns -1 for error, 0 for keep trying, 1 for success. */
    private native function nb_connect (host :String, port :int) :int;

    /** Returns -1 for error, else the number of bytes read. */
    private native function nb_read (iBuf :ByteArray) :int;

    /** Returns -1 for error, else the number of bytes written. */
    private native function nb_write (oBuf :ByteArray) :int;

    public function flush () :void
    {
        // TODO: we should probably respect flush somehow...
    }

	public function get endian(): String
    {
        return _iBuf.endian;
    }

	public function set endian(type: String) :void
    {
        _iBuf.endian = type;
        _oBuf.endian = type;
    }

    public function get bytesAvailable () :uint
    {
        return _iBuf.bytesAvailable;
    }

    public function set objectEncoding (encoding :uint) :void
    {
        if (encoding != ObjectEncoding.AMF3) {
            throw new Error("Only AMF3 supported");
        }
    }

    public function get objectEncoding () :uint
    {
        return ObjectEncoding.AMF3;
    }

    // IDataInput
    public function readBytes(bytes :ByteArray, offset :uint=0, length :uint=0) :void
    {
        return _iBuf.readBytes(bytes, offset, length);
    }

    public function readBoolean() :Boolean
    {
        return _iBuf.readBoolean();
    }

    public function readByte() :int
    {
        return _iBuf.readByte();
    }

    public function readUnsignedByte() :uint
    {
        return _iBuf.readUnsignedByte();
    }

    public function readShort() :int
    {
        return _iBuf.readShort();
    }

    public function readUnsignedShort() :uint
    {
        return _iBuf.readUnsignedShort();
    }

    public function readInt() :int
    {
        return _iBuf.readInt();
    }

    public function readUnsignedInt() :uint
    {
        return _iBuf.readUnsignedInt();
    }

    public function readFloat() :Number
    {
        return _iBuf.readFloat();
    }

    public function readDouble() :Number
    {
        return _iBuf.readDouble();
    }

    public function readUTF() :String
    {
        return _iBuf.readUTF();
    }

    public function readUTFBytes(length :uint) :String
    {
        return _iBuf.readUTFBytes(length);
    }

    // IDataOutput
    public function writeBytes(bytes :ByteArray, offset :uint = 0, length :uint = 0) :void
    {
        _oBuf.writeBytes(bytes, offset, length);
    }

    public function writeBoolean(value :Boolean) :void
    {
        _oBuf.writeBoolean(value);
    }

    public function writeByte(value :int) :void
    {
        _oBuf.writeByte(value);
    }

    public function writeShort(value :int) :void
    {
        _oBuf.writeShort(value);
    }

    public function writeInt(value :int) :void
    {
        _oBuf.writeInt(value);
    }

    public function writeUnsignedInt(value :uint) :void
    {
        _oBuf.writeUnsignedInt(value);
    }

    public function writeFloat(value :Number) :void
    {
        _oBuf.writeFloat(value);
    }

    public function writeDouble(value :Number) :void
    {
        _oBuf.writeDouble(value);
    }

    public function writeUTF(value :String) :void
    {
        _oBuf.writeUTF(value);
    }

    public function writeUTFBytes(value :String) :void
    {
        _oBuf.writeUTFBytes(value);
    }

    // AMF3 bits
    public function readObject () :*
    {
        return AMF3Decoder.decode(this);
    }

    public function writeObject (object :*) :void
    {
        AMF3Encoder.encode(this, object);
    }

    protected function massageBuffer (buffer :ByteArray) :ByteArray
    {
        // we only switch buffers if we're wasting 25% and at least 64k
        if (buffer.position < 0x10000 || 4*buffer.position < buffer.length) {
            return buffer;
        }

        var newBuffer :ByteArray = new ByteArray();

        if (buffer.bytesAvailable > 0) {
            buffer.readBytes(newBuffer, 0, buffer.bytesAvailable);
        }
        return newBuffer;
    }

    private var _state :int;
    private var _host :String;
    private var _port :int;

    private var _iBuf :ByteArray = new ByteArray();
    private var _oBuf :ByteArray = new ByteArray();

    // we have to keep our own position in oBuf because writing changes it (?!)
    private var _oPos :int = 0;

    private var _bytesTotal :int = 0;

    private static var _theSocket :Socket = null;

    private static const ST_VIRGIN :int = 1;
    private static const ST_WAITING :int = 2;
    private static const ST_CONNECTED :int = 3;
}
}

Cut down on the verbosity, but leave these in for now, there's surely a few bugs left.


//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.IDataOutput;

import com.adobe.images.PNGEncoder;

import flump.SwfTexture;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;

import com.threerings.util.Arrays;

public class Atlas
{
    // The empty border size around the right and bottom edges of each texture, to prevent bleeding
    public static const PADDING :int = 1;

    public var name :String;

    public function Atlas (name :String, w :int, h :int) {
        this.name = name;
        _width = w;
        _height = h;
        _mask = Arrays.create(_width * _height, false);
    }

    public function get area () :int { return _width * _height; }

    public function get filename () :String { return name + ".png"; }

    public function get used () :int {
        var used :int = 0;
        _nodes.forEach(function (n :Node, ..._) :void { used += n.bounds.width * n.bounds.height; });
        return used;
    }

    public function writePNG (bytes :IDataOutput) :void {
        var constructed :Sprite = new Sprite();
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const bm :Bitmap = new Bitmap(node.texture.toBitmapData(), "auto", true);
            constructed.addChild(bm);
            bm.x = node.bounds.x;
            bm.y = node.bounds.y;
        });
        const bd :BitmapData =
            SwfTexture.renderToBitmapData(constructed, _width, _height);
        bytes.writeBytes(PNGEncoder.encode(bd));
    }

    public function toMold () :AtlasMold {
        const mold :AtlasMold = new AtlasMold();
        mold.file = name + ".png";
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const texMold :AtlasTextureMold = new AtlasTextureMold();
            texMold.symbol = tex.symbol;
            texMold.bounds = new Rectangle(node.bounds.x, node.bounds.y, tex.w, tex.h);
            texMold.offset = new Point(tex.offset.x, tex.offset.y);
            mold.textures.push(texMold);
        });
        return mold;
    }

    // Try to place a texture in this atlas, return true if it fit
    public function place (tex :SwfTexture) :Boolean {
        var w :int = tex.w + PADDING;
        var h :int = tex.h + PADDING;
        if (w > _width || h > _height) {
            return false;
        }

        var found :Boolean = false;
        for (var yy :int = 0; yy <= _height - h && !found; ++yy) {
            for (var xx :int = 0; xx <= _width - w; ++xx) {
                // if our right-most pixel is masked, jump ahead by that much
                if (maskAt(xx + w - 1, yy)) {
                    xx += w;
                    continue;
                }

                if (!isMasked(xx, yy, w, h)) {
                    _nodes.push(new Node(xx, yy, tex));
                    setMasked(xx, yy, w, h);
                    found = true;
                    break;
                }
            }
        }

        return found;
    }

    protected function isMasked (x :int, y :int, w :int, h :int) :Boolean {
        var xMax :int = x + w - 1;
        var yMax :int = y + h - 1;
        // fail fast on extents
        if (maskAt(x, y) || maskAt(x, yMax) || maskAt(xMax, y) || maskAt(xMax, yMax)) {
            return true;
        }

        for (var yy :int = y + 1; yy < yMax; ++yy) {
            for (var xx :int = x + 1; xx < xMax; ++xx) {
                if (maskAt(xx, yy)) {
                    return true;
                }
            }
        }
        return false;
    }

    protected function setMasked (x :int, y :int, w: int, h :int) :void {
        for (var yy :int = y; yy < y + h; ++yy) {
            for (var xx :int = x; xx < x + w; ++xx) {
                _mask[(yy * _width) + xx] = true;
            }
        }
    }

    protected function maskAt (xx :int, yy :int) :Boolean {
        return _mask[(yy * _width) + xx];
    }

    protected var _nodes :Array = [];
    protected var _width :int;
    protected var _height :int;
    protected var _mask :Array;
}
}

import flash.geom.Rectangle;

import flump.SwfTexture;

class Node
{
    public var bounds :Rectangle;
    public var texture :SwfTexture;

    public function Node (x :int, y :int, texture :SwfTexture) {
        this.texture = texture;
        this.bounds = new Rectangle(x, y, texture.w, texture.h);
    }
}

//
// Flump - Copyright 2012 Three Rings Design

package flump.export {

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.IDataOutput;

import com.adobe.images.PNGEncoder;

import flump.SwfTexture;
import flump.mold.AtlasMold;
import flump.mold.AtlasTextureMold;

import com.threerings.util.Arrays;

public class Atlas
{
    // The empty border size around the right and bottom edges of each texture, to prevent bleeding
    public static const PADDING :int = 2;

    public var name :String;

    public function Atlas (name :String, w :int, h :int) {
        this.name = name;
        _width = w;
        _height = h;
        _mask = Arrays.create(_width * _height, false);
    }

    public function get area () :int { return _width * _height; }

    public function get filename () :String { return name + ".png"; }

    public function get used () :int {
        var used :int = 0;
        _nodes.forEach(function (n :Node, ..._) :void { used += n.bounds.width * n.bounds.height; });
        return used;
    }

    public function writePNG (bytes :IDataOutput) :void {
        var constructed :Sprite = new Sprite();
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const bm :Bitmap = new Bitmap(node.texture.toBitmapData(), "auto", true);
            constructed.addChild(bm);
            bm.x = node.bounds.x;
            bm.y = node.bounds.y;
        });
        const bd :BitmapData =
            SwfTexture.renderToBitmapData(constructed, _width, _height);
        bytes.writeBytes(PNGEncoder.encode(bd));
    }

    public function toMold () :AtlasMold {
        const mold :AtlasMold = new AtlasMold();
        mold.file = name + ".png";
        _nodes.forEach(function (node :Node, ..._) :void {
            const tex :SwfTexture = node.texture;
            const texMold :AtlasTextureMold = new AtlasTextureMold();
            texMold.symbol = tex.symbol;
            texMold.bounds = new Rectangle(node.bounds.x, node.bounds.y, tex.w, tex.h);
            texMold.offset = new Point(tex.offset.x, tex.offset.y);
            mold.textures.push(texMold);
        });
        return mold;
    }

    // Try to place a texture in this atlas, return true if it fit
    public function place (tex :SwfTexture) :Boolean {
        var w :int = tex.w + PADDING;
        var h :int = tex.h + PADDING;
        if (w > _width || h > _height) {
            return false;
        }

        var found :Boolean = false;
        for (var yy :int = 0; yy <= _height - h && !found; ++yy) {
            for (var xx :int = 0; xx <= _width - w; ++xx) {
                // if our right-most pixel is masked, jump ahead by that much
                if (maskAt(xx + w - 1, yy)) {
                    xx += w;
                    continue;
                }

                if (!isMasked(xx, yy, w, h)) {
                    _nodes.push(new Node(xx, yy, tex));
                    setMasked(xx, yy, w, h);
                    found = true;
                    break;
                }
            }
        }

        return found;
    }

    protected function isMasked (x :int, y :int, w :int, h :int) :Boolean {
        var xMax :int = x + w - 1;
        var yMax :int = y + h - 1;
        // fail fast on extents
        if (maskAt(x, y) || maskAt(x, yMax) || maskAt(xMax, y) || maskAt(xMax, yMax)) {
            return true;
        }

        for (var yy :int = y + 1; yy < yMax; ++yy) {
            for (var xx :int = x + 1; xx < xMax; ++xx) {
                if (maskAt(xx, yy)) {
                    return true;
                }
            }
        }
        return false;
    }

    protected function setMasked (x :int, y :int, w: int, h :int) :void {
        for (var yy :int = y; yy < y + h; ++yy) {
            for (var xx :int = x; xx < x + w; ++xx) {
                _mask[(yy * _width) + xx] = true;
            }
        }
    }

    protected function maskAt (xx :int, yy :int) :Boolean {
        return _mask[(yy * _width) + xx];
    }

    protected var _nodes :Array = [];
    protected var _width :int;
    protected var _height :int;
    protected var _mask :Array;
}
}

import flash.geom.Rectangle;

import flump.SwfTexture;

class Node
{
    public var bounds :Rectangle;
    public var texture :SwfTexture;

    public function Node (x :int, y :int, texture :SwfTexture) {
        this.texture = texture;
        this.bounds = new Rectangle(x, y, texture.w, texture.h);
    }
}

Increase atlas padding to 2 pixels

Increase atlas padding to 2 pixels

I'm seeing edge artifacting at 1. Maybe this should be a configurable
setting?


package battlecode.client.viewer.render {

    import battlecode.client.viewer.MatchController;
    import battlecode.common.Team;
    import battlecode.events.MatchEvent;

    import flash.display.GradientType;
    import flash.geom.Matrix;

    import mx.containers.Canvas;
    import mx.containers.HBox;
    import mx.controls.Label;
    import mx.events.ResizeEvent;

    public class DrawDominationBar extends HBox {
        private var controller:MatchController;
        private var domBarCanvas:Canvas;
        private var leftDomLabel:Label;
        private var rightDomLabel:Label;
        private var lastRound:uint = 0;

        public function DrawDominationBar(controller:MatchController) {
            super();

            this.controller = controller;
            this.controller.addEventListener(MatchEvent.ROUND_CHANGE, onRoundChange);
            this.controller.addEventListener(MatchEvent.MATCH_CHANGE, onMatchChange);

            this.height = 50;

            domBarCanvas = new Canvas();
            domBarCanvas.percentHeight = 100;
            domBarCanvas.percentWidth = 100;
            domBarCanvas.horizontalScrollPolicy = "off";
            domBarCanvas.verticalScrollPolicy = "off";
            domBarCanvas.addEventListener(ResizeEvent.RESIZE, onResize);

            leftDomLabel = new Label();
            leftDomLabel.setStyle("color", 0xFFFFFF);
            leftDomLabel.setStyle("fontSize", 14);
            leftDomLabel.setStyle("fontWeight", "bold");
            leftDomLabel.setStyle("textAlign", "center");
            leftDomLabel.setStyle("fontFamily", "Courier New");

            rightDomLabel = new Label();
            rightDomLabel.setStyle("color", 0xFFFFFF);
            rightDomLabel.setStyle("fontSize", 14);
            rightDomLabel.setStyle("fontWeight", "bold");
            rightDomLabel.setStyle("textAlign", "center");
            rightDomLabel.setStyle("fontFamily", "Courier New");

            addChild(domBarCanvas);
            domBarCanvas.addChild(leftDomLabel);
            domBarCanvas.addChild(rightDomLabel);
        }

        private function onResize(e:ResizeEvent):void {
            redrawAll();
        }

        private function onRoundChange(e:MatchEvent):void {
            drawDomBar();
        }

        private function onMatchChange(e:MatchEvent):void {
            updateTooltip();
            drawDomBar();
        }

        public function redrawAll():void {
            drawDomBar();
        }

        private function updateTooltip():void {
            this.toolTip = controller.match.getTeamA() + " vs. " + controller.match.getTeamB() + "\n";
            this.toolTip += "Game " + (controller.currentMatch + 1) + " of " + controller.totalMatches + "\n";
            this.toolTip += "Map: " + controller.match.getMapName() + "\n";
        }

        private function drawDomBar():void {
            var aPoints:uint = controller.currentState.getPoints(Team.A);
            var bPoints:uint = controller.currentState.getPoints(Team.B);

            var centerWidth:Number = this.domBarCanvas.width / 2;
            var centerHeight:Number = this.domBarCanvas.height / 2;
            var barMaxWidth:Number = (this.domBarCanvas.width / 2) * .8;

            this.domBarCanvas.graphics.clear();

            var minDomPts:int = 10000000;
            var sideRatio:Number = minDomPts / 10000000;

            leftDomLabel.text = "(+" + minDomPts.toString() + ")";
            leftDomLabel.y = centerHeight - (leftDomLabel.height / 2) - 10;
            leftDomLabel.x = centerWidth - barMaxWidth * sideRatio - leftDomLabel.width / 2;

            rightDomLabel.text = "(+" + minDomPts.toString() + ")";
            rightDomLabel.y = centerHeight - (rightDomLabel.height / 2) - 10;
            rightDomLabel.x = centerWidth + barMaxWidth * sideRatio - rightDomLabel.width / 2;

            // side spikes
            this.domBarCanvas.graphics.lineStyle(2, 0xFF6666);
            this.domBarCanvas.graphics.moveTo(centerWidth - barMaxWidth * sideRatio + 1, centerHeight + 10);
            this.domBarCanvas.graphics.lineTo(centerWidth - barMaxWidth * sideRatio + 1, centerHeight + 2);

            this.domBarCanvas.graphics.lineStyle(2, 0x9999FF);
            this.domBarCanvas.graphics.moveTo(centerWidth + barMaxWidth * sideRatio - 1, centerHeight + 10);
            this.domBarCanvas.graphics.lineTo(centerWidth + barMaxWidth * sideRatio - 1, centerHeight + 2);

            // domination
            var topFill:uint = (aPoints > bPoints) ? 0xFFCCCC : 0xCCCCFF;
            var bottomFill:uint = (aPoints > bPoints) ? 0xFF0000 : 0x0000FF;
            var domBarWidth:Number = (aPoints - bPoints) / 10000000 * barMaxWidth;
            if (domBarWidth < -barMaxWidth) domBarWidth = -barMaxWidth;
            if (domBarWidth > barMaxWidth) domBarWidth = barMaxWidth;

            var fillMatrix:Matrix = new Matrix();
            fillMatrix.createGradientBox(barMaxWidth, 12, Math.PI/2, centerWidth, centerHeight - 0);

            this.domBarCanvas.graphics.lineStyle(1, 0xFFFFFF);
            this.domBarCanvas.graphics.beginGradientFill(GradientType.LINEAR, [topFill, bottomFill], [1, 1], [0, 255], fillMatrix, "pad");
            this.domBarCanvas.graphics.drawRect(centerWidth, centerHeight - 0, -domBarWidth, 12);
            this.domBarCanvas.graphics.endFill();

            // center spike
            this.domBarCanvas.graphics.lineStyle(4, 0xCCCCCC);
            this.domBarCanvas.graphics.moveTo(centerWidth, centerHeight + 16);
            this.domBarCanvas.graphics.lineTo(centerWidth, centerHeight - 4);
        }

    }

}

package battlecode.client.viewer.render {

    import battlecode.client.viewer.MatchController;
    import battlecode.common.Team;
    import battlecode.events.MatchEvent;

    import flash.display.GradientType;
    import flash.geom.Matrix;

    import mx.containers.Canvas;
    import mx.containers.HBox;
    import mx.events.ResizeEvent;

    public class DrawDominationBar extends HBox {
        private var controller:MatchController;
        private var domBarCanvas:Canvas;

        public function DrawDominationBar(controller:MatchController) {
            super();

            this.controller = controller;
            this.controller.addEventListener(MatchEvent.ROUND_CHANGE, onRoundChange);
            this.controller.addEventListener(MatchEvent.MATCH_CHANGE, onMatchChange);

            this.height = 50;

            domBarCanvas = new Canvas();
            domBarCanvas.percentHeight = 100;
            domBarCanvas.percentWidth = 100;
            domBarCanvas.horizontalScrollPolicy = "off";
            domBarCanvas.verticalScrollPolicy = "off";
            domBarCanvas.addEventListener(ResizeEvent.RESIZE, onResize);

            addChild(domBarCanvas);
        }

        private function onResize(e:ResizeEvent):void {
            redrawAll();
        }

        private function onRoundChange(e:MatchEvent):void {
            drawDomBar();
        }

        private function onMatchChange(e:MatchEvent):void {
            updateTooltip();
            drawDomBar();
        }

        public function redrawAll():void {
            drawDomBar();
        }

        private function updateTooltip():void {
            this.toolTip = controller.match.getTeamA() + " vs. " + controller.match.getTeamB() + "\n";
            this.toolTip += "Game " + (controller.currentMatch + 1) + " of " + controller.totalMatches + "\n";
            this.toolTip += "Map: " + controller.match.getMapName() + "\n";
        }

        private function drawDomBar():void {
            var aPoints:uint = controller.currentState.getPoints(Team.A);
            var bPoints:uint = controller.currentState.getPoints(Team.B);

            var centerWidth:Number = this.domBarCanvas.width / 2;
            var centerHeight:Number = this.domBarCanvas.height / 2;
            var barMaxWidth:Number = (this.domBarCanvas.width / 2) * .8;

            this.domBarCanvas.graphics.clear();

            // side spikes
            this.domBarCanvas.graphics.lineStyle(2, 0xFF6666);
            this.domBarCanvas.graphics.moveTo(centerWidth - barMaxWidth + 1, centerHeight + 10);
            this.domBarCanvas.graphics.lineTo(centerWidth - barMaxWidth + 1, centerHeight + 2);

            this.domBarCanvas.graphics.lineStyle(2, 0x9999FF);
            this.domBarCanvas.graphics.moveTo(centerWidth + barMaxWidth - 1, centerHeight + 10);
            this.domBarCanvas.graphics.lineTo(centerWidth + barMaxWidth - 1, centerHeight + 2);

            // domination
            var topFill:uint = (aPoints > bPoints) ? 0xFFCCCC : 0xCCCCFF;
            var bottomFill:uint = (aPoints > bPoints) ? 0xFF0000 : 0x0000FF;
            var domBarWidth:Number = (aPoints - bPoints) / 10000000 * barMaxWidth;
            if (domBarWidth < -barMaxWidth) domBarWidth = -barMaxWidth;
            if (domBarWidth > barMaxWidth) domBarWidth = barMaxWidth;

            var fillMatrix:Matrix = new Matrix();
            fillMatrix.createGradientBox(barMaxWidth, 12, Math.PI/2, centerWidth, centerHeight - 0);

            this.domBarCanvas.graphics.lineStyle(1, 0xFFFFFF);
            this.domBarCanvas.graphics.beginGradientFill(GradientType.LINEAR, [topFill, bottomFill], [1, 1], [0, 255], fillMatrix, "pad");
            this.domBarCanvas.graphics.drawRect(centerWidth, centerHeight - 0, -domBarWidth, 12);
            this.domBarCanvas.graphics.endFill();

            // center spike
            this.domBarCanvas.graphics.lineStyle(4, 0xCCCCCC);
            this.domBarCanvas.graphics.moveTo(centerWidth, centerHeight + 16);
            this.domBarCanvas.graphics.lineTo(centerWidth, centerHeight - 4);
        }

    }

}

simplify dom bar

simplify dom bar


package krewfw.data_structure {

    /**
     * Simple priority queue (not so optimized.)
     * Reasonable data structures such as Heap, is not used yet.
     */
    //------------------------------------------------------------
    public class PriorityQueue {

        private var _queue:Vector.<PriorityNode>;
        private var _isDirty:Boolean;

        //------------------------------------------------------------
        public function PriorityQueue() {
            _queue   = new Vector.<PriorityNode>();
            _isDirty = false;
        }

        //------------------------------------------------------------
        // public
        //------------------------------------------------------------

        /**
         * Insert element with priority (small number is high priority.)
         */
        public function enqueue(priority:int, item:*):void {
            var pNode:PriorityNode = new PriorityNode(priority, item);
            _queue.push(pNode);
            _isDirty = true;
        }

        /**
         * Remove and get top-priority element. Multiple elements that have
         * same priority are returned in no particular order.
         * If queue is empty, return null.
         */
        public function dequeue():* {
            if (!_queue.length) { return null; }

            if (_isDirty) { _sort(); }
            return _queue.pop().item;
        }

        /**
         * Get top-priority element without removing it. Multiple elements that
         * have same priority are returned in no particular order.
         * If queue is empty, return null.
         */
        public function peek():* {
            if (!_queue.length) { return null; }

            if (_isDirty) { _sort(); }
            return _queue[_queue.length - 1].item;
        }

        /**
         * Clear the queue.
         */
        public function clear():void {
            for (var i:int = 0;  i < _queue.length; ++i) {
                _queue[i] = null;
            }
            _queue.length = 0;
            _isDirty      = false;
        }

        /**
         * Kill reference for GC.
         */
        public function dispose():void {
            clear();
            _queue = null;
        }

        /**
         * Get the number of elements of queue.
         */
        public function get length():int {
            return _queue.length;
        }

        //------------------------------------------------------------
        // private
        //------------------------------------------------------------

        private function _sort():void {
            _queue.sort(_sortFunc);
            _isDirty = false;
        }

        /**
         * Keep top-priority element at end of Array to use pop() instead of shift().
         */
        private function _sortFunc(a:PriorityNode, b:PriorityNode):int {
            if (a.priority == b.priority) { return 0; }
            return (a.priority > b.priority) ? -1 : 1;
        }

    }
}

//====================================================================
internal class PriorityNode {

    public var priority:int;
    public var item:*;

    public function PriorityNode(priority:int, item:*) {
        this.priority = priority;
        this.item     = item;
    }

}

package krewfw.data_structure {

    /**
     * Simple priority queue (not so optimized.)
     * Reasonable data structures such as Heap, is not used yet.
     */
    //------------------------------------------------------------
    public class PriorityQueue {

        private var _queue:Vector.<PriorityNode>;
        private var _isDirty:Boolean;

        public var verbose:Boolean = false;

        //------------------------------------------------------------
        public function PriorityQueue() {
            _queue   = new Vector.<PriorityNode>();
            _isDirty = false;
        }

        //------------------------------------------------------------
        // public
        //------------------------------------------------------------

        /**
         * Insert element with priority (small number is high priority.)
         */
        public function enqueue(priority:int, item:*):void {
            var pNode:PriorityNode = new PriorityNode(priority, item);
            _queue.push(pNode);
            _isDirty = true;

            if (verbose) {
                trace("[PriorityQueue :: enqueue] priority:", priority);
                dumpPriority();
            }
        }

        /**
         * Remove and get top-priority element. Multiple elements that have
         * same priority are returned in no particular order.
         * If queue is empty, return null.
         */
        public function dequeue():* {
            if (verbose) {
                trace("[PriorityQueue :: dequeue] length:", _queue.length);
            }
            if (!_queue.length) { return null; }

            if (_isDirty) { _sort(); }
            var topItem:* = _queue.pop().item;

            if (verbose) { dumpPriority(); }
            return topItem;
        }

        /**
         * Get top-priority element without removing it. Multiple elements that
         * have same priority are returned in no particular order.
         * If queue is empty, return null.
         */
        public function peek():* {
            if (!_queue.length) { return null; }

            if (_isDirty) { _sort(); }
            return _queue[_queue.length - 1].item;
        }

        /**
         * Clear the queue.
         */
        public function clear():void {
            for (var i:int = 0;  i < _queue.length; ++i) {
                _queue[i] = null;
            }
            _queue.length = 0;
            _isDirty      = false;
        }

        /**
         * Kill reference for GC.
         */
        public function dispose():void {
            clear();
            _queue = null;
        }

        /**
         * Get the number of elements of queue.
         */
        public function get length():int {
            return _queue.length;
        }

        //------------------------------------------------------------
        // private
        //------------------------------------------------------------

        private function _sort():void {
            _queue.sort(_sortFunc);
            _isDirty = false;
        }

        /**
         * Keep top-priority element at end of Array to use pop() instead of shift().
         */
        private function _sortFunc(a:PriorityNode, b:PriorityNode):int {
            if (a.priority == b.priority) { return 0; }
            return (a.priority > b.priority) ? -1 : 1;
        }

        //------------------------------------------------------------
        // debug
        //------------------------------------------------------------

        public function dumpPriority():void {
            var priorities:Array = [];
            for each (var item:PriorityNode in _queue) {
                priorities.push(item.priority);
            }
            trace(" -", priorities);
        }

    }
}

//====================================================================
internal class PriorityNode {

    public var priority:int;
    public var item:*;

    public function PriorityNode(priority:int, item:*) {
        this.priority = priority;
        this.item     = item;
    }

}

Modify priority queue: add debug trace

Modify priority queue: add debug trace