LogoLogo
  • Home
  • Projects
  • About
  • Contact

Active Window(S) Blur

Devon O. · July 06, 2008 · Actionscript, Flash · 12 comments
2

After taking another look at this post, I came up with a way of making multiple windows that will all blur the same image. I have to admit, though, I’m not particularly fond nor proud of the way I did it. The trouble is this: a masked display object can only have a single mask – so all items which will be used as a mask must be added to a single encompassing parent. But you would also like each mask item to be draggable along with the window it “rides behind”. Therefore, ideally, you’d like each mask item to be a child of the window instance (as I did it in the previous post). But there lies the rub. A display object can have only a single parent, hence you can’t add the child to both the mask and the window.

The solution I came up with was this: add the masking item to the mask instance and move the masking item with the window using an ENTER_FRAME event (rather than a parent-child relationship). If anyone has a more elegant solution, please post a comment. I’m probably overlooking something simple, but brilliant…

The MWindowBlur (Multiple Window Blur) class:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package com.onebyonedesign.extras {
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.DisplayObjectContainer;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.filters.BlurFilter;
    import flash.geom.Point;
    import flash.utils.Dictionary;
    
    /**
    * Allows creation of multiple windows that blur the same background image
    * @author Devon O.
    */
    public class MWindowBlur {
        
        private var _background:DisplayObjectContainer;
        private var _blurData:BitmapData;
        private var _blurImage:Bitmap;
        private var _blurAmount:int;
        private var _blur:BlurFilter;
        
        private var _mask:Sprite = new Sprite();
        private var _point:Point = new Point();
        private var _windows:Array = [];
        private var _maskDictionary:Dictionary = new Dictionary(true);
        
        public function MWindowBlur(background:DisplayObjectContainer, blurAmount:int = 8) {
            _background = background;
            _blurAmount = (blurAmount >= 0 && blurAmount <= 255) ? blurAmount : 8;
            _blur = new BlurFilter(_blurAmount, _blurAmount, 3);
            createBlur();
        }
        
        public function addWindow(window:DisplayObjectContainer):Boolean {
            if (_windows.indexOf(window) > -1) return false;
            
            var WindowClass:Class = Object(window).constructor;
            var m:DisplayObjectContainer = new WindowClass();
            m.transform = window.transform;
            m.filters = window.filters;
            if (window.scale9Grid) {
                m.scale9Grid = window.scale9Grid;
            }
            _maskDictionary[window] = m;
            _windows.push(window);
            
            if (!_mask.willTrigger(Event.ENTER_FRAME))
                _mask.addEventListener(Event.ENTER_FRAME, moveMask);
 
            _mask.addChild(m);
            
            if (!_background.contains(_mask))
                _background.addChild(_mask);
            
            return true;
        }
        
        public function removeWindow(window:DisplayObjectContainer = null):Boolean {
            if (!_windows.length) return false;
            
            if (!window) return removeWindow(_windows[_windows.length - 1]);
            
            var index:int = _windows.indexOf(window);
            if (index < 0) return false;
            
            _windows.splice(index, 1);
            _mask.removeChild(_maskDictionary[window]);
            if (!_windows.length)
                _mask.removeEventListener(Event.ENTER_FRAME, moveMask);
            
            return true;
        }
        
        public function kill():void {
            if (_mask.willTrigger(Event.ENTER_FRAME))
                _mask.removeEventListener(Event.ENTER_FRAME, moveMask);
            
            if (_background.contains(_mask))
                _background.removeChild(_mask);
                
            if (_background.contains(_blurImage))
                _background.removeChild(_blurImage);
                
            _blurData.dispose();
            
            _blurImage = null;
            _blurData = null;
            _maskDictionary = null;
            _background = null;
            _blur = null;
        }
        
        public function get blurAmount():int { return _blurAmount; }
        
        public function set blurAmount(value:int):void {
            _blurAmount = value;
            createBlur();
        }
        
        private function createBlur():void {
            if (_blurData) _blurData.dispose();
            _blur.blurX = _blur.blurY = _blurAmount;
            _blurData = new BitmapData(_background.width, _background.height, false);
            _blurData.draw(_background);
            _blurData.applyFilter(_blurData, _blurData.rect, _point, _blur);
            _blurImage = new Bitmap(_blurData);
            _blurImage.mask = _mask;
            _background.addChild(_blurImage);
        }
        
        private function moveMask(event:Event):void {
            var i:int = _windows.length;
            while (i--) {
                var w:DisplayObjectContainer = _windows[i];
                var m:DisplayObjectContainer = _maskDictionary[w];
                m.transform = w.transform;
            }
        }
    }
}

