{"id":209,"date":"2011-03-10T01:30:43","date_gmt":"2011-03-09T20:00:43","guid":{"rendered":"http:\/\/techtwaddle.net\/2011\/03\/10\/windows-phone-7-translation-rotation-scaling-and-the-effect-of-bitmapcache-on-performance\/"},"modified":"2011-03-10T02:12:31","modified_gmt":"2011-03-09T20:42:31","slug":"windows-phone-7-translation-rotation-scaling-and-the-effect-of-bitmapcache-on-performance","status":"publish","type":"post","link":"https:\/\/techtwaddle.co.in\/blog\/2011\/03\/10\/windows-phone-7-translation-rotation-scaling-and-the-effect-of-bitmapcache-on-performance\/","title":{"rendered":"Windows Phone 7: Translation, rotation, scaling and the effect of &lsquo;BitmapCache&rsquo; on performance"},"content":{"rendered":"<p style=\"text-align: justify;\">One thing that was pending on my \u201ctodo&#8221; list from a long time was implementing the \u2018<a href=\"http:\/\/en.wikipedia.org\/wiki\/Conway%27s_Game_of_Life\">Game Of Life<\/a>\u2019 on Windows Phone 7. I got the basic version running in a couple of hours and I\u2019ve been thinking about improving it since and adding new features to it. Maybe I\u2019ll submit it to the marketplace someday, who knows. I have also been reading about gestures, multi-touch, pinch-to-zoom and related topics and most importantly trying to understand the math behind each of those gestures, and the math is so elegant that it fascinates me!<\/p>\n<p style=\"text-align: justify;\"><strong>Game Of Life<\/strong><br \/>\n<a href=\"http:\/\/en.wikipedia.org\/wiki\/Conway%27s_Game_of_Life\">Game Of Life<\/a> is a simple cellular automaton in which you create a pattern in a world made of rectangular grids, start the evolution process and then watch the pattern change as the world evolves. The world is made up of dead cells initially, you create a pattern by selecting a few cells and giving them \u201clife\u201d. The world then evolves according to a set of rules (source: <a href=\"http:\/\/en.wikipedia.org\/wiki\/Conway%27s_Game_of_Life#Rules\">Wikipedia<\/a>):<\/p>\n<ol>\n<li>Any live cell with fewer than two live neighbours dies, as if caused by under-population.<\/li>\n<li>Any live cell with two or three live neighbours lives on to the next generation.<\/li>\n<li>Any live cell with more than three live neighbours dies, as if by overcrowding.<\/li>\n<li>Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.<\/li>\n<\/ol>\n<p style=\"text-align: justify;\">It\u2019s a fascinating concept and some <a href=\"http:\/\/en.wikipedia.org\/wiki\/Conway%27s_Game_of_Life#Examples_of_patterns\">very interesting patterns<\/a> emerge out of it, read more about Game Of Life on Wikipedia <a href=\"http:\/\/en.wikipedia.org\/wiki\/Conway%27s_Game_of_Life\">here<\/a>.<\/p>\n<p style=\"text-align: justify;\"><strong>Gestures<\/strong><br \/>\nGestures like translation, scaling and rotation seemed complex to me at first, but they\u2019re pretty simple once you understand the math that makes the magic happen. I came across two great articles that really dig deep into these concepts. Both articles use the <a href=\"http:\/\/silverlight.codeplex.com\/\">Silverlight Toolkit for Windows Phone 7<\/a> and the gesture support that it provides. I was a little surprised to know that the silverlight toolkit actually uses XNA\u2019s touch api\u2019s to detect gestures. These are the articles that you must read:<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/msdn.microsoft.com\/hi-in\/magazine\/gg650664%28en-us%29.aspx\">MSDN Magazine : Touch Gestures on Windows Phone by Charles Petzold<\/a>. This is the implementation I chose to use in my app Game Of Life. The code is available for download in the article.<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/www.frenk.com\/2011\/03\/windows-phone-7-correct-pinch-zoom-in-silverlight\/\">Windows Phone 7: Correct pinch zoom in silverlight by Francesco De Vittori<\/a>. I was using this before I stumbled on Charles\u2019 article :) Also, Charles\u2019 implementation seemed more intuitive to me.<\/p>\n<p style=\"text-align: justify;\">Charles Petzolds\u2019 implementation makes use of Matrix transforms. It took me some time to understand matrix transforms and realize their importance in 2D\/3D graphics. The only time I used matrix multiplication was to solve silly linear equations in college. You\u2019ll find many a articles on the internet about matrix transforms but the best resource I found again comes from Charles Petzold. <em><strong>Chapter 22 \u2013 From Gestures to Transforms<\/strong><\/em> in his free book <a href=\"http:\/\/www.charlespetzold.com\/phone\/index.html\">Programming Windows Phone 7<\/a>. Download it now if you haven\u2019t already, it\u2019s a great resource.<\/p>\n<p style=\"text-align: justify;\">The two paths had to meet. Using gestures in Game Of Life was the best way to learn them.<\/p>\n<p style=\"text-align: justify;\">In my first implementation of Game Of Life, I used the Manipulation Delta events to support pinch-to-zoom. In this I used the <em>DeltaManipulation.Scale.X<\/em> and <em>DeltaManipulation.Scale.Y<\/em> values in the <em>ManipulationDeltaEventArgs<\/em> class (passed to the <em>ManipulationDelta<\/em> event handler) to modify the <em>ScaleX<\/em> and <em>ScaleY<\/em> values of a Scale transform on the object to be scaled. If that sentence didn\u2019t make sense, don\u2019t worry, this is the easiest and the worst implementation of pinch-to-zoom. The scaling was not smooth or accurate. To understand what a perfect pinch-to-zoom should be read this \u2013 <a href=\"http:\/\/adtsai.blogspot.com\/2010\/09\/pinch-zooming-using-xna4-on-wp7-getting.html\">Pinch Zooming using XNA on WP7: Getting it right<\/a>. The article explains this with reference to XNA but the concept remains the same everywhere.<\/p>\n<p style=\"text-align: justify;\">In my second attempt I used the <a href=\"http:\/\/silverlight.codeplex.com\/\">Silverlight Toolkit for Windows Phone<\/a> and <a href=\"http:\/\/www.frenk.com\/2011\/03\/windows-phone-7-correct-pinch-zoom-in-silverlight\/\">Francesco\u2019s implementation<\/a> of pinch-to-zoom. It was working pretty nicely with a few quirks here and there. Though the implementation is easy to understand, I felt there were too many variables used for storing state information and the code looked a bit messy, but it worked.<\/p>\n<p style=\"text-align: justify;\">It is while tuning this implementation that the MSDN Magazine article was published. Charles Petzold\u2019s implementation felt intuitive and was much cleaner. The only part I had to figure out was the matrix transforms he used. And that I\u2019ll explain a bit here.<\/p>\n<p style=\"text-align: justify;\">This is what the app looks like,<\/p>\n<p><a href=\"https:\/\/www.techtwaddle.co.in\/blog\/wp-content\/uploads\/2011\/03\/gameoflife.jpg\"><img decoding=\"async\" loading=\"lazy\" style=\"display: inline; border: 0px;\" title=\"game-of-life\" src=\"https:\/\/www.techtwaddle.co.in\/blog\/wp-content\/uploads\/2011\/03\/gameoflife_thumb.jpg\" border=\"0\" alt=\"game-of-life\" width=\"275\" height=\"484\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">The rectangular grids are added programmatically to a canvas. Here is the XAML for the canvas,<\/p>\n<p><span style=\"color: #000080;\"><\/p>\n<pre lang=\"xml\">\r\n<Canvas Canvas.Left=\"0\" Canvas.Top=\"0\" Height=\"736\" Name=\"MainCanvas\"\r\n        Width=\"480\" Background=\"Aqua\" Canvas.ZIndex=\"-1\">\r\n\r\n    <Canvas.RenderTransform>\r\n        <TransformGroup>\r\n            <MatrixTransform x:Name=\"previousTransform\"\/>\r\n\r\n            <TransformGroup x:Name=\"currentTransform\">\r\n                <ScaleTransform x:Name=\"scaleTransform\"\/>\r\n                <RotateTransform x:Name=\"rotateTransform\"\/>\r\n                <TranslateTransform x:Name=\"translateTransform\"\/>\r\n            <\/TransformGroup>\r\n\r\n        <\/TransformGroup>\r\n    <\/Canvas.RenderTransform>\r\n\r\n<\/Canvas>\r\n<\/pre>\n<p><\/span><\/p>\n<p style=\"text-align: justify;\">So during the Drag Delta and Pinch Delta events the transforms under <em>currentTransform<\/em> are manipulated to achieve the desired effect and once the drag or pinch gestures are completed a function, <em>TransferTransforms()<\/em>, is called:<\/p>\n<p><span style=\"color: #000080;\"> <\/span><\/p>\n<pre escaped=\"true\" lang=\"csharp\">void TransferTransforms()\r\n{\r\n    previousTransform.Matrix = Multiply(previousTransform.Matrix, currentTransform.Value);\r\n\r\n    \/\/Set current transforms to default values\r\n    scaleTransform.ScaleX = scaleTransform.ScaleY = 1;\r\n    scaleTransform.CenterX = scaleTransform.CenterY = 0;\r\n\r\n    rotateTransform.Angle = 0;\r\n    rotateTransform.CenterX = rotateTransform.CenterY = 0;\r\n\r\n    translateTransform.X = translateTransform.Y = 0;\r\n}<\/pre>\n<p><span style=\"color: #000080;\"> <\/span><\/p>\n<p><span style=\"color: #000080;\"><\/p>\n<pre escaped=\"true\" lang=\"csharp\">Matrix Multiply(Matrix A, Matrix B)\r\n{\r\n    return new Matrix(A.M11 * B.M11 + A.M12 * B.M21,\r\n            A.M11 * B.M12 + A.M12 * B.M22,\r\n            A.M21 * B.M11 + A.M22 * B.M21,\r\n            A.M21 * B.M12 + A.M22 * B.M22,\r\n            A.OffsetX * B.M11 + A.OffsetY * B.M21 + B.OffsetX,\r\n            A.OffsetX * B.M12 + A.OffsetY * B.M22 + B.OffsetY);\r\n}<\/pre>\n<p><\/span><\/p>\n<p style=\"text-align: justify;\">To understand what is happening here we need to look at the XAML first. The <em>RenderTransform<\/em> on the <em>MainCanvas<\/em> is a double-barrelled (term used by Charles in his article) transform. Basically, a transform group within a transform group. So the effective transform on <em>MainCanvas<\/em> is equal to the effect of <em>previousTransform<\/em> plus the effect of <em>currentTransform<\/em>. Well, it\u2019s not exactly \u201cplus\u201d. First, <em>previousTransform<\/em> is applied on <em>MainCanvas<\/em> to change its state, and then <em>currentTransform<\/em> is applied on that state to change it further. If you <a href=\"http:\/\/msdn.microsoft.com\/hi-in\/magazine\/gg650664%28en-us%29.aspx\">download<\/a> and look into Charles\u2019 code, you\u2019ll see that during drag delta and pinch delta events, only <em>currentTransform<\/em> values are modified. Once the drag or pinch gesture is complete, <em>TransferTransform()<\/em> is called to \u201ctransfer\u201d the values of <em>currentTransform<\/em> to <em>previousTransform<\/em>. And this transfer happens by the way of matrix multiplication, which is what the function <em>Mulitply()<\/em> does. It\u2019s not over yet. After the multiplication the values of <em>currentTransform<\/em> (i.e <em>scaleTransform<\/em>, <em>rotateTransform<\/em> and <em>translateTransform<\/em>) are reset. This is important because, as we discussed before, the effective transform on <em>MainCanvas<\/em> is effect of <em>previousTransform<\/em> \u201cplus\u201d the effect of <em>currentTransform<\/em>. Transferring the values of <em>currentTransform<\/em> to <em>previousTransform<\/em> and then resetting <em>currentTransform<\/em> keeps the effect same.<\/p>\n<p style=\"text-align: justify;\"><strong>CacheMode and BitmapCache<\/strong><br \/>\nNow I got the translation, scaling and rotation to work correctly, but the performance was not very great. There was a huge lag in pinching and dragging, and this is where <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.media.bitmapcache.aspx\">BitmapCache<\/a> comes in. Every <em>UIElement<\/em> has a property called <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.uielement.cachemode.aspx\">CacheMode<\/a>, which can be set to <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.media.bitmapcache.aspx\">BitmapCache<\/a>.<\/p>\n<p style=\"text-align: justify;\">In XAML, <em>CacheMode=\u201dBitmapCache\u201d<\/em><\/p>\n<p style=\"text-align: justify;\">In code, <em>uiElem.CacheMode = new BitmapCache();<\/em><\/p>\n<p style=\"text-align: justify;\">When the CacheMode of a <em>UIElement<\/em> is set to BitmapCache, a snapshot of the <em>UIElement<\/em> is taken and is stored in the video memory. So the element is not redrawn every time, instead all the operations are performed on the cached bitmap. This is super fast and is particularly useful when working with transforms on controls. Change the <em>MainCanvas<\/em> element in the XAML to include <em>CacheMode<\/em>,<\/p>\n<p><span style=\"color: #000080;\"><\/p>\n<pre lang=\"xml\">\r\n<Canvas Canvas.Left=\"0\" Canvas.Top=\"0\" Height=\"736\" Name=\"MainCanvas\"\r\n        Width=\"480\" Background=\"Aqua\" Canvas.ZIndex=\"-1\" CacheMode=\u201dBitmapCache\u201d> \r\n<\/pre>\n<p><\/span><\/p>\n<p style=\"text-align: justify;\">and this will have a dramatic effect on the performance as you will see in the video below.<\/p>\n<p><object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"480\" height=\"390\" codebase=\"http:\/\/download.macromedia.com\/pub\/shockwave\/cabs\/flash\/swflash.cab#version=6,0,40,0\"><param name=\"allowFullScreen\" value=\"true\" \/><param name=\"allowscriptaccess\" value=\"always\" \/><param name=\"src\" value=\"http:\/\/www.youtube.com\/v\/4_xHnwYJt-k?fs=1&amp;hl=en_US&amp;rel=0\" \/><param name=\"allowfullscreen\" value=\"true\" \/><\/object><\/p>\n<p style=\"text-align: justify;\">Please leave a comment if you have anything else to add.<\/p>\n<p>Until next time..<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One thing that was pending on my \u201ctodo&#8221; list from a long time was implementing the \u2018Game Of Life\u2019 on Windows Phone 7. I got the basic version running in a couple of hours and I\u2019ve been thinking about improving it since and adding new features to it. Maybe I\u2019ll submit it to the marketplace &hellip; <a href=\"https:\/\/techtwaddle.co.in\/blog\/2011\/03\/10\/windows-phone-7-translation-rotation-scaling-and-the-effect-of-bitmapcache-on-performance\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Windows Phone 7: Translation, rotation, scaling and the effect of &lsquo;BitmapCache&rsquo; on performance<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false},"categories":[7,10,6,3,5],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p1ktFF-3n","_links":{"self":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts\/209"}],"collection":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/comments?post=209"}],"version-history":[{"count":4,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts\/209\/revisions"}],"predecessor-version":[{"id":210,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/posts\/209\/revisions\/210"}],"wp:attachment":[{"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/media?parent=209"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/categories?post=209"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techtwaddle.co.in\/blog\/wp-json\/wp\/v2\/tags?post=209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}