{"id":347,"date":"2009-07-16T09:19:31","date_gmt":"2009-07-16T16:19:31","guid":{"rendered":"https:\/\/actionsnippet.com\/?p=1767"},"modified":"2009-07-16T09:19:31","modified_gmt":"2009-07-16T16:19:31","slug":"setvector-vs-copypixels","status":"publish","type":"post","link":"https:\/\/actionsnippet.com\/?p=347","title":{"rendered":"setVector vs copyPixels"},"content":{"rendered":"<pre class=\"brush: as3; title: ; notranslate\" title=\"\">\r\nvar brushNum:int = 10000;\r\nvar canvas:BitmapData = new BitmapData(800,600,false, 0x000000);\r\naddChild(new Bitmap(canvas));\r\n\r\nvar shape:Shape = new Shape();\r\nwith(shape.graphics) beginFill(0xFF0000), drawCircle(10,10,5);\r\nshape.filters = &#x5B;new BlurFilter(6, 6, 4)];\r\n\r\nvar brush:BitmapData = new BitmapData(20, 20, false, 0x000000);\r\nbrush.draw(shape, shape.transform.matrix);\r\n\r\n \r\n \r\n\/\/ make sure brushVect is fixed length\r\nvar brushVect:Vector.&lt;uint&gt; = new Vector.&lt;uint&gt;(brush.width * brush.height, true);\r\nvar tempVect:Vector.&lt;uint&gt; =  brush.getVector(brush.rect);\r\nvar i:int = 0;\r\n\/\/ quick hack to retain fixed length\r\nfor (i = 0; i&lt;brushVect.length; i++){\r\n\tbrushVect&#x5B;i] = tempVect&#x5B;i];\r\n}\r\n \r\ncanvas.setVector(brush.rect, brushVect);\r\n\r\nvar pnt:Point = new Point();\r\nvar brushRect:Rectangle = brush.rect;\r\nvar destRect:Rectangle = brushRect.clone();\r\nvar locX:Vector.&lt;Number&gt; = new Vector.&lt;Number&gt;(brushNum, true);\r\nvar locY:Vector.&lt;Number&gt; = new Vector.&lt;Number&gt;(brushNum, true);\r\nfor (i= 0; i&lt;brushNum; i++){\r\n\tlocX&#x5B;i] = Math.random() * stage.stageWidth - 10;\r\n\tlocY&#x5B;i] = Math.random() * stage.stageHeight - 10;\r\n}\r\n\r\nvar iterations:int = 50;\r\nvar timer:Number;\r\nvar avg:Vector.&lt;Number&gt; = new Vector.&lt;Number&gt;();\r\ntrace(&quot;copyPixels&quot;);\r\naddEventListener(Event.ENTER_FRAME, onLoop);\r\nfunction onLoop(evt:Event):void {\r\n\t   canvas.fillRect(canvas.rect, 0x000000);\r\n\t   var i:int = brushNum;\r\n\t   if (drawMode == &quot;copyPixels&quot;){\r\n\t\t   timer = getTimer();\r\n\t\t   canvas.lock();\r\n\t\t   while(--i &gt; -1){\r\n\t\t\t\tpnt.x = locX&#x5B;i];\r\n\t\t\t\tpnt.y = locY&#x5B;i];\r\n\t\t\t\t\/\/ copyPixels can easily do alpha manipulation, setVector cannot (see comment below);\r\n\t\t\t\tcanvas.copyPixels(brush, brushRect, pnt);\/\/, null, null, true);\r\n\t\t   }\r\n\t\t   canvas.unlock();\r\n\t\t   avg.push(getTimer() - timer);\r\n\t   }else{\r\n\t\t   timer = getTimer();\r\n\t\t   canvas.lock();\r\n\t\t   while(--i&gt; -1){\r\n\t\t\t   destRect.x = locX&#x5B;i];\r\n\t\t\t   destRect.y = locY&#x5B;i];\r\n\t\t\t   canvas.setVector(destRect, brushVect);\r\n\t\t   }\r\n\t\t   canvas.unlock();\r\n\t\t   avg.push(getTimer() - timer);\r\n\t   }\r\n\t   \/\/ take an average of iterations iterations\r\n\t   if (avg.length == iterations){\r\n\t\t   var average:Number = 0;\r\n\t\t   for (i = 0; i&lt;iterations; i++){\r\n\t\t\t     average += avg&#x5B;i];\r\n\t\t   }\r\n\t\t   trace(average \/ iterations);\r\n\t\t   avg = new Vector.&lt;Number&gt;();\r\n\t   }\r\n}\r\n\r\nvar drawMode:String = &quot;copyPixels&quot;;\r\nstage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased);\r\nfunction onKeyReleased(evt:Event):void{\r\n\tavg = new Vector.&lt;Number&gt;();\r\n\tdrawMode = (drawMode == &quot;copyPixels&quot;) ? &quot;setVector&quot; : &quot;copyPixels&quot;\r\n\ttrace(drawMode);\r\n}\r\n<\/pre>\n<p>In the comments of a <a href=\"https:\/\/actionsnippet.com\/?p=1760#comments\">post from a few days back<\/a>, <a href=\"http:\/\/www.flashfuck.it\/\">Piergiorgio Niero<\/a> mentioned that setVector may be faster than copyPixels. To see if this was true,  Piergiorgio and I each tried a few things and while Piergiorgio seemed to reach some conclusions&#8230; I wasn&#8217;t sure we had properly tested to see which one was actually faster.<\/p>\n<p>I created the above snippet to help test to see which is indeed faster. This snippet draws 10,000 small  20&#215;20 pixel graphics to the stage. There is no animation because I wanted to try and isolate the speed of the setVector and copyPixels calls. These are the results on my macbook pro 2.4 ghz duo:<\/p>\n<p>\/\/ average speed of 50 iterations of drawing<br \/>\ncopyPixels<br \/>\n15.1<br \/>\n15.68<br \/>\n15.44<br \/>\n15.46<br \/>\n15.62<br \/>\n15.74<br \/>\n15.68<br \/>\nsetVector<br \/>\n32.6<br \/>\n32.6<br \/>\n31.1<br \/>\n32.1<br \/>\n32.82<br \/>\n32.54<br \/>\ncopyPixels<br \/>\n15.48<br \/>\n15.62<br \/>\n15.74<br \/>\n15.46<br \/>\n15.42<br \/>\n15.44<br \/>\n15.64<br \/>\nsetVector<br \/>\n32.62<br \/>\n32.8<br \/>\n33.08<br \/>\n32.48<br \/>\n32.74<br \/>\n32.32<\/p>\n<p>If you interested in this, post your results in the comments along with the type of computer you&#8217;re using. I have a feeling there will be a wide variety of results&#8230; just make sure you&#8217;re not using the flash debug player, as that can act significantly different than the release version of the player.<\/p>\n<h1>setVector() and copyPixels() Usage<\/h1>\n<p>Something to note here is that setVector and copyPixels aren&#8217;t normally suitable for the same thing. copyPixels is used to move a rectangle of pixels from one BitmapData to another &#8211; you can easily do advanced alpha channel manipulation and scaling with it and you don&#8217;t have to do pixel by pixel logic. setVector is used to do pixel by pixel manipulation &#8211; it is a sort of mature\/advanced setPixel function that allows you to do logic on a Vector of uints and then set the pixels of a rectangular region of a BitmapData object equal to the data within that Vector. So if you need to do alpha manipulation or image scaling with setVector you&#8217;ll find yourself running into some more advanced programming than copyPixels requires&#8230; and if you tried to do pixel by pixel manipulation with copyPixels&#8230; well, that just isn&#8217;t what it was meant to be used for&#8230;<\/p>\n<p>I&#8217;m always wary of these kind of speed tests&#8230; if anyone has suggestions about how to improve this test, please feel free to comment.<\/p>\n<p>UPDATE <a href=\"http:\/\/sleepydesign.com\/\">katopz<\/a> pointed out I should use fixed length Vectors&#8230; so I changed the brushVect instantiation code slightly. I didn&#8217;t do it for the avg vector because it only has 50 values and it doesn&#8217;t help improve the speed of setVector and copyPixels in any way and complicates the code slightly&#8230; it&#8217;s hard to decide which optimization techniques you should choose to make habbit and which ones you should only whip out when you need speed&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>var brushNum:int = 10000; var canvas:BitmapData = new BitmapData(800,600,false, 0x000000); addChild(new Bitmap(canvas)); var shape:Shape = new Shape(); with(shape.graphics) beginFill(0xFF0000), drawCircle(10,10,5); shape.filters = &#x5B;new BlurFilter(6, 6, 4)]; var brush:BitmapData = new BitmapData(20, 20, false, 0x000000); brush.draw(shape, shape.transform.matrix); \/\/ make sure brushVect is fixed length var brushVect:Vector.&lt;uint&gt; = new Vector.&lt;uint&gt;(brush.width * brush.height, true); var tempVect:Vector.&lt;uint&gt; = brush.getVector(brush.rect); [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,79],"tags":[],"class_list":["post-347","post","type-post","status-publish","format-standard","hentry","category-bitmapdata","category-vector"],"_links":{"self":[{"href":"https:\/\/actionsnippet.com\/index.php?rest_route=\/wp\/v2\/posts\/347","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/actionsnippet.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/actionsnippet.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/actionsnippet.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/actionsnippet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=347"}],"version-history":[{"count":0,"href":"https:\/\/actionsnippet.com\/index.php?rest_route=\/wp\/v2\/posts\/347\/revisions"}],"wp:attachment":[{"href":"https:\/\/actionsnippet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=347"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/actionsnippet.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=347"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/actionsnippet.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=347"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}