The Flash document class for a test ride:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package {
    
    import com.onebyonedesign.extras.MWindowBlur;
    import com.onebyonedesign.ui.OBO_ValueSlider;
    import com.onebyonedesign.ui.events.ValueSliderEvent;
    import fl.controls.Button;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.filters.DropShadowFilter;
    import flash.text.AntiAliasType;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
    
    /**
    * Demonstrates MWindowBlur (for multiple windows) Class
    * @author Devon O.
    */
    public class Main extends Sprite {
        
        // GraphicWindow is MovieClip in .fla library
        private var _activeWindow:GraphicWindow;
        // Background is MovieClip in .fla library
        private var _bg:Background;
        private var _windowBlur:MWindowBlur;
        private var _shadow:DropShadowFilter = new DropShadowFilter(2, 90, 0x000000, 1, 2, 2, 1, 3);
        private var _windowArray:Array = [];
        
        public function Main():void {
            // Background is MovieClip in .fla library
            _bg = new Background();
            addChild(_bg);
            init();
        }
        
        private function init():void {
            initBlur();
            initControlPanel();
            addWindow();
        }
        
        private function initBlur():void {
            _windowBlur = new MWindowBlur(_bg);
        }
        
        private function initControlPanel():void {
            var cp:Sprite = new Sprite();
            cp.graphics.beginFill(0xEAEAEA);
            cp.graphics.drawRoundRect(0, 0, 222, 70, 10, 10);
            cp.graphics.endFill();
            cp.filters = [_shadow];
            cp.x = 10;
            cp.y = stage.stageHeight - cp.height - 10;
            
            var tf:TextField = new TextField();
            var fmt:TextFormat = new TextFormat("_sans", 11);
            tf.defaultTextFormat = fmt;
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.selectable = false;
            tf.mouseEnabled = false;
            tf.antiAliasType = AntiAliasType.ADVANCED;
            tf.text = "Blur amount:";
            tf.x = 5;
            tf.y = 5;
            cp.addChild(tf);
            
            var blurSlider:OBO_ValueSlider = new OBO_ValueSlider(139, 0, 32, _windowBlur.blurAmount);
            blurSlider.x = tf.x + tf.textWidth + 8;
            blurSlider.y = 13;
            blurSlider.addEventListener(ValueSliderEvent.DRAG, blurChangeHandler);
            cp.addChild(blurSlider);
            
            var b1:Button = new Button();
            b1.label = "Add Window";
            b1.x = 5;
            b1.y = 40;
            b1.addEventListener(MouseEvent.CLICK, addWindow);
            cp.addChild(b1);
            
            var b2:Button = new Button();
            b2.label = "Remove Window";
            b2.x = b1.x + b1.width + 10;
            b2.y = 40;
            b2.addEventListener(MouseEvent.CLICK, removeWindow);
            cp.addChild(b2);
            
            addChild(cp);
        }
        
        private function addWindow(event:MouseEvent = null):void {
            // GraphicWindow is MovieClip in library
            var window:GraphicWindow = new GraphicWindow();
            window.width = randRange(50, 300);
            window.height = randRange(50, 200);
            
            window.x = randRange(0, 500 - window.width);
            window.y = randRange(0, 500 - window.height);
            window.filters = [_shadow];
            
            _windowArray.push(window);
            
            addChild(window);
            
            _windowBlur.addWindow(window);
            window.addEventListener(MouseEvent.MOUSE_DOWN, pressHandler);
        }
        
        private function removeWindow(event:MouseEvent):void {
            if (_windowArray.length) {
                _windowBlur.removeWindow();
                removeChild(_windowArray.pop());
            }
        }
        
        private function blurChangeHandler(event:ValueSliderEvent):void {
            _windowBlur.blurAmount = int(event.value);
        }
        
        private function pressHandler(event:MouseEvent):void {
            _activeWindow = event.currentTarget as GraphicWindow;
            addChild(_activeWindow);
            stage.addEventListener(MouseEvent.MOUSE_UP, releaseHandler);
            _activeWindow.startDrag(false);
        }
        
        private function releaseHandler(event:MouseEvent):void {
            stage.removeEventListener(MouseEvent.MOUSE_UP, releaseHandler);
            _activeWindow.stopDrag();
        }
        
        private function randRange(min:Number, max:Number):Number {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
    }
}

And a quick example:

  Facebook   Pinterest   Twitter   Google+
  • Using Attributes for Property Validation
    December 24, 2019 · 0 comments
    <p>Programmers are always looking for ways to write safer more bullet proof
    1651
    5
    Read more
  • Getting Started with Proscenium
    October 09, 2011 · 13 comments
    5142
    5
    Read more
  • Papervision3d + As3dmod = Twisty Cubes
    May 30, 2009 · 10 comments
    3680
    3
    Read more
12 Comments:
  1. Very nice. A couple suggestions:

    1) When two windows are layered, it would be nice if the front window blurred the one behind it.
    2) Presently, the blur amount seems to be a global value. Can it be set for each window individually?

    Awesome job.

    Tom Lee · July 15, 2008
  2. I appreciate you taking the time to create this example. I am trying to build this, but, as a newbie to AS, I am having some trouble. I can’t seem to resolve the Background or GraphicWindow data type. Any suggestions?

    Steve · August 25, 2008
  3. Hey Steve,
    Both items are MovieClips inside the .fla library. Once you have an object in the library, you can right click it and pick “linkage” from the context menu. Check the “Export for actionscript” box, leave the other boxes alone and in the Class textbox just put “Background” (for the image you want to be blurred) or “GraphicWindow” (for the window you want to drag around). Hope that helps out..

    Devon O. · August 25, 2008
  4. Devon,

    Could you please post a .ZIP with the ActiveBlur class, FLA, and its corresponding document class?

    Cheers!

    Skye · August 28, 2008
  5. Well, there’s really no more than what’s posted above, but since so many are asking, you can get the .fla that created the above .swf here. You’ll also need the ui package mentioned in this post to create the value slider control above – but the package isn’t necessary for general usage of the MWindowBlur class.

    Devon O. · August 28, 2008
  6. Hi, I’ve put together a really simple timeline example to try and get this working (before trying it on a more complicated project), but it doesn’t seem to be working… can you see any reason why?

    ////////////////////////////////////////////////////////////////////////////////

    import com.onebyonedesign.extras.*;

    var bg:Sprite = new Sprite();
    var matr:Matrix = new Matrix();
    matr.createGradientBox(200, 50, 20, -50, 200);
    bg.graphics.beginGradientFill(“linear”, [0xff0000, 0x00ff00], [1,1], [150,255], matr);
    bg.graphics.drawRoundRect(100,20,200,250,20);
    bg.graphics.endFill();
    addChild(bg);

    var blur:MWindowBlur=new MWindowBlur(bg,100);

    var box:Sprite = new Sprite();
    box.graphics.beginFill(0x0000ff, 0.5);
    box.graphics.drawRect(0,0,100,100);
    box.graphics.endFill();
    addChild(box);

    box.addEventListener(MouseEvent.MOUSE_DOWN, drag);

    blur.addWindow(box);

    function drag(e:Event) {
    box.removeEventListener(MouseEvent.MOUSE_DOWN, drag);
    box.addEventListener(MouseEvent.MOUSE_UP, drop);
    box.startDrag();
    }//drag

    function drop(e:Event) {
    box.addEventListener(MouseEvent.MOUSE_DOWN, drag);
    box.removeEventListener(MouseEvent.MOUSE_UP, drop);
    box.stopDrag();
    }//drag

    Chrs · April 15, 2009
  7. Hey Chris. There’s a couple things causing the problem. For some reason, the blur windows cannot be created programmatically – they have to be exported from the library or on the stage. So, if you make your box a class in the library, that will take care of the biggest problem. The other thing is that the background object should be aligned to the origin (0,0). Do those two things and it should work fine.

    Devon O. · April 15, 2009
  8. Hey Devon’! This is awesome, but I don’t understand how I can use this, in my document? Should I’ve two movieclips, one background and one window-route in the .fla project? And how do I use the actions you have posted? Should I paste it in a normal keyframe in “actions” (by pressing F9)?
    Would you please make a short video how you do this? :)

    vb · April 27, 2011
  9. I need same thing to be done in AS3

    Pankaj Kumar · May 31, 2011
  10. Pankaj Kumar really nice comment! Maybe you need someone to read this post for you. =P

    am · August 28, 2011

Leave a Comment! Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Devon O. Wolfgang

AIR | Unity3D | AR/VR

Unity Certified Developer

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development” and “Starling Game Development Essentials”

Reviewer of “The Starling Handbook”

Unity Engineer at Touch Press.

Categories
  • Actionscript (95)
  • AIR (16)
  • Flash (99)
  • Games (7)
  • Liberty (13)
  • Life (53)
  • Shaders (20)
  • Unity3D (21)
Recent Comments
  • MainDepth on Unity Ripple or Shock Wave Effect
  • Devon O. on Unity Ripple or Shock Wave Effect
  • Feral_Pug on Unity Ripple or Shock Wave Effect
  • bavvireal on Unity3D Endless Runner Part I – Curved Worlds
  • Danielius Vargonas on Custom Post Processing with the LWRP
Archives
  • December 2020 (1)
  • December 2019 (1)
  • September 2019 (1)
  • February 2019 (2)
  • December 2018 (1)
  • July 2018 (1)
  • June 2018 (1)
  • May 2018 (2)
  • January 2018 (1)
  • December 2017 (2)
  • October 2017 (1)
  • September 2017 (2)
  • January 2017 (1)
  • July 2016 (1)
  • December 2015 (2)
  • March 2015 (1)
  • September 2014 (1)
  • January 2014 (1)
  • August 2013 (1)
  • July 2013 (1)
  • May 2013 (1)
  • March 2013 (2)
  • December 2012 (1)
  • November 2012 (1)
  • September 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (1)
  • December 2011 (2)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (1)
  • May 2011 (2)
  • April 2011 (2)
  • March 2011 (1)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (3)
  • October 2010 (5)
  • September 2010 (1)
  • July 2010 (2)
  • May 2010 (5)
  • April 2010 (2)
  • March 2010 (7)
  • February 2010 (5)
  • January 2010 (5)
  • December 2009 (3)
  • November 2009 (1)
  • October 2009 (5)
  • September 2009 (5)
  • August 2009 (1)
  • July 2009 (1)
  • June 2009 (2)
  • May 2009 (6)
  • April 2009 (4)
  • March 2009 (2)
  • February 2009 (4)
  • January 2009 (1)
  • December 2008 (5)
  • November 2008 (2)
  • September 2008 (1)
  • August 2008 (6)
  • July 2008 (6)
  • June 2008 (9)
  • May 2008 (4)
  • April 2008 (3)
  • March 2008 (4)
  • February 2008 (9)
  • January 2008 (7)
  • December 2007 (6)
Copyright © 2021 Devon O. Wolfgang