<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2077469061561410808</id><updated>2012-02-11T18:48:33.137+01:00</updated><category term='Web development'/><category term='Physics Game'/><category term='Mathematics'/><category term='XNA'/><category term='Optimization'/><category term='Game mechanics'/><category term='Physics'/><title type='text'>Whatever Crossed My Mind</title><subtitle type='html'>C#, XNA, physics, math, optimizations and more</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ianqvist.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>51</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6141721791407147885</id><published>2012-01-30T08:49:00.001+01:00</published><updated>2012-01-30T08:49:41.678+01:00</updated><title type='text'>Introduction To WP7 Development and Farseer Slides</title><content type='html'>I've &lt;a href="https://skydrive.live.com/redir.aspx?cid=f116593ba64184a2&amp;amp;resid=F116593BA64184A2%21290&amp;amp;parid=F116593BA64184A2%21210" target="_blank"&gt;put up the slides&lt;/a&gt; from my presentation at Nordic Game Jam 2012. Have fun!&lt;br /&gt;&lt;br /&gt;&lt;img alt="" height="354" src="data:image/png;base64,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" width="640" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6141721791407147885?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2012/01/introduction-to-wp7-development-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6141721791407147885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6141721791407147885'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2012/01/introduction-to-wp7-development-and.html' title='Introduction To WP7 Development and Farseer Slides'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-3898236313237716835</id><published>2012-01-12T20:20:00.001+01:00</published><updated>2012-01-12T20:27:16.095+01:00</updated><title type='text'>Windows Phone 7 Isolated Storage Helper</title><content type='html'>While working with &lt;a href="http://windowsphonegeek.com/tips/all-about-wp7-isolated-storage--intro-to-isolated-storage" target="_blank"&gt;isolated storage&lt;/a&gt; on WP7, I faced a lot of problems such as deleting a folder containing files. The default behavior of the isolated storage is safe, this means it will not delete folders that contains files. I was also missing the convenience methods &lt;a href="http://msdn.microsoft.com/en-us/library/s2tte0y1.aspx" target="_blank"&gt;ReadAllLines()&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/dd383693.aspx" target="_blank"&gt;WriteAllLines()&lt;/a&gt; we normally have in the .NET Framework 4.&lt;br /&gt;&lt;br /&gt;I decided to write a small helper that supports this functionality. You can find a description of each below:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;DeleteDirectoryRecursive()&lt;/b&gt;&lt;br /&gt;WP7 isolated storage does not delete folders that contains files. This method finds all sub folders, delete files inside the sub folders and then the folder itself.&lt;br /&gt;&lt;b&gt; &lt;/b&gt;&lt;br /&gt;&lt;b&gt;ReadAllLines()&lt;/b&gt;&lt;br /&gt;Reads all the lines of a file and puts them into a list. This is missing from the IsolatedStorageFile API&lt;br /&gt;&lt;br /&gt;&lt;b&gt;WriteAllLines()&lt;/b&gt;&lt;br /&gt;Writes all the lines of an enumerable collection to a file. If the file does not exist, it will create it. If the file already exists, it will overwrite the file. Just as ReadAllLines(), it is just a convenience method that is missing from the IsolatedStorageFile API.&lt;br /&gt;&lt;br /&gt;The code can be found on &lt;a href="https://skydrive.live.com/redir.aspx?cid=f116593ba64184a2&amp;amp;resid=F116593BA64184A2%21285&amp;amp;parid=F116593BA64184A2%21210&amp;amp;authkey=%21AFcBJYZnFfWBb2o" target="_blank"&gt;my SkyDrive&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-3898236313237716835?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2012/01/windows-phone-7-isolated-storage-helper.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3898236313237716835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3898236313237716835'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2012/01/windows-phone-7-isolated-storage-helper.html' title='Windows Phone 7 Isolated Storage Helper'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8547303401366191666</id><published>2011-12-31T23:20:00.001+01:00</published><updated>2012-02-11T18:48:33.153+01:00</updated><title type='text'>How To Make Codeplex Remember Your Password</title><content type='html'>&lt;a href="http://www.codeplex.com/" target="_blank"&gt;Codeplex&lt;/a&gt; is an open source community site created by Microsoft, and it is also where I currently host the &lt;a href="http://farseerphysics.codeplex.com/" target="_blank"&gt;Farseer Physics Engine&lt;/a&gt; project. One of the problems I’ve always have had with the site, is the missing “Remember Password” checkbox for the Team Foundation source control login. The reason they are missing the feature, is that the client is actually using the credential manager inside Windows. Here is how you make it remember your password in Windows 7:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Click &lt;i&gt;Start&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Click &lt;i&gt;Control Panel&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Click &lt;i&gt;Credential Manager&lt;/i&gt;&lt;/li&gt;&lt;li&gt;Click “&lt;i&gt;Add a Windows Credential&lt;/i&gt;”&lt;/li&gt;&lt;li&gt;Enter the following information:&lt;/li&gt;&lt;/ol&gt;Internet or network address: &lt;b&gt;tfs.codeplex.com&lt;/b&gt;    &lt;br /&gt;User name: &amp;lt;&lt;b&gt;Your Username Here&lt;/b&gt;&amp;gt;    &lt;br /&gt;Password: &amp;lt;&lt;b&gt;Your Password Here&lt;/b&gt;&amp;gt;&lt;br /&gt;Click &lt;i&gt;OK&lt;/i&gt; and the Team Foundation client should never ask you again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8547303401366191666?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2011/12/how-to-make-codeplex-remember-your.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8547303401366191666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8547303401366191666'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2011/12/how-to-make-codeplex-remember-your.html' title='How To Make Codeplex Remember Your Password'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-2652464488553291825</id><published>2011-12-07T03:08:00.001+01:00</published><updated>2011-12-07T03:08:07.839+01:00</updated><title type='text'>XNA and Farseer Physics Engine 3.3 Presentation at Nokia</title><content type='html'>&lt;p&gt;The slides and demos from the presentation at Nokia can be found &lt;a href="https://skydrive.live.com/redir.aspx?cid=f116593ba64184a2&amp;amp;resid=F116593BA64184A2!275&amp;amp;parid=F116593BA64184A2!210&amp;amp;authkey=!ADnz85PEBXBzuNk"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-y_iCBOYpExk/Tt7KgXyNbxI/AAAAAAAAAFw/4pNp3_U1Qm4/s1600-h/FarseerWalkerSample%25255B5%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="FarseerWalkerSample" border="0" alt="FarseerWalkerSample" src="http://lh6.ggpht.com/-MHRTMgDw1II/Tt7KhRqKn9I/AAAAAAAAAF0/KbAoGIv5fdE/FarseerWalkerSample_thumb%25255B3%25255D.png?imgmax=800" width="474" height="387" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Thanks to everyone that showed up!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-2652464488553291825?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2011/12/xna-and-farseer-physics-engine-33.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2652464488553291825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2652464488553291825'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2011/12/xna-and-farseer-physics-engine-33.html' title='XNA and Farseer Physics Engine 3.3 Presentation at Nokia'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/-MHRTMgDw1II/Tt7KhRqKn9I/AAAAAAAAAF0/KbAoGIv5fdE/s72-c/FarseerWalkerSample_thumb%25255B3%25255D.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-2949507704936752061</id><published>2011-12-05T17:19:00.000+01:00</published><updated>2011-12-07T03:11:58.131+01:00</updated><title type='text'>XNA 4.0 Introduction</title><content type='html'>The PowerPoint slides and XNA HelloWorld application from my talk at ITU can be found &lt;a href="https://skydrive.live.com/redir.aspx?cid=f116593ba64184a2&amp;amp;resid=F116593BA64184A2%21274&amp;amp;parid=F116593BA64184A2%21210&amp;amp;authkey=%21AL_M6wo5DDLqTyw" target="_blank"&gt;here&lt;/a&gt;.  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-mtGohQPN52s/Tt7LaQjXY8I/AAAAAAAAAGA/xpMHfIY8d8c/s1600-h/Spiderweb%25255B5%25255D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Spiderweb" border="0" alt="Spiderweb" src="http://lh3.ggpht.com/-LgeHlAfQlV0/Tt7LbFeo3wI/AAAAAAAAAGE/85ndJ-LpPBs/Spiderweb_thumb%25255B3%25255D.png?imgmax=800" width="579" height="360" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Thanks to Joe Kiniry for lending me a room to do the presentation.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-2949507704936752061?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2011/12/xna-40-introduction.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2949507704936752061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2949507704936752061'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2011/12/xna-40-introduction.html' title='XNA 4.0 Introduction'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/-LgeHlAfQlV0/Tt7LbFeo3wI/AAAAAAAAAGE/85ndJ-LpPBs/s72-c/Spiderweb_thumb%25255B3%25255D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5958307312550394630</id><published>2010-12-27T17:56:00.001+01:00</published><updated>2010-12-27T18:03:19.553+01:00</updated><title type='text'>Benchmarking Box2D Based Physics Engines</title><content type='html'>&lt;p&gt;With the help of Paril - the developer of &lt;a href="http://code.google.com/p/box2c/"&gt;Box2C&lt;/a&gt; - I've made a benchmark of the following engines:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://jbox2d.org/" target="_blank"&gt;jBox2D&lt;/a&gt; rev 261 trunk &lt;/li&gt;    &lt;li&gt;&lt;a href="http://box2d.org/" target="_blank"&gt;Box2D&lt;/a&gt; 2.2 &lt;/li&gt;    &lt;li&gt;Box2D 2.1.2 &lt;/li&gt;    &lt;li&gt;Box2C rev 20 (wrapper for Box2D 2.1.2) &lt;/li&gt;    &lt;li&gt;&lt;a href="http://farseerphysics.codeplex.com/" target="_blank"&gt;Farseer Physics Engine&lt;/a&gt; 3.2 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I were quite surprised by the findings, so I decided to post them here.&lt;/p&gt;  &lt;p&gt;I benchmarked the different engines using the Pyramid test from the Box2D Testbed. We used a pyramid base count of 35 that resulted in 630 stacked boxes at once. We found that higher base count resulted in too much breakup in the pyramid in the engines based on Box2D 2.2. I started the tests and waited for the solver to converge and the timer output became steady. I repeated this several times to make sure the results were consistent.&lt;/p&gt;  &lt;h3&gt;Test system&lt;/h3&gt;  &lt;p&gt;2 x Quad core Xeon 2.33 Ghz 1333 Mhz FSB    &lt;br /&gt;6 Gb FBDIMM RAM     &lt;br /&gt;Geforce 7900 GT 256 Mb RAM&lt;/p&gt;  &lt;p&gt;Running Windows 7 64Bit with as few applications as possible.&lt;/p&gt;  &lt;h3&gt;Box2D Settings&lt;/h3&gt;  &lt;p&gt;Velocity iterations: 8    &lt;br /&gt;Position iterations: 3     &lt;br /&gt;CCD: Enabled     &lt;br /&gt;Sleeping: Disabled     &lt;br /&gt;Warmstarting: Enabled&lt;/p&gt;  &lt;p&gt;Rest of the settings are the Box2D defaults.&lt;/p&gt;  &lt;h3&gt;Results&lt;/h3&gt;  &lt;p&gt;&lt;strong&gt;jBox2D rev 261 trunk (Fastmath = false to the right)&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_DtkSARQSLuw/TRjFM6P1EYI/AAAAAAAAACc/QNHzLSNJ9KU/s1600-h/jBox2D-rev%20261%20trunk-Converged%5B5%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="jBox2D-rev 261 trunk-Converged" border="0" alt="jBox2D-rev 261 trunk-Converged" src="http://lh6.ggpht.com/_DtkSARQSLuw/TRjFNbHY5pI/AAAAAAAAACg/QPhlxid5HI4/jBox2D-rev%20261%20trunk-Converged_thumb%5B3%5D.png?imgmax=800" width="240" height="192" /&gt;&lt;/a&gt;&amp;#160;&lt;a href="http://lh4.ggpht.com/_DtkSARQSLuw/TRjFN4WEJ-I/AAAAAAAAACk/E2w0-_Fe5dQ/s1600-h/jBox2D-FMathOff-Converged%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="jBox2D-FMathOff-Converged" border="0" alt="jBox2D-FMathOff-Converged" src="http://lh5.ggpht.com/_DtkSARQSLuw/TRjFOaFbFRI/AAAAAAAAACo/uol_YQLW9F4/jBox2D-FMathOff-Converged_thumb%5B1%5D.png?imgmax=800" width="240" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Box2D 2.2&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_DtkSARQSLuw/TRjFOiGqLiI/AAAAAAAAACs/H6dZU4EHtj4/s1600-h/Box2D-2.2.0-Converged%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Box2D-2.2.0-Converged" border="0" alt="Box2D-2.2.0-Converged" src="http://lh4.ggpht.com/_DtkSARQSLuw/TRjFPCMrxjI/AAAAAAAAACw/VoUV8mos6yE/Box2D-2.2.0-Converged_thumb%5B1%5D.png?imgmax=800" width="240" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Box2D 2.1.2&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_DtkSARQSLuw/TRjFP69zF5I/AAAAAAAAAC0/VzjKrYH1m1g/s1600-h/Box2D-2.1.2-Converged%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Box2D-2.1.2-Converged" border="0" alt="Box2D-2.1.2-Converged" src="http://lh4.ggpht.com/_DtkSARQSLuw/TRjFQWyqHKI/AAAAAAAAAC4/fCC_3K0zSX4/Box2D-2.1.2-Converged_thumb%5B1%5D.png?imgmax=800" width="240" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Box2C rev 20&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_DtkSARQSLuw/TRjFRvJcMuI/AAAAAAAAAC8/YKFAh2n4zdY/s1600-h/Box2C-2.1.2-Converged%5B7%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Box2C-2.1.2-Converged" border="0" alt="Box2C-2.1.2-Converged" src="http://lh5.ggpht.com/_DtkSARQSLuw/TRjFSGiI-ZI/AAAAAAAAADA/n92d9fWlkCk/Box2C-2.1.2-Converged_thumb%5B3%5D.png?imgmax=800" width="240" height="187" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Farseer Physics Engine 3.2&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_DtkSARQSLuw/TRjFSkxyLFI/AAAAAAAAADE/CBDdhnlwzsY/s1600-h/FPE3.2-Converged%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="FPE3.2-Converged" border="0" alt="FPE3.2-Converged" src="http://lh3.ggpht.com/_DtkSARQSLuw/TRjFS3jDtDI/AAAAAAAAADI/Wab4lnJsScE/FPE3.2-Converged_thumb%5B1%5D.png?imgmax=800" width="240" height="156" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="2" width="675"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="121"&gt;Engine:&lt;/td&gt;        &lt;td valign="top" width="60"&gt;Time&lt;/td&gt;        &lt;td valign="top" width="492"&gt;Notes&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="121"&gt;&lt;strong&gt;jBox2D rev 261&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="60"&gt;11/12 ms&lt;/td&gt;        &lt;td valign="top" width="492"&gt;Unstable pyramid when fastmath was set to true – I clocked it at 11 ms.         &lt;br /&gt;Some boxes fell of the top and fell outside the screen. With fastmath = false,          &lt;br /&gt;the simulation was a bit more stable, but also a bit more wobbly.          &lt;br /&gt;Turing off fastmath resulted in 1 ms slower simulation (total: 12 ms)&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="121"&gt;&lt;strong&gt;Box2D 2.2.0&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="60"&gt;8 ms&lt;/td&gt;        &lt;td valign="top" width="492"&gt;&amp;nbsp;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="121"&gt;&lt;strong&gt;Box2D 2.1.2&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="60"&gt;10 ms&lt;/td&gt;        &lt;td valign="top" width="492"&gt;Simulation seems more rigid than Box2D 2.2.0 and the pyramid looks perfect.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="121"&gt;&lt;strong&gt;Box2C rev 20&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="60"&gt;13 ms&lt;/td&gt;        &lt;td valign="top" width="492"&gt;3 ms slower because of the overhead of being a C# wrapper.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="121"&gt;&lt;strong&gt;Farseer Physics Engine 3.2&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="60"&gt;6 ms&lt;/td&gt;        &lt;td valign="top" width="492"&gt;&amp;nbsp;&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;h3&gt;Conclusion&lt;/h3&gt;  &lt;p&gt;Farseer Physics Engine 3.2 is by far the fastest of the engines, which might seem a little odd considering it is a direct port of Box2D 2.2.0 and written in C#. However, due to the heavy manual optimizations done to the collision system, it manages to be even more efficient than the original Box2D library. I’m not sure how different jBox2D is from Box2D 2.2 seeing as it produces different results from the rest of the engines, but 11-12 ms is a pretty good result considering it is written entirely in Java.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5958307312550394630?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/12/benchmarking-box2d-based-physics.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5958307312550394630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5958307312550394630'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/12/benchmarking-box2d-based-physics.html' title='Benchmarking Box2D Based Physics Engines'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_DtkSARQSLuw/TRjFNbHY5pI/AAAAAAAAACg/QPhlxid5HI4/s72-c/jBox2D-rev%20261%20trunk-Converged_thumb%5B3%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8851347498792345502</id><published>2010-11-25T20:16:00.001+01:00</published><updated>2010-11-25T20:19:57.348+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Optimizing Performance On The Xbox 360 - Part 2</title><content type='html'>&lt;p&gt;In &lt;a href="http://ianqvist.blogspot.com/2010/11/optimizing-performance-for-xbox-360.html" target="_blank"&gt;part 1&lt;/a&gt; I described the reasons why Xbox 360 is slower than an equivalent PC and&amp;#160; some of the basic recommendations for optimizing C# code to make it run faster. In this post I will mention a few other tricks to increase performance on the Xbox 360.&lt;/p&gt;  &lt;h4&gt;Structures… again.&lt;/h4&gt;  &lt;p&gt;In the .NET world, objects are allocated on the heap and structures are allocated on the stack. Remember, only the heap is garbage collected, this means that structures are not subject to the expensive garbage collection operation. Allocation on the stack is basically free as we only need to increase a stack pointer and call a constructor. This means you can reduce garbage collection and increase speed by using structures instead of objects – however, you need to know the &lt;a href="http://ianqvist.blogspot.com/2010/09/value-types-and-reference-types.html" target="_blank"&gt;difference&lt;/a&gt; between the two. You should also follow the general recommendations for using structures:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Small data objects (data containers) &lt;/li&gt;    &lt;li&gt;Often destroyed or created &lt;/li&gt;    &lt;li&gt;Read-only (or mostly-read) objects &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Reuse those objects&lt;/h4&gt;  &lt;p&gt;As mentioned before, objects are allocated on the heap that is garbage collected. That is why you should avoid creating a lot of objects on each update. Instead, you should reuse the objects using pools as explained in &lt;a href="http://ianqvist.blogspot.com/2010/11/optimizing-performance-for-xbox-360.html" target="_blank"&gt;part 1&lt;/a&gt;. Another and simpler way is to move the object to outer scope and/or make it static. One object that you should pay close attention to is the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.spritebatch.aspx" target="_blank"&gt;SpriteBatch&lt;/a&gt; (if you are using &lt;a href="http://create.msdn.com/en-US/" target="_blank"&gt;XNA&lt;/a&gt;). Do not create the SpriteBatch object on each update, but keep a reference to it through out the game.&lt;/p&gt;  &lt;p&gt;You should also pay attention to &lt;a href="http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx" target="_blank"&gt;List&amp;lt;T&amp;gt;&lt;/a&gt;, arrays and other commonly used list types. When you create a new List&amp;lt;T&amp;gt; and add a single item to it, it will initialize an array with a size of 4. If you add more than 4 elements, it will create a new array with double the size. The results is that 2 arrays have been garbage collected. To keep that from happening, you should initialize List&amp;lt;T&amp;gt; with a capacity that is equal to what you need. To keep the List&amp;lt;T&amp;gt; form being garbage collected, you should move the list to outer scope and clear it before use instead of initializing a new instance.&lt;/p&gt;  &lt;h4&gt;Boxing&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx" target="_blank"&gt;Boxing&lt;/a&gt; is the process of encapsulating a value type in a reference type container. This is great as it allows us to pass value types as objects to methods or store them in collections as objects. However, this is not great for performance and we have to eliminate boxing and unboxing where we can. You can use tools like &lt;a href="http://www.red-gate.com/products/reflector/" target="_blank"&gt;Reflector&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/en-us/library/f7dy01k1%28VS.80%29.aspx" target="_blank"&gt;Ildasm&lt;/a&gt; to disassemble your application to &lt;a href="http://en.wikipedia.org/wiki/MSIL" target="_blank"&gt;MSIL&lt;/a&gt; code. Inside the MSIL code you simply look for the &lt;strong&gt;box&lt;/strong&gt; and &lt;strong&gt;unbox&lt;/strong&gt; keywords. You can find more info along with pictures in my post &lt;a href="http://ianqvist.blogspot.com/2009/09/performance-tips-and-tricks-part-4.html" target="_blank"&gt;Performance Tips and Tricks Part 4&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Further reading&lt;/h4&gt;  &lt;p&gt;I recommend you read two GDC 2008 PowerPoint presentations. &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyId=8450DB46-283F-4924-B35C-3CCD1DB7E97E&amp;amp;displaylang=en" target="_blank"&gt;CLR Performance&lt;/a&gt; by Frank Savage and &lt;a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyId=B11AD912-4158-44CC-A771-A5E044F7E3BB&amp;amp;displaylang=en" target="_blank"&gt;Understanding XNA Framework Performance&lt;/a&gt; by &lt;a href="http://blogs.msdn.com/b/shawnhar/" target="_blank"&gt;Shawn Hargreaves&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8851347498792345502?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/11/optimizing-performance-on-xbox-360-part.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8851347498792345502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8851347498792345502'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/11/optimizing-performance-on-xbox-360-part.html' title='Optimizing Performance On The Xbox 360 - Part 2'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-7149532762671716983</id><published>2010-11-21T19:52:00.001+01:00</published><updated>2010-11-25T20:20:06.892+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Optimizing Performance On The Xbox 360 - Part 1</title><content type='html'>&lt;p&gt;After my &lt;a href="http://ianqvist.blogspot.com/2010/01/performance-tips-and-tricks-series.html" target="_blank"&gt;Performance Tips and Tricks&lt;/a&gt; series I got a lot of requests to write a post regarding the performance on the Xbox 360 platform. I will try to focus on why Xbox 360 is slower than PC and what we can do to get around it. But first we need to underline the importance of good programming.&lt;/p&gt;  &lt;h4&gt;Algorithms and datastructure complexity&lt;/h4&gt;  &lt;p&gt;I’ve been on the topic of complexity &lt;a href="http://ianqvist.blogspot.com/2010/07/big-o-notation-summary.html" target="_blank"&gt;before&lt;/a&gt;. I can’t underline how important it is that we keep the complexity of our algorithms low. If you are sorting a large dataset, make sure you use the &lt;a href="http://en.wikipedia.org/wiki/Quicksort" target="_blank"&gt;correct&lt;/a&gt; algorithm and if you are sorting a small dataset (&amp;lt;10 items), there is &lt;a href="http://en.wikipedia.org/wiki/Insertion_sort" target="_blank"&gt;another and faster&lt;/a&gt; algorithm.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Note: &lt;/strong&gt;If you use .Net &lt;a href="http://msdn.microsoft.com/en-us/library/w56d4y5z.aspx" target="_blank"&gt;List&amp;lt;T&amp;gt;.Sort()&lt;/a&gt;, it automatically chooses the best algorithm depending on your dataset.&lt;/p&gt;  &lt;p&gt;If you are using pixel perfect collision detection, perhaps you should implement a physics system that uses a polygon collision system instead. You could also implement a &lt;a href="http://ianqvist.blogspot.com/2010/07/broad-and-narrow-phase-collision.html" target="_blank"&gt;broad phase&lt;/a&gt; system to filter out collisions that you don’t need to process. Implementing a fast and efficient algorithm is 100 times better than any micro-optimization or performance trick out there. But this post is not about using efficient algorithms, it is about the case where you already have implemented the algorithms and still need to squeeze the last drops of performance out of the platform.&lt;/p&gt;  &lt;h4&gt;Why is it slow?&lt;/h4&gt;  &lt;p&gt;Xbox 360 uses a custom &lt;a href="http://en.wikipedia.org/wiki/Xbox_360_hardware#Central_processing_unit" target="_blank"&gt;triple-core&lt;/a&gt; 64bit PowerPC 3.2 GHz CPU. It is designed by IBM with high floating point performance in mind by using multiple FPU and SIMD vector processing units in each core. It is a quite powerful platform, but an equivalent PC still outperforms it, how can that be?&lt;/p&gt;  &lt;p&gt;I’m afraid that the hardware is not the problem here, it is the software on the Xbox 360. Let us take an example; the following piece of code runs in 12500 ticks on Xbox 360 and 10 ticks on PC.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_DtkSARQSLuw/TOlqIYd1BQI/AAAAAAAAABQ/dE8ShxvzrkI/s1600-h/code13.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="code1" border="0" alt="code1" src="http://lh5.ggpht.com/_DtkSARQSLuw/TOlqJaVmoLI/AAAAAAAAABU/SfIiXnMDrcw/code1_thumb1.png?imgmax=800" width="224" height="85" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;That is a huge difference and even if we switch to integers instead of floats (to get around the &lt;a href="http://en.wikipedia.org/wiki/Floating-point_unit" target="_blank"&gt;FPU&lt;/a&gt;) we still get around 7060 ticks on Xbox 360 and 10 ticks on PC. The low performance when using floats is due to missing &lt;a href="http://en.wikipedia.org/wiki/AltiVec" target="_blank"&gt;AltiVec&lt;/a&gt; support in .Net Compact Framework and some missing optimizations in the floating point code. The .Net Compact Framework was not designed to run on Xbox 360. In fact, it was designed with portability in mind and did not have any floating point code until the Xbox was released. Thankfully the .Net CF team implemented some FPU code and that improved the floating point performance a lot (by a factor of 10!).&lt;/p&gt;  &lt;p&gt;Then there is the garbage collector. The CF has a simplified version of the garbage collector that works without &lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Generational_GC_.28ephemeral_GC.29" target="_blank"&gt;generations&lt;/a&gt;. Instead it looks up all the objects after 1 MB has been &lt;a href="http://blogs.msdn.com/b/stevenpr/archive/2004/07/26/an-overview-of-the-net-compact-framework-garbage-collector.aspx" target="_blank"&gt;allocated&lt;/a&gt;. There are also a few other differences such as code pitching where the GC frees code it has jitted before to free up memory. And last but not least there are the compiler optimizations performed by the CF &lt;a href="http://en.wikipedia.org/wiki/Just-in-time_compilation" target="_blank"&gt;JIT&lt;/a&gt; compiler. The optimizations carried out by the CF JIT is severely limited, especially the method inlining. The CF JIT will only inline a method based on the following criteria:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;16 bytes or less of IL &lt;/li&gt;    &lt;li&gt;No branching (if statements) &lt;/li&gt;    &lt;li&gt;No local variables &lt;/li&gt;    &lt;li&gt;No exception handlers &lt;/li&gt;    &lt;li&gt;No 32-bit floating point arguments or return value &lt;/li&gt;    &lt;li&gt;If it has more than one argument, they must be accessed in order from lowest to highest. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;That means it is basically only inline property getter/setters and methods that call other methods.&lt;/p&gt;  &lt;p&gt;The missing FPU code, the few optimizations and the simple garbage collector is all because the CF never was designed to work on anything else but embedded devices such as mobile phones. Lets take a look at what options we have…&lt;/p&gt;  &lt;h4&gt;Optimizing the code&lt;/h4&gt;  &lt;p&gt;It is very important that you start by &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2009/07/06/why-measure-when-you-can-guess.aspx" target="_blank"&gt;profiling&lt;/a&gt; your code. You can use the &lt;a href="http://msdn.microsoft.com/en-us/library/bb198208.aspx" target="_blank"&gt;XNA Remote Performance Monitor&lt;/a&gt; to profile memory allocations (garbage collector problems) and you can use the &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2009/07/07/profiling-with-stopwatch.aspx" target="_blank"&gt;Stopwatch&lt;/a&gt; class to profile different areas of your code to see which area you should focus on. A normal PC profiler also comes in handy as the areas that tend to take up the most time on PC, almost always are the same areas on the Xbox 360. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_DtkSARQSLuw/TOlqKEzEHuI/AAAAAAAAABY/zvEUgdGdq2s/s1600-h/gc10.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="gc" border="0" alt="gc" src="http://lh4.ggpht.com/_DtkSARQSLuw/TOlqLWgxitI/AAAAAAAAABc/bzCxD5xXCmk/gc_thumb6.png?imgmax=800" width="528" height="436" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;When you have found the different areas to focus on, we can move on to actually optimizing them.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Virtual methods      &lt;br /&gt;&lt;/strong&gt;One of the places to optimize are the virtual methods and properties. While virtuals are&amp;#160; great for &lt;a href="http://en.wikipedia.org/wiki/Object-oriented_programming" target="_blank"&gt;OOP&lt;/a&gt;, they are not so great for the CF JIT compiler. Virtual methods are around 40% slower than static or instance calls and just to make it all worse, they are never inlined by the compiler.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_DtkSARQSLuw/TOlr6VX1cvI/AAAAAAAAACA/nZSK_vpTR0Y/s1600-h/virtual1%5B15%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="virtual1" border="0" alt="virtual1" src="http://lh6.ggpht.com/_DtkSARQSLuw/TOlr6y19I2I/AAAAAAAAACE/bkeDAnnirhY/virtual1_thumb%5B9%5D.png?imgmax=800" width="600" height="113" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;To get around it you need to avoid virtuals where you can. If you need to use virtuals, make sure you mark your overridden methods and classes as &lt;a href="http://msdn.microsoft.com/en-us/library/88c54tsw%28VS.71%29.aspx" target="_blank"&gt;sealed&lt;/a&gt;. If you use the sealed keyword, the compiler can sometimes resolve the destination of a virtual call and avoid the expensive virtual call.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Use fields instead of properties      &lt;br /&gt;&lt;/strong&gt;While properties are a neat way to keep your code clean, they are not that great performance wise. Under the hood, properties are ordinary methods and while simple get/set properties gets inlined by the compiler, there are no guarantees that all of them will get inlined. The solutions is to use fields instead, but not at the costs of a poorly designed application. So use it wisely!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_DtkSARQSLuw/TOlqQR0jgqI/AAAAAAAAABo/v5qzmsIqwyc/s1600-h/field%5B14%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="field" border="0" alt="field" src="http://lh5.ggpht.com/_DtkSARQSLuw/TOlqSEPT6MI/AAAAAAAAABs/wSh_V19BeR8/field_thumb%5B8%5D.png?imgmax=800" width="512" height="63" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The ref keyword      &lt;br /&gt;&lt;/strong&gt;If you are working with &lt;a href="http://msdn.microsoft.com/en-us/library/ah19swz4%28VS.71%29.aspx" target="_blank"&gt;structs&lt;/a&gt;, you should try and use the &lt;a href="http://msdn.microsoft.com/en-us/library/14akc2c7.aspx" target="_blank"&gt;ref keyword&lt;/a&gt; to send them by reference instead of by value. If you are working with the XNA library, the Matrix, Vector2 and Vector3 classes have math methods that uses ref and &lt;a href="http://msdn.microsoft.com/en-us/library/t3c3bfhx%28VS.80%29.aspx" target="_blank"&gt;out&lt;/a&gt; to pass structs by reference instead of by value.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_DtkSARQSLuw/TOlr7H4GPAI/AAAAAAAAACI/cm85nGpv4cQ/s1600-h/ref%5B17%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="ref" border="0" alt="ref" src="http://lh6.ggpht.com/_DtkSARQSLuw/TOlr7kFq_wI/AAAAAAAAACM/zPV6kg2tqII/ref_thumb%5B11%5D.png?imgmax=800" width="600" height="114" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Inlining      &lt;br /&gt;&lt;/strong&gt;Manually inlining code when using the Compact Framework can give you an extra performance boost. The gain is typically around 5-15% depending on your code. The tricky part of inlining is to determine what code to inline. I recommend you follow some simple rules:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Small methods &lt;/li&gt;    &lt;li&gt;Methods that are only called from one place &lt;/li&gt;    &lt;li&gt;Methods that does not alter the state of the object (only give input and get output methods) &lt;/li&gt;    &lt;li&gt;Methods that does not already get inlined by the compiler &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It is important to run a profiler while you inline. You might get even worse performance by inlining the wrong methods. It is important to measure it!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_DtkSARQSLuw/TOlr77SvJ2I/AAAAAAAAACQ/iE2nUcRbsLU/s1600-h/inline%5B10%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="inline" border="0" alt="inline" src="http://lh5.ggpht.com/_DtkSARQSLuw/TOlr8DentRI/AAAAAAAAACU/Lwh-DSreR28/inline_thumb%5B6%5D.png?imgmax=800" width="600" height="138" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Pooling      &lt;br /&gt;&lt;/strong&gt;In the &lt;a href="http://en.wikipedia.org/wiki/Common_Language_Runtime" target="_blank"&gt;CLR&lt;/a&gt;, creating an object is a really &lt;a href="http://vineetgupta.spaces.live.com/blog/cns!8DE4BDC896BEE1AD!1104.entry" target="_blank"&gt;efficient&lt;/a&gt; operation while destroying the object is not. This is due to the fact that destroying an object will make it subject to the garbage collector. A way to get around this is to use &lt;a href="http://en.wikipedia.org/wiki/Object_pool_pattern" target="_blank"&gt;pooling&lt;/a&gt; of objects. You basically create a pool (you could use a &lt;a href="http://msdn.microsoft.com/en-us/library/system.collections.stack.aspx" target="_blank"&gt;stack&lt;/a&gt;) and then pre-allocate a bunch of empty objects before use. When you need an object, you fetch one from the pool and when you are done with it, you put it back in the pool. This way you keep the object reference alive and it will get collected by the garbage collector.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Fixed point math      &lt;br /&gt;&lt;/strong&gt;I’ve been on this &lt;a href="http://ianqvist.blogspot.com/2009/10/floating-and-fixed-point-arithmetic.html" target="_blank"&gt;subject before&lt;/a&gt;. If you have some heavy floating point operations that you need to run on a platform with low floating point performance, then you should implement fixed point math. A trick is to identify operations that don’t need floating point accuracy (like my code above in the explanation) and convert it to use integers instead.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;a href="http://ianqvist.blogspot.com/2010/11/optimizing-performance-on-xbox-360-part.html" target="_blank"&gt;Part 2 is here&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-7149532762671716983?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/11/optimizing-performance-for-xbox-360.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7149532762671716983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7149532762671716983'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/11/optimizing-performance-for-xbox-360.html' title='Optimizing Performance On The Xbox 360 - Part 1'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_DtkSARQSLuw/TOlqJaVmoLI/AAAAAAAAABU/SfIiXnMDrcw/s72-c/code1_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-3654557185045460922</id><published>2010-11-12T19:51:00.001+01:00</published><updated>2010-11-12T19:51:50.038+01:00</updated><title type='text'>Farseer Physics Engine 3.1 released</title><content type='html'>&lt;p&gt;I’ve just packaged and released Farseer Physics Engine 3.1. It has a lot of new features and a couple of bugs have been fixed. You can see a list of changes in the new version on the &lt;a href="http://farseerphysics.codeplex.com/releases/view/51080" target="_blank"&gt;downloads page&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_DtkSARQSLuw/TN2MwV9PU_I/AAAAAAAAABI/bG0g-CQwcjU/s1600-h/Sample%5B4%5D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Sample" border="0" alt="Sample" src="http://lh4.ggpht.com/_DtkSARQSLuw/TN2Mw6gv5sI/AAAAAAAAABM/S1mIZOFZ7lE/Sample_thumb%5B2%5D.png?imgmax=800" width="559" height="369" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-3654557185045460922?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/11/farseer-physics-engine-31-released.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3654557185045460922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3654557185045460922'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/11/farseer-physics-engine-31-released.html' title='Farseer Physics Engine 3.1 released'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_DtkSARQSLuw/TN2Mw6gv5sI/AAAAAAAAABM/S1mIZOFZ7lE/s72-c/Sample_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-3331015960766188637</id><published>2010-10-27T12:56:00.001+02:00</published><updated>2010-10-27T16:05:49.692+02:00</updated><title type='text'>Tunneling explained</title><content type='html'>&lt;p&gt;Tunneling is an effect where two shapes can get stuck in each other or simply pass each other without impact. The effect exist because we are limited by the CPU and have to do the calculations in timesteps instead of one continuous stream.&lt;/p&gt;  &lt;p&gt;The effect comes apparent especially at high velocities and/or with small shapes. Bullets of a gun is a perfect example because they are usually fired with high velocity and are small in size. To illustrate this, have a look at the following picture:&lt;/p&gt;  &lt;p&gt;&lt;img title="SlowBullet.png" alt="SlowBullet.png" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=FarseerPhysics&amp;amp;DownloadId=76281" /&gt;     &lt;br /&gt;(The numbers illustrate the timestep/seconds)&lt;/p&gt;  &lt;p&gt;Imagine that it runs at 1 second per update with a velocity of 34 pixels/second    &lt;br /&gt;Everything is fine because the bullet hits the wall as it should and the physics simulator responds with a proper collision reaction.&lt;/p&gt;  &lt;p&gt;But when we turn up the velocity to 89 pixels/second, then this happens&lt;/p&gt;  &lt;p&gt;&lt;img title="FastBullet.png" alt="FastBullet.png" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=FarseerPhysics&amp;amp;DownloadId=76282" /&gt;&lt;/p&gt;  &lt;p&gt;The bullet went right through the wall - the physics engine never had a chance of responding to the collision because it never happened - that is what is called tunneling.&lt;/p&gt;  &lt;h4&gt;What can be done about it&lt;/h4&gt;  &lt;p&gt;There exist something called CCD or Continuous Collision Detection. It is a name that covers several different methods of preventing tunneling, one of the more used ones is Conservative Advancement. CA is a substep that is performed within a world timestep. Tt moves the shape along its path until it reaches the next timestep. This is very CPU expensive so it is best to turn it on only for shapes that needs it.&lt;/p&gt;  &lt;p&gt;There are simpler ways of limiting tunneling, but they are not as effective in all cases:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Use a smaller timestep in the physics engine &lt;/li&gt;    &lt;li&gt;Use raycasting &lt;/li&gt;    &lt;li&gt;Make your shapes larger &lt;/li&gt;    &lt;li&gt;Make your shapes slower &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-3331015960766188637?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/10/what-is-tunneling.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3331015960766188637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3331015960766188637'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/10/what-is-tunneling.html' title='Tunneling explained'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-4101620701802640419</id><published>2010-09-10T23:11:00.001+02:00</published><updated>2010-09-10T23:11:32.281+02:00</updated><title type='text'>Value Types and Reference Types Explained</title><content type='html'>&lt;p&gt;There are two types of data types in the .NET framework: Value and reference types.   &lt;br /&gt;Lets first have a look at the &lt;a href="http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx" target="_blank"&gt;value types&lt;/a&gt;:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Value types are allocated on the current thread’s stack.&lt;/li&gt;    &lt;li&gt;The lifetime of the value type is only inside the scope where it is used. &lt;/li&gt;    &lt;li&gt;When you pass a value type as a parameter in a method, the value type is copied.&lt;/li&gt;    &lt;li&gt;A wrapper object is created if you pass a value type to a method that expects an object.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Value types are suitable for representing lightweight objects such as vectors, matrices and colors. Value types has less overhead than classes by the fact that no additional memory for the reference is needed. However, there are a few things that are worth mentioning:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ah19swz4%28VS.71%29.aspx" target="_blank"&gt;Structs&lt;/a&gt; can’t have a default parameterless constructor. It is provided by default and it initializes all the fields to their default values.&lt;/li&gt;    &lt;li&gt;You can’t initialize an instance field inside a struct&lt;/li&gt;    &lt;li&gt;You can’t use inheritance in structs&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Value types are important for performance since they are allocated on the stack (the stack is not garbage collected) – they are cheaper to allocate and deallocate than classes. However, if your struct is &lt;a href="http://msdn.microsoft.com/en-us/library/ms229017.aspx" target="_blank"&gt;more than 16 bytes&lt;/a&gt;, it may be more efficient to use a class instead.&lt;/p&gt;  &lt;p&gt;Now, let us have a look at &lt;a href="http://msdn.microsoft.com/en-us/library/490f96s2.aspx" target="_blank"&gt;reference types&lt;/a&gt;:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Stored on the managed heap.&lt;/li&gt;    &lt;li&gt;Variables that are reference types only contain a pointer to the data.&lt;/li&gt;    &lt;li&gt;Reference types are garbage collected when they are no longer referenced.&lt;/li&gt;    &lt;li&gt;Are always passed by reference (the pointer to the data is passed)&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For your convenience, here is a list of value and reference types:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="2" width="400"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="200"&gt;&lt;strong&gt;Value types&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="200"&gt;&lt;strong&gt;Reference types&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="200"&gt;         &lt;p&gt;Enums           &lt;br /&gt;Structs            &lt;br /&gt;Boolean, Date and Char            &lt;br /&gt;Decimal            &lt;br /&gt;Byte, Short, Integer, Long            &lt;br /&gt;Single and Double&lt;/p&gt;       &lt;/td&gt;        &lt;td valign="top" width="200"&gt;         &lt;p&gt;Classes           &lt;br /&gt;Delegates            &lt;br /&gt;Exceptions            &lt;br /&gt;Attributes            &lt;br /&gt;Arrays&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h4&gt;The ref keyword&lt;/h4&gt;  &lt;p&gt;The ref keyword is very important when it comes to both performance and the behavior of value and reference types. If you put ref in front of a parameter in a method, the argument is passed by reference regardless whether it is a value or reference type.&lt;/p&gt;  &lt;p&gt;Example:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_DtkSARQSLuw/TIqfABGijNI/AAAAAAAAAA0/diAj0OTMwVE/s1600-h/image%5B8%5D.png"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_DtkSARQSLuw/TIqfA9Sug_I/AAAAAAAAAA8/tuurj6QaOFw/image_thumb%5B9%5D.png?imgmax=800" width="314" height="227" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The output of this application is “http://google.it”. If we didn’t have the ref keyword in front of the parameter, the output would be “http://google.com”. This is because the original pointer (reference) to the data is passed to the method when using the ref keyword. Value types can also be passed to the method by reference (and no, it does not get &lt;a href="http://msdn.microsoft.com/en-us/library/yz2be5wk%28VS.80%29.aspx" target="_blank"&gt;boxed&lt;/a&gt;) – yielding the same behavior as the reference type.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-4101620701802640419?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/09/value-types-and-reference-types.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/4101620701802640419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/4101620701802640419'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/09/value-types-and-reference-types.html' title='Value Types and Reference Types Explained'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_DtkSARQSLuw/TIqfA9Sug_I/AAAAAAAAAA8/tuurj6QaOFw/s72-c/image_thumb%5B9%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5127694217988749900</id><published>2010-09-07T14:03:00.001+02:00</published><updated>2010-09-07T14:03:35.734+02:00</updated><title type='text'>Blank Visual Studio 2010 Team Explorer Window</title><content type='html'>&lt;p&gt;Recently I decided to upgrade my Visual Studio 2008 installation to Visual Studio 2010. I uninstalled all VS2008 packages and made sure to clean out folders left behind. After a long VS2010 installation I fired up Team Explorer and connected to my Codeplex.com projects; after doing so, I was met by an empty Team Explorer window.&lt;/p&gt;  &lt;p&gt;Several reinstalls later and registry changes I tried reading up on how to repair installations and came across the command:&lt;/p&gt;  &lt;p&gt;devenv /setup&lt;/p&gt;  &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/ex6a2fad%28vs.80%29.aspx" target="_blank"&gt;setup&lt;/a&gt; switch did the trick and I now have a fully working Team Explorer window.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5127694217988749900?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/09/blank-visual-studio-2010-team-explorer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5127694217988749900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5127694217988749900'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/09/blank-visual-studio-2010-team-explorer.html' title='Blank Visual Studio 2010 Team Explorer Window'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5867585239702592154</id><published>2010-08-23T22:35:00.001+02:00</published><updated>2010-08-23T22:35:10.542+02:00</updated><title type='text'>Farseer Physics Engine 3.0 Has Been Released!</title><content type='html'>&lt;p&gt;It is out! The next generation of physics engines for the .NET platform has finally been released. It uses Box2D as the core engine, but it is so much more than just an ordinary physics engine.&lt;/p&gt;  &lt;p&gt;You can get the 3.0 release from the Farseer Physics Engine &lt;a href="http://farseerphysics.codeplex.com/releases/view/27942"&gt;Codeplex project&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5867585239702592154?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/08/farseer-physics-engine-30-has-been.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5867585239702592154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5867585239702592154'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/08/farseer-physics-engine-30-has-been.html' title='Farseer Physics Engine 3.0 Has Been Released!'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6290672040995324650</id><published>2010-08-16T23:02:00.001+02:00</published><updated>2010-08-16T23:05:53.391+02:00</updated><title type='text'>Synchronizing Google Calendar with iPhone and Outlook</title><content type='html'>&lt;p&gt;I bring this little tutorial to show how to synchronize &lt;a href="http://www.google.com/calendar"&gt;Google Calendar&lt;/a&gt; with both iPhone and Outlook. I use Outlook 2010 and iPhone iOS 4.0.1 for this tutorial.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Outlook 2010&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Download and install &lt;a href="http://dl.google.com/googlecalendarsync/GoogleCalendarSync_Installer.exe"&gt;Google Calendar Sync&lt;/a&gt;. This will enable you to syncronize between Google Calendar and Outlook.&lt;/li&gt;    &lt;li&gt;Test out the synchronization by creating an event in Outlook calendar, right-click on the Google Calendar Sync icon in the notification area, and click “Sync”. Your event should show up in Google Calendar.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;iPhone iOS 4.x&lt;/strong&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Click “Settings” and click on “Mail, Contacts and Calendars”.&lt;/li&gt;    &lt;li&gt;Click “Add account” and pick “Microsoft Exchange” (Yes, we use Microsoft Exchange in this case. It enables Google Mail, Google Contacts and Google Calendar push-notifications support)&lt;/li&gt;    &lt;li&gt;Enter your information:&lt;/li&gt;    &lt;ol&gt;     &lt;li&gt;E-Mail&lt;/li&gt;      &lt;li&gt;Leave Domain blank&lt;/li&gt;      &lt;li&gt;Your username; put your full email here&lt;/li&gt;      &lt;li&gt;Your password&lt;/li&gt;      &lt;li&gt;Description contains the name of the account. You can leave it to the default or choose one yourself.&lt;/li&gt;   &lt;/ol&gt;    &lt;li&gt;Once you click Next, it should take 2 seconds and a Server field appears. Enter “m.google.com” and click Next again.&lt;/li&gt;    &lt;li&gt;Select the services you want to sync. I have both mail and calendars synchronized with Google.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;That is it. When you create a new event in Google Calendar, it will appear a few seconds after on your iPhone.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Shared Google calendars&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;A friend of mine and I share a calendar on Google Calendar. Unfurtnaly it can’t be synced with Google Calendar Sync since it only works with your default Google calendar and default Outlook calendar. However, there is a way to make your iPhone work with shared calendars:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;On your iPhone, go to the address: m.google.com&lt;/li&gt;    &lt;li&gt;Log in to Google using your Google account.&lt;/li&gt;    &lt;li&gt;If it tells you that your device is unsupported, switch the language to English and it should disappear.&lt;/li&gt;    &lt;li&gt;Select your device from the list.&lt;/li&gt;    &lt;li&gt;Select the calendars you would like to sync.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Note: This did not work on my phone right away. I had to untick it and tick the shared calendar again before it worked.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Google has a &lt;a href="http://www.google.com/sync/index.html"&gt;sync page&lt;/a&gt; that gives you a tutorial for your device. The same tutorial as I wrote can be &lt;a href="http://www.google.com/support/mobile/bin/answer.py?answer=138740&amp;amp;topic=14252"&gt;found here&lt;/a&gt; for iPhone. I will let this post live because it contains information not found in the Google sync tutorial (like step 3 in shared calendars).&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6290672040995324650?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/08/synchronizing-google-calendar-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6290672040995324650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6290672040995324650'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/08/synchronizing-google-calendar-with.html' title='Synchronizing Google Calendar with iPhone and Outlook'/><author><name>Genbox</name><uri>http://www.blogger.com/profile/06409161195797258709</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-124814593442529145</id><published>2010-07-31T17:23:00.001+02:00</published><updated>2010-07-31T17:23:35.006+02:00</updated><title type='text'>Make Team Explorer Remember Login Credentials</title><content type='html'>&lt;p&gt;When working with Team Explorer in Visual Studio, you might have come across the annoying user login box that pops up each time you open a Team Foundation Server connected solution. The Team Explorer development team decided to use the built-in credential vault in Windows instead of using their own implementation. Here is how you save the credentials inside the Windows 7 credential vault.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Open the Control Panel&lt;/li&gt;    &lt;li&gt;Click on &lt;strong&gt;User Accounts&lt;/strong&gt; (Called User Accounts and Family Safety in category view)&lt;/li&gt;    &lt;li&gt;Click &lt;strong&gt;Manage Your Credentials&lt;/strong&gt; to the left (Called Manage Windows Credentials in category view)&lt;/li&gt;    &lt;li&gt;Next to the Windows Credentials category you click the &lt;strong&gt;Add a Windows credential&lt;/strong&gt; button.&lt;/li&gt;    &lt;li&gt;Enter server address, username and password.&lt;/li&gt;    &lt;li&gt;Click &lt;strong&gt;Ok&lt;/strong&gt;&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Now the Team Explorer client should remember your password.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-124814593442529145?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/07/make-team-explorer-remember-login.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/124814593442529145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/124814593442529145'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/07/make-team-explorer-remember-login.html' title='Make Team Explorer Remember Login Credentials'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6430876037068986284</id><published>2010-07-03T23:23:00.001+02:00</published><updated>2010-07-03T23:24:27.868+02:00</updated><title type='text'>Broad And Narrow Phase Collision Detection Systems</title><content type='html'>&lt;p&gt;If you don’t know about the big O notation, I recommend you read about it &lt;a href="http://ianqvist.blogspot.com/2010/07/big-o-notation-summary.html" target="_blank"&gt;here&lt;/a&gt; first. This post gives you an idea of what broad and narrow phase algorithms are and how they are used in physics engines.&lt;/p&gt;  &lt;h4&gt;&lt;b&gt;Broad Phase Collision Detection&lt;/b&gt;&lt;/h4&gt;  &lt;p&gt;Performance is an essential part of a physics engine. You can get away with just implementing a few algorithms that detect collisions using a O(n^2) algorithm, but when you add more and more objects to the simulator It becomes quite expensive (CPU wise). Not very good for performance.&lt;/p&gt;  &lt;p&gt;We can reduce the amount of tests by implementing a broad phase into our collision system. It is responsible of eliminating tests and thus reducing the number of tests needed (We obviously don't need to test objects far away from the player). We could for example have an algorithm that tests the distance using the X and Y axis of the screen, if the objects are too far away from each other, we can eliminate them as potential collisions. There are many algorithms that can eliminate tests, a few of them are:&lt;/p&gt;  &lt;p&gt;&lt;b&gt;SAP (Sweep and Prune)&lt;/b&gt; - &lt;a href="http://en.wikipedia.org/wiki/Sweep_and_prune"&gt;More info&lt;/a&gt; - O(n log(n)) algorithm&lt;/p&gt;  &lt;p&gt;&lt;b&gt; Spatial Hash&lt;/b&gt; - &lt;a href="http://conkerjo.wordpress.com/2009/06/13/spatial-hashing-implementation-for-fast-2d-collisions/"&gt;More info&lt;/a&gt; - O(n log(n)) algorithm&lt;/p&gt;  &lt;p&gt;If I remember correctly they can be O(1) in best case and O(n^2) in worst case.&lt;/p&gt;  &lt;p&gt;It is important to remember that the broad phase only keeps track of the distance between objects. If they are close enough to create a potential collision, the objects are paired. To determine if two objects are close enough to create a collision, we use something called a AABB (Axis Aligned Bounding Box). It is simply a box that does not rotate that encapsulates the whole object. It is cheaper to test box vs. box instead of a lot of polygons vs. polygon.&lt;/p&gt;  &lt;p&gt;Too far from each other to be tested for collisions:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/TC-qUbNnqvI/AAAAAAAAAN4/1glXQ_pdMQE/s1600-h/NoPair4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="NoPair" border="0" alt="NoPair" src="http://lh6.ggpht.com/_Dhwvn65yBx0/TC-qU3snUBI/AAAAAAAAAN8/a1sAkj31b7Q/NoPair_thumb2.png?imgmax=800" width="324" height="342" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Close and needs to be further tested for collision:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/TC-qVU1RzHI/AAAAAAAAAOA/937d1r3wnck/s1600-h/Pair2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pair" border="0" alt="Pair" src="http://lh4.ggpht.com/_Dhwvn65yBx0/TC-qV-d1WRI/AAAAAAAAAOE/aB8J36jE0M0/Pair_thumb.png?imgmax=800" width="324" height="342" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h4&gt;&lt;b&gt;Narrow Phase Collision Detection&lt;/b&gt;&lt;/h4&gt;  &lt;p&gt;Once the broad phase collider has done its job, we are left with a couple of pairs that needs further testing. A physics engine needs to know exactly how deep polygon shapes have penetrated each other and some other stuff like the normals. A narrow phase algorithm basically takes in two polygon shapes and finds out where those two polygons intersect and how deep.&lt;/p&gt;  &lt;p&gt;We need the depth of penetration, the normal and the position of the collision to calculate a proper physics response.&lt;/p&gt;  &lt;p&gt;Collision where the red dot is the point of collision.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/TC-qWZY6wtI/AAAAAAAAAOI/W8Swoi1bABw/s1600-h/Collision2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Collision" border="0" alt="Collision" src="http://lh4.ggpht.com/_Dhwvn65yBx0/TC-qWixGpTI/AAAAAAAAAOM/go397Bhie5I/Collision_thumb.png?imgmax=800" width="324" height="342" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;There are also a few different narrow phase algorithms. Two examples of such algorithms are listed here:&lt;/p&gt;  &lt;p&gt;&lt;b&gt;SAT (Separate Axis Theorem)&lt;/b&gt; - &lt;a href="http://en.wikipedia.org/wiki/Separating_axis_theorem"&gt;More info&lt;/a&gt;&lt;b&gt;     &lt;br /&gt;Distance Grid&lt;/b&gt; - &lt;a href="http://lab.polygonal.de/2008/07/13/collision-detection-for-particle-systems/"&gt;More info&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6430876037068986284?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/07/broad-and-narrow-phase-collision.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6430876037068986284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6430876037068986284'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/07/broad-and-narrow-phase-collision.html' title='Broad And Narrow Phase Collision Detection Systems'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_Dhwvn65yBx0/TC-qU3snUBI/AAAAAAAAAN8/a1sAkj31b7Q/s72-c/NoPair_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-3996245089742756150</id><published>2010-07-03T23:17:00.001+02:00</published><updated>2010-08-19T22:27:21.964+02:00</updated><title type='text'>The Big O notation – Summary</title><content type='html'>&lt;p&gt;Big O notation was invented to describe the growth rate of a function. You basically take away all constants and small factors and only focus on the big factors. Let’s take an example; the function:&lt;/p&gt;  &lt;p&gt;&lt;em&gt;x&lt;/em&gt;^2 + 2&lt;em&gt;x&lt;/em&gt; + 6&lt;/p&gt;  &lt;p&gt;in terms of big O notation becomes:&lt;/p&gt;  &lt;p&gt;O(&lt;em&gt;x&lt;/em&gt;^2)&lt;/p&gt;  &lt;p&gt;We use this notation to describe the growth rate of algorithms too. A brute force algorithm that checks each and every object against the next is called O(n^2) (quadratic growth). If you have 100 objects, you will have to do 100^2 = 10.000 checks.&lt;/p&gt;  &lt;p&gt;Having a O(n log(n)) algorithm is obviously better as it grows slower. If you have the same 100 objects, you will only have to do 100 * log(100) = 200 checks!&lt;/p&gt;  &lt;p&gt;To give a graphical view of the growth. X is the number of objects and Y is the number of collision checks that needs to be performed.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/TC-o816HI7I/AAAAAAAAANw/976PrTcneTE/s1600-h/Growth%5B3%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Growth" border="0" alt="Growth" src="http://lh4.ggpht.com/_Dhwvn65yBx0/TC-o9bQ7sdI/AAAAAAAAAN0/rMBtpcEjNkc/Growth_thumb%5B1%5D.png?imgmax=800" width="486" height="278" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;As you can see, when the number of items increase, the number of checks to perform increases much more rapidly in the n^2 function than the n*log(n) function.&lt;/p&gt;  &lt;p&gt;Here is a table of the mostly used notations:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="2" width="368"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="189"&gt;&lt;strong&gt;Notation&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="177"&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="206"&gt;O(1)&lt;/td&gt;        &lt;td valign="top" width="185"&gt;Constant&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="210"&gt;O(log n)&lt;/td&gt;        &lt;td valign="top" width="188"&gt;Logarithmic&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="211"&gt;O(n)&lt;/td&gt;        &lt;td valign="top" width="189"&gt;Linear&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="211"&gt;O(n log n)&lt;/td&gt;        &lt;td valign="top" width="189"&gt;Linearithmic&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="211"&gt;O(n^2)&lt;/td&gt;        &lt;td valign="top" width="189"&gt;Quadratic&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;You can find a more complete list in &lt;a href="http://en.wikipedia.org/wiki/Time_complexity#Table_of_common_time_complexities" target="_blank"&gt;this Wikipedia article&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-3996245089742756150?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/07/big-o-notation-summary.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3996245089742756150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3996245089742756150'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/07/big-o-notation-summary.html' title='The Big O notation – Summary'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Dhwvn65yBx0/TC-o9bQ7sdI/AAAAAAAAAN0/rMBtpcEjNkc/s72-c/Growth_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-3769976884297393271</id><published>2010-05-30T15:13:00.001+02:00</published><updated>2010-06-02T02:05:45.088+02:00</updated><title type='text'>The Ramer-Douglas-Peucker Polygon Simplification Algorithm</title><content type='html'>&lt;p&gt;One of the important algorithms in vector graphics and robotics is the Ramer-Douglas-Peucker algorithm. It simplifies a polygon by reducing the number of points by some tolerance. It was invented independently by &lt;a href="http://dx.doi.org/10.1016/S0146-664X(72)80017-0" target="_blank"&gt;Urs Ramer&lt;/a&gt; in 1972 and by &lt;a href="http://utpjournals.metapress.com/content/fm576770u75u7727/" target="_blank"&gt;David Douglas &amp;amp; Thomas Peucker&lt;/a&gt; in 1973. In 1992 it was improved by &lt;a href="http://www.cs.ubc.ca/cgi-bin/tr/1992/TR-92-07" target="_blank"&gt;John Hershberger &amp;amp; Jack Snoeyink&lt;/a&gt; at the cost of the algorithm only working with simple 2D planar polylines, and not in higher dimentions.&lt;/p&gt;  &lt;p&gt;Here is how it roughly works: &lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/TAJke1dADrI/AAAAAAAAAM8/pxa6qn3RJ00/s1600-h/220px-Douglas_Peucker%5B17%5D.png"&gt;&lt;img style="margin: 0px 0px 0px 20px; display: inline" title="220px-Douglas_Peucker" alt="220px-Douglas_Peucker" align="right" src="http://lh5.ggpht.com/_Dhwvn65yBx0/TAJkfVpx5pI/AAAAAAAAANA/M8Cm6-AhuII/220px-Douglas_Peucker_thumb%5B13%5D.png?imgmax=800" width="173" height="240" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;0. Start with a polygon.&lt;/p&gt;  &lt;p&gt;1. Make a polyline between the two endpoints. This is the initial approximation to the simplified polygon.&lt;/p&gt;  &lt;p&gt;2. Calculate the distance between the edge and the remaining vertices. If the vertex tested is further away that the user defined tolerance, then the vertex is added to the simplification.&lt;/p&gt;  &lt;p&gt;3. Repeat step 2 until you have a complete approximation of the polygon like shown in step 4 in the picture.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The idea with the algorithm is that we can give it an input like the one to the left and get an output like the one to the right:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/TAWfXtjtlOI/AAAAAAAAANU/hbCD_qzAUvg/s1600-h/simplifying-polygons-L.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="simplifying-polygons-L" border="0" alt="simplifying-polygons-L" src="http://lh5.ggpht.com/_Dhwvn65yBx0/TAJkkkd0XsI/AAAAAAAAANY/khx85eAerL4/simplifying-polygons-L_thumb%5B3%5D.jpg?imgmax=800" width="83" height="82" /&gt;&lt;/a&gt;&amp;#160;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/TAJklEW1NuI/AAAAAAAAANc/nh_QQrIQ91c/s1600-h/simplifying-polygons-R.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="simplifying-polygons-R" border="0" alt="simplifying-polygons-R" src="http://lh4.ggpht.com/_Dhwvn65yBx0/TAJkla-obvI/AAAAAAAAANk/ai8lVyU9RL0/simplifying-polygons-R_thumb%5B3%5D.jpg?imgmax=800" width="63" height="83" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;This gives us a lot of possibilities; it can reconstruct the original representation of a polygon and it can provide us with compression of the data. A large and complicated polygon can be simplified down to the bare essentials by reducing the details of the polygon.&lt;/p&gt;  &lt;p&gt;I’ve added this algorithm to &lt;a href="http://farseerphysics.codeplex.com/SourceControl/changeset/view/66371#1097936" target="_blank"&gt;Farseer Physics Engine 3.0&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-3769976884297393271?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/05/ramer-douglas-peucker-polygon.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3769976884297393271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3769976884297393271'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/05/ramer-douglas-peucker-polygon.html' title='The Ramer-Douglas-Peucker Polygon Simplification Algorithm'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Dhwvn65yBx0/TAJkfVpx5pI/AAAAAAAAANA/M8Cm6-AhuII/s72-c/220px-Douglas_Peucker_thumb%5B13%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6037374318888311094</id><published>2010-02-15T22:18:00.001+01:00</published><updated>2010-02-15T22:18:07.910+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game mechanics'/><title type='text'>Physics engine series</title><content type='html'>&lt;p&gt;A quick post to summarize the posts I’ve already made on physics engines. The series are not yet done. I will cover the broad and narrow phase algorithms when I get around to write about them.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-1.html" target="_blank"&gt;Part 1&lt;/a&gt; – The very basics of physics engines. What is the responsibility of a physics engine and how are they defined.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-2.html" target="_blank"&gt;Part 2&lt;/a&gt; – A quick overview of how a physics engine work. Collision detection, physics response and their submechanisms.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-3.html" target="_blank"&gt;Part 3&lt;/a&gt; – A look into the physics response part of a physics engine. How do we calculate velocity and how do we apply it using numerical integration.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6037374318888311094?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/02/physics-engine-series.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6037374318888311094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6037374318888311094'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/02/physics-engine-series.html' title='Physics engine series'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-2667778563122339625</id><published>2010-01-21T17:29:00.001+01:00</published><updated>2010-01-21T17:29:16.605+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Performance tips and tricks series</title><content type='html'>&lt;p&gt;In the past I posted 4 blogs posts with ways to optimize your applications using keywords, compiler tricks and approximations. Here is a quick overview of the blog posts:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-1.html" target="_blank"&gt;Part 1&lt;/a&gt; – Common sense in application development. Use constants and loop manipulation.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-2.html" target="_blank"&gt;Part 2&lt;/a&gt; – Most commonly used keywords in C#: sealed, static, struct, ref, out and unsafe&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-3.html" target="_blank"&gt;Part 3&lt;/a&gt; – Information about method inlining. Notes on virtual calls, struct arguments and exception handling. Short introduction to loop unrolling.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ianqvist.blogspot.com/2009/09/performance-tips-and-tricks-part-4.html" target="_blank"&gt;Part 4&lt;/a&gt; – Boxing and unboxing, more on exception handling and string operations&lt;/p&gt;  &lt;p&gt;Hopefully I will get the time to write some Xbox360 specific optimizations in the near future. I’m busy with the development of &lt;a href="http://www.codeplex.com/FarseerPhysics" target="_blank"&gt;Farseer Physics Engine 3.0&lt;/a&gt; at the moment, so it might take some time.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-2667778563122339625?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/01/performance-tips-and-tricks-series.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2667778563122339625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2667778563122339625'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/01/performance-tips-and-tricks-series.html' title='Performance tips and tricks series'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5949702386923162396</id><published>2010-01-08T01:26:00.001+01:00</published><updated>2010-01-08T01:26:10.338+01:00</updated><title type='text'>My Xbox 360 nightmares</title><content type='html'>&lt;p&gt;Once upon a time an open source software developer wrote a &lt;a href="http://farseerphysics.codeplex.com/" target="_blank"&gt;physics engine&lt;/a&gt; for the .net platform. (Let us call him &lt;u&gt;me&lt;/u&gt;!) Because of many requests from his users, he targeted Xbox360 as one of the supported platforms.&lt;/p&gt;  &lt;p&gt;The many users of his free physics engine felt generous and donated a Xbox360 so that he could optimize the physics engine for that platform. Overjoyed by the offer, he accepted and could not wait to see what kind of machine the Xbox360 really was.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Nightmare number 1     &lt;br /&gt;&lt;/strong&gt;After paying for a cheap Xbox360 Arcade on&amp;#160; the Internet he waited almost a month before realizing something was wrong. After 5 emails to the retailer and several weeks later, the order was finally canceled and he went on another journey to find a cheap retailer that would provide him with a brand new Xbox360.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Nightmare number 2     &lt;br /&gt;&lt;/strong&gt;After his first experience he checked out all the possible references to the new shop as he possible could. Customer comments, google ratings and even the famous &lt;a href="http://www.e-maerket.dk/"&gt;E-Mark&lt;/a&gt;. Little did he know that the retailer just repeated his experience from the first nightmare. After several weeks, he finally got his money back again.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The dream of a Xbox360     &lt;br /&gt;&lt;/strong&gt;Eager to try off a Xbox360, he went to a store with a brand new Xbox on display. He walked to the customer information desk, only to be informed that they had no Xbox360 left in the store. Feeling a taste of defeat he went outside the store to think about where to go next…&lt;/p&gt;  &lt;p&gt;&lt;u&gt;WAIT&lt;/u&gt; someone said from inside the store… the developer turned around to see a guy with a big greenish box with XBOX 360 written on the side. Renewed with joy and happiness he went to the checkout to get his brand new Xbox360 home. After connecting everything and make it look like the alter in a church, the Xbox360 turned on with all the glowing colors of 1080p HD.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Nightmare number 3     &lt;br /&gt;&lt;/strong&gt;Like a kid at Christmas time the developer turned on his computer and tried to connect to the Xbox360. Little did he know that it required an application that could be found in the &lt;a href="http://marketplace.xbox.com/en-US/games/media/66acd000-77fe-1000-9115-d802584e07d1/" target="_blank"&gt;Game Markedplace&lt;/a&gt;, and to get the application, he had to pay 1/2 the price of the Xbox he just bought. Thinking that nothing should stand in his way of getting it to work, he paid the amount necessary and started waiting. After waiting for what seemed liked ages, the account was finally recognized in the Xbox system of magic and he could deploy games with ease.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Nightmare number 4     &lt;br /&gt;&lt;/strong&gt;Getting tired of running the same physics simulation 100 times in a row and feeling curious about what else this new fancy thing could do, he decided to play some of the games that physics engine users had created. Clicking on the “free trial” link next to one of those games left him with a message saying “You have to be a gold member to play this game”… thinking that gold membership must be the Xbox world’s key to unlock all doors, he bought a gold membership and clicked the same link again. This time he got a new message saying: “This game is not available in your region”… Fury with rage he went to bed, cursing the name of Xbox while trying to sleep.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Back to the real world     &lt;br /&gt;&lt;/strong&gt;Well, That was all I had to go though… only to discover that I had no way of playing the games that used the fruits of my labor. Waiting so long to get a Xbox360, only to find out I’m left with a useless mini computer with no games on it and a deep hole in my pocket. I hope that they are going to put Denmark on the “allowed region” list soon or my expensive gold membership is going to be a total waste. Thanks for nothing so far Microsoft.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5949702386923162396?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2010/01/my-xbox-360-nightmares.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5949702386923162396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5949702386923162396'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2010/01/my-xbox-360-nightmares.html' title='My Xbox 360 nightmares'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8306301687255030115</id><published>2009-12-20T03:00:00.001+01:00</published><updated>2009-12-20T03:06:51.751+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web development'/><title type='text'>Facebook style auto-complete textbox in ASP.net</title><content type='html'>&lt;p&gt;You might have seen the crispy AJAX enabled auto-complete list when entering friends into a textbox. I was especially intrigued by the “Compose Message – To:” textbox. You enter a part of a name and almost instantly a list of names popup. Adding a name is as simple as selecting it from the list and it gets added to the textbox.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sy2FQrOnDbI/AAAAAAAAAMw/f_UxZYNyL2o/s1600-h/ComposeMessage%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ComposeMessage" border="0" alt="ComposeMessage" src="http://lh3.ggpht.com/_Dhwvn65yBx0/Sy2FQzA2QcI/AAAAAAAAAM0/9roA0IZRDPY/ComposeMessage_thumb.png?imgmax=800" width="562" height="237" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;I started to identify the different parts of this functionality:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Labels inside textbox &lt;/li&gt;    &lt;li&gt;Auto-completion on entering text &lt;/li&gt;    &lt;li&gt;Growable textbox size &lt;/li&gt;    &lt;li&gt;Highlighting of results &lt;/li&gt;    &lt;li&gt;Close button on labels &lt;/li&gt;    &lt;li&gt;Many more… &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It looked like a daunting task, so I decided to search for an already made solution instead of making one myself. I came across an &lt;a href="http://ajaxcontroltoolkit.codeplex.com/WorkItem/View.aspx?WorkItemId=18534" target="_blank"&gt;Ajax Control Toolkit issue&lt;/a&gt; that requested this functionality and even a &lt;a href="http://stackoverflow.com/questions/210308/nice-labels-with-x-in-to-field-of-compose-message" target="_blank"&gt;jQuery plugin mentioned on Stack Overflow&lt;/a&gt;. Seemed like a lot of people mentioned this functionality, but nothing really appealed to me until I found &lt;a href="http://devthought.com/projects/mootools/textboxlist/" target="_blank"&gt;TextboxList on DevThought.com&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;It immediately caught my attention since it had a working demo that was exactly what I wanted. The greatest thing about TextboxList is that it is simple and very extensible, so I started my journey to create a To: field like the one from Facebook.&lt;/p&gt;  &lt;h3&gt;ASP.net implementation&lt;/h3&gt;  &lt;p&gt;I’m working in ASP.net with C# and the demo provided by DevThought.com was PHP only. Since I have a past of PHP, I decided to quickly take a look at their demo and create a ASP.net clone.&lt;/p&gt;  &lt;p&gt;The only thing I did was to convert the auto-completion to C#. Everything else has just been taken from the original demo and fitted into a simple web site project. You can download the source code here:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://cid-f116593ba64184a2.skydrive.live.com/self.aspx/.Public/TextBoxListASP.net.zip" target="_blank"&gt;Download TextboxList ASP.net Demo&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8306301687255030115?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/12/facebook-style-autocomplete-textbox-in.html#comment-form' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8306301687255030115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8306301687255030115'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/12/facebook-style-autocomplete-textbox-in.html' title='Facebook style auto-complete textbox in ASP.net'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/Sy2FQzA2QcI/AAAAAAAAAM0/9roA0IZRDPY/s72-c/ComposeMessage_thumb.png?imgmax=800' height='72' width='72'/><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6524873663171915957</id><published>2009-11-23T01:43:00.001+01:00</published><updated>2009-11-23T22:03:05.969+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><title type='text'>Pseudo orientation in Farseer Physics Engine</title><content type='html'>&lt;p&gt;Farseer Physics Engine does not know about its object’s orientation. It has no clue about what is up and what is down. It only needs to know where other objects are in the physics world – nothing else. Sometimes it is good to know what is left, right, top and bottom. In this blog post I will describe a way of determining the side on which an object is hit, no matter the rotation of the object.&lt;/p&gt;  &lt;p&gt;Let’s take a simple box as an example:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SwnaixOf3eI/AAAAAAAAAMQ/esZZIStIQow/s1600-h/Box%5B9%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Box" border="0" alt="Box" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SwnajL3nO5I/AAAAAAAAAMU/zM6z8y6bbS8/Box_thumb%5B10%5D.png?imgmax=800" width="126" height="122" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;We can easily determine what is left, right, top and bottom on that box. We do it all the time in the real world. In geometry though, we need to calculate it. Imagine a circle inside the box. This circle is made up of 360 degrees or 2*π in radians. We can now use this circle to find out where the box was hit (left, right, top, bottom) by determining the angle at which the other object hit. &lt;/p&gt;  &lt;p&gt;A good reference to how radians are laid out on a circle can be &lt;a href="http://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Degree-Radian_Conversion.svg/600px-Degree-Radian_Conversion.svg.png" target="_blank"&gt;found on Wikipedia&lt;/a&gt;.     &lt;br /&gt;Now we end up with something like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SwnajryK0jI/AAAAAAAAAMY/Bbi4T0iQ748/s1600-h/Orientation%5B5%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Orientation" border="0" alt="Orientation" src="http://lh4.ggpht.com/_Dhwvn65yBx0/Swnaj-BDDYI/AAAAAAAAAMc/vFUmtXJkJb8/Orientation_thumb%5B1%5D.png?imgmax=800" width="126" height="122" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Now we need to determine the intervals of the angle values that makes up the 4 parts. &lt;/p&gt;  &lt;p&gt;Right side: π*1.75 to&amp;#160; π*2 and 0 to π*0.25    &lt;br /&gt;Bottom side: π*0.25 to π*0.75     &lt;br /&gt;Left side: π*0.75 to π*1.25     &lt;br /&gt;Top side: π*1.25 to π*1.75&lt;/p&gt;  &lt;p&gt;But since we are using the &lt;a href="http://en.wikipedia.org/wiki/Atan2" target="_blank"&gt;Atan2&lt;/a&gt; function that has a range from –π to π, we need a interval that is adjusted to that range:&lt;/p&gt;  &lt;p&gt;Right side: –π to (-3*π)/4 and (3*π)/4 to π   &lt;br /&gt;Bottom side: (-3*π)/4 to –π    &lt;br /&gt;Left side: 0 to π/4 and –π/4 to 0    &lt;br /&gt;Top side: π/4 to (3*π)/4&lt;/p&gt;  &lt;p&gt;Now that we know the interval of angle values to test against, we need something to test it with. Farseer Physics provide you with the normal of the collisionpoints (called contact). This is a vector pointing directly from the first geometry to the second.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Swnakd9kxYI/AAAAAAAAAMg/4RurzqlJqN0/s1600-h/TwoObjects%5B8%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="TwoObjects" border="0" alt="TwoObjects" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SwnakhJq2qI/AAAAAAAAAMk/w8rQoGdp9hc/TwoObjects_thumb%5B2%5D.png?imgmax=800" width="269" height="267" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;It looks like we can measure the angle of the normal and then see what interval it is within right? Wrong… What if this happens:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SwnalKESE-I/AAAAAAAAAMo/xWghDWN_fgU/s1600-h/TwoObjectsRotated%5B5%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="TwoObjectsRotated" border="0" alt="TwoObjectsRotated" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SwnalelzjDI/AAAAAAAAAMs/2j1UK3RsXKE/TwoObjectsRotated_thumb%5B1%5D.png?imgmax=800" width="269" height="267" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Remember, the object is rotated, the intervals are not! If we measured the angle against the intervals now, it would say that the right side of the box is hit, when it is the top that gets hit.&lt;/p&gt;  &lt;p&gt;The solution is to rotate either the intervals or the normal. I took the latter of the two. It can all be seen in the sample project below (Based on Farseer Physics Simple Samples for XNA):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://cid-f116593ba64184a2.skydrive.live.com/self.aspx/.Public/Farseer%20Physics%20Orientation.zip" target="_blank"&gt;Download sample project&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;(click the folder icon – XNA 3.1 needed to run it)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6524873663171915957?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/11/pseudo-orientation-in-farseer-physics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6524873663171915957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6524873663171915957'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/11/pseudo-orientation-in-farseer-physics.html' title='Pseudo orientation in Farseer Physics Engine'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Dhwvn65yBx0/SwnajL3nO5I/AAAAAAAAAMU/zM6z8y6bbS8/s72-c/Box_thumb%5B10%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6510342794565064115</id><published>2009-10-12T02:54:00.000+02:00</published><updated>2010-01-08T01:28:01.187+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Physics'/><title type='text'>2D Physics Engine Tutorial – Part 3</title><content type='html'>&lt;p&gt;In &lt;a href="http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-2.html" target="_blank"&gt;part 2&lt;/a&gt; we had a look at the collision detection part of physics engines. In this post we take a look at the collision response part and see what kind of mechanisms it involves.&lt;/p&gt;  &lt;h4&gt;Movement&lt;/h4&gt;  &lt;p&gt;Physics engines have the ability to move objects around both in linear and angular motion. It is done using linear and angular &lt;a href="http://en.wikipedia.org/wiki/Velocity" target="_blank"&gt;velocity&lt;/a&gt; (with &lt;a href="http://en.wikipedia.org/wiki/Speed" target="_blank"&gt;speed&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Accelleration" target="_blank"&gt;acceleration&lt;/a&gt;), &lt;a href="http://en.wikipedia.org/wiki/Force" target="_blank"&gt;force&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Numerical_ordinary_differential_equations" target="_blank"&gt;integrators&lt;/a&gt;.&lt;/p&gt;  &lt;h5&gt;Velocity&lt;/h5&gt;  &lt;p&gt;Velocity is a &lt;a href="http://en.wikipedia.org/wiki/Euclidean_vector" target="_blank"&gt;vector&lt;/a&gt; that describes the rate of change in position; the magnitude of the vector is the speed and the direction of the vector is the direction in which the speed is applied.&lt;/p&gt;  &lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; background-color: #eeeeee; padding-left: 5px; width: 550px; padding-right: 5px; margin-left: auto; border-top: black 1px solid; margin-right: auto; border-right: black 1px solid; padding-top: 5px"&gt;   &lt;p&gt;&lt;b&gt;Velocity definition&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/Sr_thwvRM5I/AAAAAAAAAKI/ziJ8oU5zjO8/s1600-h/901d56d788a63b1a2e5bf684ea444d5717.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="901d56d788a63b1a2e5bf684ea444d57" border="0" alt="901d56d788a63b1a2e5bf684ea444d57" src="http://lh5.ggpht.com/_Dhwvn65yBx0/Sr_tiyf-OnI/AAAAAAAAAKM/EAPiaZw03hY/901d56d788a63b1a2e5bf684ea444d57_thu.png?imgmax=800" width="74" height="42" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;&lt;strong&gt;v&lt;/strong&gt; is the velocity vector, &lt;strong&gt;Δx&lt;/strong&gt; is the displacement and &lt;strong&gt;Δt&lt;/strong&gt; is the change in time.&lt;/p&gt; &lt;/div&gt;  &lt;br /&gt;  &lt;h5&gt;Force&lt;/h5&gt;  &lt;p&gt;Force exist in many ways, but generally it is the agent that cause a body to change in motion or make a mass change its velocity. Force has both magnitude and direction and thus it can be expressed as a vector.&lt;/p&gt;  &lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; background-color: #eeeeee; padding-left: 5px; width: 550px; padding-right: 5px; margin-left: auto; border-top: black 1px solid; margin-right: auto; border-right: black 1px solid; padding-top: 5px"&gt;   &lt;p&gt;&lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Newton%27s_second_law#Newton.27s_second_law" target="_blank"&gt;Newton’s second law&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sr_tjMBPxoI/AAAAAAAAAKQ/ktks6yT8LPw/s1600-h/33559ed31bc09e706e6de860655b1fea5.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="33559ed31bc09e706e6de860655b1fea" border="0" alt="33559ed31bc09e706e6de860655b1fea" src="http://lh3.ggpht.com/_Dhwvn65yBx0/Sr_tjQRmFJI/AAAAAAAAAKU/5k8RhNAC77I/33559ed31bc09e706e6de860655b1fea_thu.png?imgmax=800" width="73" height="20" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;&lt;strong&gt;F&lt;/strong&gt; is the force vector, &lt;strong&gt;m&lt;/strong&gt; is the mass and &lt;strong&gt;a&lt;/strong&gt; is the acceleration vector.&lt;/p&gt; &lt;/div&gt;  &lt;br /&gt;  &lt;h5&gt;Acceleration&lt;/h5&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Acceleration" target="_blank"&gt;Acceleration&lt;/a&gt; is change in velocity over time. Acceleration can be defined by isolating &lt;strong&gt;a&lt;/strong&gt; from Newton’s second law:&lt;/p&gt;  &lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; background-color: #eeeeee; padding-left: 5px; width: 550px; padding-right: 5px; margin-left: auto; border-top: black 1px solid; margin-right: auto; border-right: black 1px solid; padding-top: 5px"&gt;   &lt;p&gt;&lt;b&gt;Acceleration definition&lt;/b&gt;&lt;/p&gt;    &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/Sr_tjkyjlSI/AAAAAAAAAKY/4KkIcuImz1s/s1600-h/Newtons2Law2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Newtons2Law" border="0" alt="Newtons2Law" src="http://lh5.ggpht.com/_Dhwvn65yBx0/Sr_tj5S-UiI/AAAAAAAAAKc/2kGjXwm3VvA/Newtons2Law_thumb.png?imgmax=800" width="217" height="21" /&gt;&lt;/a&gt; &lt;/p&gt;    &lt;p&gt;&lt;strong&gt;F&lt;/strong&gt; is the force vector, &lt;strong&gt;m&lt;/strong&gt; is the mass and &lt;strong&gt;a&lt;/strong&gt; is the acceleration.&lt;/p&gt; &lt;/div&gt;  &lt;br /&gt;  &lt;h4&gt;Integrator&lt;/h4&gt;  &lt;p&gt;In the previous velocity definition it is stated that velocity is the displacement over time. If we know the current position, velocity and the force that will be applied on it, we can integrate it to find its position and velocity at some point in the future. The integrator performs &lt;a href="http://en.wikipedia.org/wiki/Numerical_integration" target="_blank"&gt;numerical integration&lt;/a&gt;; that is – it takes a small step into the future and tries to find the next position and velocity an object will have – each time it takes a step, it will use the previous result as the new starting point. It works like this:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Use initial position, velocity and force &lt;/li&gt;    &lt;li&gt;Step 1 time step into the future and integrate to find the new position and velocity &lt;/li&gt;    &lt;li&gt;Add the position and velocity change to the previous position and velocity &lt;/li&gt;    &lt;li&gt;Go to step 1, using the results obtained in step 3. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;This way we can find the position and velocity of any object at any point in the future.&lt;/p&gt;  &lt;h6&gt;&lt;/h6&gt;  &lt;h5&gt;Euler’s method&lt;/h5&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Euler_method" target="_blank"&gt;Euler’s method&lt;/a&gt; is a simple first-order numerical integrator that we can use to integrate the position of an object. The step-by-step method mentioned above is used in Euler’s method.&lt;/p&gt;  &lt;p&gt;Solving an example using Euler’s method of integration:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sr_tkddSkXI/AAAAAAAAAKg/lCNpCqdbv_U/s1600-h/EulerIntegrationCode5.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="EulerIntegrationCode" border="0" alt="EulerIntegrationCode" src="http://lh6.ggpht.com/_Dhwvn65yBx0/Sr_tkmvIJDI/AAAAAAAAAKk/hUMUUmwvsY8/EulerIntegrationCode_thumb1.png?imgmax=800" width="349" height="241" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;If we run this code, we will get the following results:&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="2" width="298" border-color="black" border-collapse="collapse"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="89"&gt;&lt;strong&gt;Time&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="106"&gt;&lt;strong&gt;Position&lt;/strong&gt;&lt;/td&gt;        &lt;td valign="top" width="101"&gt;&lt;strong&gt;Velocity&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;0&lt;/td&gt;        &lt;td valign="top" width="106"&gt;0&lt;/td&gt;        &lt;td valign="top" width="101"&gt;0&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;1&lt;/td&gt;        &lt;td valign="top" width="106"&gt;0&lt;/td&gt;        &lt;td valign="top" width="101"&gt;10&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;2&lt;/td&gt;        &lt;td valign="top" width="106"&gt;10&lt;/td&gt;        &lt;td valign="top" width="101"&gt;20&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;3&lt;/td&gt;        &lt;td valign="top" width="106"&gt;30&lt;/td&gt;        &lt;td valign="top" width="101"&gt;30&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;4&lt;/td&gt;        &lt;td valign="top" width="106"&gt;60&lt;/td&gt;        &lt;td valign="top" width="101"&gt;40&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;5&lt;/td&gt;        &lt;td valign="top" width="106"&gt;100&lt;/td&gt;        &lt;td valign="top" width="101"&gt;50&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;6&lt;/td&gt;        &lt;td valign="top" width="106"&gt;150&lt;/td&gt;        &lt;td valign="top" width="101"&gt;60&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;7&lt;/td&gt;        &lt;td valign="top" width="106"&gt;210&lt;/td&gt;        &lt;td valign="top" width="101"&gt;70&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;8&lt;/td&gt;        &lt;td valign="top" width="106"&gt;280&lt;/td&gt;        &lt;td valign="top" width="101"&gt;80&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;9&lt;/td&gt;        &lt;td valign="top" width="106"&gt;360&lt;/td&gt;        &lt;td valign="top" width="101"&gt;90&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="89"&gt;10&lt;/td&gt;        &lt;td valign="top" width="106"&gt;450&lt;/td&gt;        &lt;td valign="top" width="101"&gt;100&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;The problem with this is that the result is not correct. Using the &lt;a href="http://library.thinkquest.org/28388/Mechanics/Motions/Equation.htm" target="_blank"&gt;equation of motion&lt;/a&gt; we should get 500 meters:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sr_tk0aMxfI/AAAAAAAAAKo/gQOSL-5eIlY/s1600-h/clip_image00242.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002[4]" border="0" alt="clip_image002[4]" src="http://lh6.ggpht.com/_Dhwvn65yBx0/Sr_tlIMKvbI/AAAAAAAAAKs/60d0pyzrew8/clip_image0024_thumb.gif?imgmax=800" width="254" height="20" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;But we got 450 using Euler’s method. That is because Euler is inaccurate when velocity over the time step is not constant. Using a smaller time step will get us closer to the real result, but it will always have an error.&lt;/p&gt;  &lt;p&gt;There are a lot of alternatives to Euler’s method:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Semi-implicit_Euler" target="_blank"&gt;Semi-implicit Euler&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods#The_common_fourth-order_Runge.E2.80.93Kutta_method" target="_blank"&gt;Runge-Kutta (RK4) &lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Verlet_integration" target="_blank"&gt;Verlet integration&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Midpoint_method" target="_blank"&gt;Midpoint method&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Leapfrog_integration" target="_blank"&gt;Leapfrog integration&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;All of them are more accurate than Euler’s method, but they can also be slower (RK4 needs 4 steps at each iteration as an example) and they are more advanced.&lt;/p&gt;  &lt;h4&gt;Overview&lt;/h4&gt;  &lt;p&gt;Here is an updated overview of the physics engine structure. We just added the Integrator part of the engine.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/StJaUDWShWI/AAAAAAAAALw/UW7HeF3KC5Q/s1600-h/image%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_Dhwvn65yBx0/StJaUWlJo4I/AAAAAAAAAL0/E49BRoyq_D4/image_thumb.png?imgmax=800" width="570" height="255" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6510342794565064115?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-3.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6510342794565064115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6510342794565064115'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-3.html' title='2D Physics Engine Tutorial – Part 3'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Dhwvn65yBx0/Sr_tiyf-OnI/AAAAAAAAAKM/EAPiaZw03hY/s72-c/901d56d788a63b1a2e5bf684ea444d57_thu.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8888551413450160736</id><published>2009-10-11T03:06:00.001+02:00</published><updated>2009-10-11T03:28:50.585+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Game mechanics'/><title type='text'>User managed games and automatic server checks</title><content type='html'>&lt;p&gt;Let me ask you one thing: Why does network-enabled games utilize user controlled user management (like kick voting menus)?&lt;/p&gt;  &lt;p&gt;The answer is really simply: &lt;u&gt;User management&lt;/u&gt;&lt;/p&gt;  &lt;h4&gt;User management&lt;/h4&gt;  &lt;p&gt;Network-enabled games need some kind of online-police that can control the game and its users. Imagine a rouge user that joins an online game just to create havoc and chaos. I have met several examples myself in my past as both server admin, game moderator and as a player. They all have one thing in common: Make people angry and laugh at their inability to act on it. Let us have a look at the different types of bad guys:&lt;/p&gt;  &lt;h5&gt;The microphone guy&lt;/h5&gt;  &lt;p&gt;The first case is a user that connects his microphone, turns up his music (Usually obnoxious repeating music designed to drive people crazy) and press the “talk” button. This can continue the whole game and it makes people furious. Players start to blame the game and game moderators that they are not doing anything about it, but fact is that they are powerless. Once the trend has started, not even an army of server admins can respond fast enough to prevent the damage.&lt;/p&gt;  &lt;h5&gt;The message spammer guy&lt;/h5&gt;  &lt;p&gt;This one continues to spam the chat with messages of random characters. Games where the chat is displayed onscreen with the rest of the HUD are the most vulnerable ones. A devious mind can easily exploit the fact that the length of messages are only wrapped at the length of the screen. This means that he can eventually fill up the whole screen with text and make other users unable to see anything.&lt;/p&gt;  &lt;p&gt;Example:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/StEvjlitSuI/AAAAAAAAALQ/R-yCbe2hr7A/s1600-h/Chatspam%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Chatspam" border="0" alt="Chatspam" src="http://lh4.ggpht.com/_Dhwvn65yBx0/StEvkD0KZcI/AAAAAAAAALU/TKmPI2hOARw/Chatspam_thumb.png?imgmax=800" width="505" height="176" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h5&gt;The foul mouth guy&lt;/h5&gt;  &lt;p&gt;The only purpose this guy has is to piss people off. He might not have bad intentions when starting the game, but as soon as someone addresses him, he sees an opportunity of playing a dangerous game of foul-mouthing. All kinds of bad words known to man are exchanged and if the game contains a profanity filter, it also becomes an exercise of finding words that are not included in the game blacklist. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The newbie hater guy&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160; Games should be equal toward all its users in the sense that it should not prefer experienced users over new users. Once a newbie has achieved some kind of experience, he might feel better when jumping on new players and make them feel stupid. This guy makes experienced users group together and flame the new users and make them feel guilty. It can create a bad user experience and eventually loss of players.&lt;/p&gt;  &lt;h5&gt;The idle guy&lt;/h5&gt;  &lt;p&gt;This guy spawns in the game and then go for a 15 minute toilet visit. The word “player” means that the guy is playing – if he is not playing, then he is only in the way of other users. Imagine a line at the supermarket where you have been standing for 10 minutes before you realize that the guy in front of you suffers from narcolepsy and fell asleep while still standing up. (bad example, I know - You get the point)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The newbie general&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This kind of guy really depends on the game. Some games contain a general or&amp;#160; commander seat where guy in that seat controls stuff other users can’t. A good example is the &lt;a href="http://savage2.com/en/main.php" target="_blank"&gt;Savage&lt;/a&gt; game where the job of the commander is giving buffs like heal, extra armor and give negative buffs to the enemy. Each game 1 player gets to know how to command and 10 players get experienced in fighting. This causes experienced commanders to become a rarity. Once a new user is in the commander seat, the game might as well announce the other team as the winners.&lt;/p&gt;  &lt;h4&gt;The evolution of games&lt;/h4&gt;  &lt;p&gt;All the cases listed above have in common that they create a bad user experience, lessen the quality of the game and fill up the forums with posts made by furious players. This is reflected in the reputation of the game and the loss of users (and again loss of money).&lt;/p&gt;  &lt;p&gt;The solution is quite simple: &lt;strong&gt;User controlled user management.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Since old times when the first popular network games started popping up, we have had bad guys. The thing about being a bad guy is that there are no consequences to your actions. They might be kicked if some user decide to report them, but the problem with that is that there might be hundreds of users each day and the response time is not always great. Realizing this fact some games implemented user controlled user management though voting menus and automatic filtering and checks.&lt;/p&gt;  &lt;p&gt;Listing the different mechanisms:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Aggressive profanity detection&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;Detect profanity and keep a statistic. Kick the user when too much profanity has been detected and remember to warn first. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;User kick vote&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;Users can initialize a kick vote towards a single user. This is useful in cases where automatic detection fails. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Text spamming detection&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;Put in a delay after 3 rapid messages and double the delay time each time this rule is violated. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Microphone spamming detection&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;Record the length of time spent on the microphone. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;User kick/spamming history&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;If a user is constantly getting kicked from servers or has a history of rule violations, investigate the case. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Idle player detection&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;When a user has not moved for 1 minute, kick him. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Game specific limitations&lt;/strong&gt;       &lt;ul&gt;       &lt;li&gt;Like the case of newbie commander, make sure that new players are sufficiently experienced before giving them commander status. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The bottom-line is that players and their collective attitude towards the game together with automatic “bad guy” detection is necessary to keep a game playable, we learned that though the evolution of networked games. It is more important than you might imagine and so easy to prevent.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8888551413450160736?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/10/user-managed-games-and-automatic-server.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8888551413450160736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8888551413450160736'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/10/user-managed-games-and-automatic-server.html' title='User managed games and automatic server checks'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Dhwvn65yBx0/StEvkD0KZcI/AAAAAAAAALU/TKmPI2hOARw/s72-c/Chatspam_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5792732261214636718</id><published>2009-10-05T19:25:00.001+02:00</published><updated>2011-02-21T21:58:12.838+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Floating and fixed point arithmetic</title><content type='html'>&lt;p&gt;A user posted a &lt;a href="http://farseerphysics.codeplex.com/Thread/View.aspx?ThreadId=71014" target="_blank"&gt;question&lt;/a&gt; on the Farseer Physics Engine forums about fixed point math. The topic include &lt;a href="http://en.wikipedia.org/wiki/Numeral_system" target="_blank"&gt;numeral systems&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/IEEE_754-2008" target="_blank"&gt;implementation details&lt;/a&gt; and performance. A &lt;a href="http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/IntroductionToFixedPointMath" target="_blank"&gt;whole&lt;/a&gt; lot of &lt;a href="http://www.mactech.com/articles/mactech/Vol.10/10.03/FixedPointMath/" target="_blank"&gt;posts&lt;/a&gt; have been &lt;a href="http://www.ddj.com/cpp/207000448" target="_blank"&gt;written&lt;/a&gt; about it. I’m not going to provide a full introduction to fixed point math, I’m simply going to provide an abstract answer to the questions (one that apply to similar questions).&lt;/p&gt;  &lt;h4&gt;Background&lt;/h4&gt;  &lt;p&gt;Back in the good old days (before the Intel &lt;a href="http://en.wikipedia.org/wiki/Intel_i486#Differences_between_the_386_and_486" target="_blank"&gt;i486 CPU&lt;/a&gt;) all applications used fixed point arithmetic. Floating point was something new where you could get a tradeoff between space, value range and precision, but at the cost of performance.&lt;/p&gt;  &lt;p&gt;Let us take a quick example: A fixed point number with the radix (point/dot) after the forth digit: 5186.3924, would be represented with a floating point as 51863924 with an exponent of 3:&lt;/p&gt; &lt;dl&gt;&lt;dd&gt;5.1863924*10^3 = 5186.3924&lt;/dd&gt;&lt;/dl&gt;  &lt;p&gt;Let us have a look at the up’s and down’s of floating point math.&lt;/p&gt;  &lt;h4&gt;Positive side of floating point&lt;/h4&gt;  &lt;p&gt;There are both positive and negative sides of floating point arithmetic. It is basically a tradeoff that the programmer needs to balance; choosing the lesser of two evils.&lt;/p&gt;  &lt;h5&gt;Greater range and precision&lt;/h5&gt;  &lt;p&gt;Floating point numbers have a greater range of number representations. You can’t write 0.00001234567 and 12.34567 with fixed point. The radix is fixed! You can with floating point and that is one of the main reasons we use floating point over fixed point. Let us take a look at the following example from &lt;a href="http://en.wikipedia.org/wiki/Floating_point#Range_of_floating-point_numbers" target="_blank"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;  &lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; background-color: #eeeeee; padding-left: 5px; width: 550px; padding-right: 5px; margin-left: auto; border-top: black 1px solid; margin-right: auto; border-right: black 1px solid; padding-top: 5px"&gt;   &lt;p&gt;In a decimal floating-point system with three digits, the multiplication that humans would write as&lt;/p&gt;   &lt;dl&gt;&lt;dd&gt;0.12 × 0.12 = 0.0144 &lt;/dd&gt;&lt;/dl&gt;    &lt;p&gt;would be expressed as&lt;/p&gt;   &lt;dl&gt;&lt;dd&gt;(1.2 × 10&lt;sup&gt;−1&lt;/sup&gt;) × (1.2 × 10&lt;sup&gt;−1&lt;/sup&gt;) = (1.44 × 10&lt;sup&gt;−2&lt;/sup&gt;). &lt;/dd&gt;&lt;/dl&gt;    &lt;p&gt;In a fixed-point system with the decimal point at the left, it would be&lt;/p&gt;   &lt;dl&gt;&lt;dd&gt;0.120 × 0.120 = 0.014. &lt;/dd&gt;&lt;/dl&gt;    &lt;p&gt;A digit of the result was lost because of the inability of the digits and decimal point to 'float' relative to each other within the digit string.&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;Since floating point numbers are split up into 2 numbers: &lt;u&gt;Significant&lt;/u&gt; and &lt;u&gt;exponent,&lt;/u&gt; it makes sense that the range of floating point numbers is defined by the number of bits allocated to the significant and exponent. There are different types of floating point data types available:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Single&lt;/strong&gt; – Single precision with 32 bits. Called &lt;a href="http://msdn.microsoft.com/en-us/library/b1e65aza%28VS.71%29.aspx" target="_blank"&gt;single&lt;/a&gt; or float in C#.       &lt;ul&gt;       &lt;li&gt;Range: ±1.5 × 10−&lt;sup&gt;45&lt;/sup&gt; to ±3.4 × 10&lt;sup&gt;38&lt;/sup&gt; &lt;/li&gt;        &lt;li&gt;Precision: 7 digits &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SsosGfToZ6I/AAAAAAAAAK4/yFieTZcdENs/s1600-h/32bit%20float%5B5%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="32bit float" border="0" alt="32bit float" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SsosGnFKjGI/AAAAAAAAAK8/rWR09aNcWQs/32bit%20float_thumb%5B1%5D.png?imgmax=800" width="504" height="75" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Double&lt;/strong&gt; – Double precision with 64 bits. Called &lt;a href="http://msdn.microsoft.com/en-us/library/678hzkk9%28VS.71%29.aspx" target="_blank"&gt;double&lt;/a&gt; in C#.       &lt;ul&gt;       &lt;li&gt;Range ±5.0 × 10−&lt;sup&gt;324&lt;/sup&gt; to ±1.7 × 10&lt;sup&gt;308&lt;/sup&gt; &lt;/li&gt;        &lt;li&gt;Precision: 15-16 digits &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SsosGyaf5VI/AAAAAAAAALA/Xqa12HzZUyw/s1600-h/64bit%20float%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="64bit float" border="0" alt="64bit float" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SsosHOmmZLI/AAAAAAAAALE/48G4jpLtXRg/64bit%20float_thumb.png?imgmax=800" width="618" height="125" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;There are even 128 bit versions with a higher range and precision.&lt;/p&gt;  &lt;h4&gt;Negative side of floating point&lt;/h4&gt;  &lt;p&gt;Floating point numbers comes at a cost. One is space, but that is neglectable in today’s computers with the high amount of RAM and huge bandwidth. More important is accuracy and performance of the arithmetic operations associated with floating point.&lt;/p&gt;  &lt;h5&gt;Performance&lt;/h5&gt;  &lt;p&gt;As mentioned before, the &lt;a href="http://en.wikipedia.org/wiki/Intel_i486#Differences_between_the_386_and_486" target="_blank"&gt;i486 CPU&lt;/a&gt; was the first CPU to get an &lt;a href="http://en.wikipedia.org/wiki/Floating_point_unit" target="_blank"&gt;FPU&lt;/a&gt; and thus the floating point operations were no longer emulated (or run via a coprocessor). This sped up the operations by a large factor. Nearly all CPUs today have an FPU located inside of them. Graphics cards are also one big FPU – it specializes in floating point math and can process a huge amount of floating point numbers.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;So what is the problem?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Well, as the forum &lt;a href="http://farseerphysics.codeplex.com/Thread/View.aspx?ThreadId=71014" target="_blank"&gt;post&lt;/a&gt; points out, some devices does not have a FPU and even if they do, their floating point operations can be &lt;strong&gt;magnitudes slower&lt;/strong&gt; than fixed point operations. A good example is the Xbox 360 platform. It does have an FPU and it even has the &lt;a href="http://en.wikipedia.org/wiki/AltiVec" target="_blank"&gt;AltiVec&lt;/a&gt; instruction set. But the software designed for the Xbox 360 (the .Net Compact Framework - NetCF for short) does not utilize those instructions. This means we have &lt;a href="http://blogs.msdn.com/netcfteam/archive/2006/12/22/managed-code-performance-on-xbox-360-for-the-xna-framework-1-0.aspx" target="_blank"&gt;lower floating point throughput&lt;/a&gt; on the Xbox360.&lt;/p&gt;  &lt;h5&gt;Accuracy&lt;/h5&gt;  &lt;p&gt;Floating point numbers have a bad reputation of being inaccurate. Floating point are not able to represent numbers like π or 0.1 correctly and inaccuracies may create inconsistency in your application. Lets take an example:&lt;/p&gt;  &lt;p&gt;If you take the sine of pi, then it should yield zero: sin(π) = 0    &lt;br /&gt;That is not the case with most (if not all) floating point implementations.&amp;#160; sin(π) in C# yield the following result with double precision:&lt;/p&gt; &lt;dl&gt;&lt;dd&gt;1.22460635382238&lt;sup&gt;-16&lt;/sup&gt;&lt;/dd&gt;&lt;/dl&gt;  &lt;p&gt;Equality checks are also a cause of concern. If you check a condition like sin(π) = 0 then it will yield false even though it is mathematically true. Normally we use &lt;a href="http://en.wikipedia.org/wiki/Machine_epsilon" target="_blank"&gt;epsilon&lt;/a&gt; and check the equality up against that.&lt;/p&gt;  &lt;p&gt;The crazy part of this is that the floating point standard is not the same on different platforms. The implementation on an Intel CPU might be different from an AMD CPU. The differences can also sometimes lie in the operation system – further fueling the inaccuracies across platforms.&lt;/p&gt;  &lt;h4&gt;The solution&lt;/h4&gt;  &lt;p&gt;There are no perfect solution. As mentioned before it is a tradeoff and sometimes floating point is the way to go. However, there are some alternatives.&lt;/p&gt;  &lt;h5&gt;Fixed point&lt;/h5&gt;  &lt;p&gt;Fixed point math is based on simple integers. You can represent the number 1.200 by the value of 1200 and a scaling factor of 100. Most fixed point libraries implement a fixed point version of integer and then use &lt;a href="http://www.irixtech.com/java/tutorials/binary-shift-operations" target="_blank"&gt;bit-shifting&lt;/a&gt; to scale the values.&lt;/p&gt;  &lt;p&gt;Fixed point math has some advantages over floating point:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Same behavior on all platforms (&lt;a href="http://ianqvist.blogspot.com/2009/08/simulators-and-determinism.html" target="_blank"&gt;deterministic&lt;/a&gt;) &lt;/li&gt;    &lt;li&gt;Faster on platforms without FPU (and sometimes even with FPU) &lt;/li&gt;    &lt;li&gt;Lower space usage &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;But as always, there is a downside too:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Complex implementations &lt;/li&gt;    &lt;li&gt;Lower range of values &lt;/li&gt;    &lt;li&gt;Overhead of constantly scaling values &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Double precision&lt;/h5&gt;  &lt;p&gt;Double precision floating point data types are 64bit and have a higher precision than normal 32bit floating point. This is not really a solution as it simply shifts the problem to a whole other dimension. It might lower the impact of the problem, but it does not go away. Sometimes it is sufficient to switch to doubles and it is far easier to do than converting everything to fixed point math.&lt;/p&gt;  &lt;p&gt;This solution only works on platforms with an FPU as it will run even slower than single precision floats.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5792732261214636718?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/10/floating-and-fixed-point-arithmetic.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5792732261214636718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5792732261214636718'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/10/floating-and-fixed-point-arithmetic.html' title='Floating and fixed point arithmetic'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/SsosGnFKjGI/AAAAAAAAAK8/rWR09aNcWQs/s72-c/32bit%20float_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-7584087166048534060</id><published>2009-09-25T19:06:00.001+02:00</published><updated>2009-09-27T19:29:38.363+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Physics'/><title type='text'>2D Physics Engine Tutorial – Part 2</title><content type='html'>&lt;p&gt;In &lt;a href="http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-1.html" target="_blank"&gt;part 1&lt;/a&gt; I explained what a physics engine does and what kind of physics engines there exists. This post will focus on the collision detection internals of physics engines.&lt;/p&gt;  &lt;h4&gt;Overview&lt;/h4&gt;  &lt;p&gt;A physics engine does two things: Collision detection and physics reaction. They work seamless together to create the illusion of things colliding and bouncing back.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/Srz4cH14jWI/AAAAAAAAAJg/WKrKTeg-H8M/s1600-h/Drawing1%5B5%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Drawing1" border="0" alt="Drawing1" src="http://lh3.ggpht.com/_Dhwvn65yBx0/Srz4ctuUrRI/AAAAAAAAAJk/H0P0kRvc36I/Drawing1_thumb%5B1%5D.png?imgmax=800" width="360" height="155" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h5&gt;Collision Detection&lt;/h5&gt;  &lt;p&gt;The collision detection part of the engine is responsible for detecting when things overlap and by how much they overlap. Most physics engines have developed a two-tier architecture where you first detect if objects are near each other using a crude representation of the object. Then it performs the collision detection on the objects itself using its real representation. It basically is setup like this:&lt;/p&gt;  &lt;h5&gt;Broad phase&lt;/h5&gt;  &lt;p&gt;The broad phase is the one responsible for detecting objects near each other. It was developed to speed up the collision detection phase by reducing the amount of collision checks needed. Imagine a simulation containing 11 balls; the engine would need to do 121 (11^2) expensive (real shape) collision checks. If a broad phase is introduced, this number of checks can be reduced to a smaller amount. Broad phase algorithms usually use &lt;a href="http://en.wikipedia.org/wiki/Axis-aligned_bounding_box#Axis-aligned_minimum_bounding_box" target="_blank"&gt;AABB&lt;/a&gt;s to represent a crude shape of the object. It is a lot cheaper to test AABB vs. AABB than a polygon vs. polygon.&lt;/p&gt;  &lt;p&gt;The example from before with 11 balls would in the following images only have to do 121 cheap tests and 25 (5^2) expensive checks.&lt;/p&gt;  &lt;p&gt;With and without AABBs:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Srz4c0BvbvI/AAAAAAAAAJo/Xgp3gZoeJ7E/s1600-h/WithoutAABB%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="WithoutAABB" border="0" alt="WithoutAABB" src="http://lh5.ggpht.com/_Dhwvn65yBx0/Srz4dIcEthI/AAAAAAAAAJs/UASwbY8_0Yw/WithoutAABB_thumb.png?imgmax=800" width="240" height="180" /&gt;&lt;/a&gt; &lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/Srz4dVHE7JI/AAAAAAAAAJw/fku5R1Cgdbk/s1600-h/WithAABB%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="WithAABB" border="0" alt="WithAABB" src="http://lh3.ggpht.com/_Dhwvn65yBx0/Srz4dufkhbI/AAAAAAAAAJ0/IpecbQcX4UE/WithAABB_thumb.png?imgmax=800" width="240" height="180" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;There exists a lot of algorithms to do broad phase tests:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Brute-force_search" target="_blank"&gt;Brute force&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Sweep_and_prune" target="_blank"&gt;Sweep and prune&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Dynamic_tree" target="_blank"&gt;Dynamic tree&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://users.design.ucla.edu/~mflux/p5/hashcollision2/applet/" target="_blank"&gt;Spatial hash&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Binary_space_partitioning" target="_blank"&gt;BSP tree&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Quadtree" target="_blank"&gt;QuadTree&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;All of them have in common that they divide the screen up into smaller parts using trees (flat or hierarchical), grid or axis-division. Have in mind that no broad phase algorithm is the “best” – it depends on the situation in which they are used.&lt;/p&gt;  &lt;h5&gt;Narrow phase&lt;/h5&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;When the broad phase has detected that two objects are near each other (their crude representations intersect) the engine should create a pair (sometimes called an arbiter) that contains the two objects. The objects are then tested using the narrow phase algorithm. Unlike the broad phase, the narrow phase tests the real shapes (polygons) against each other. This is an expensive test in most cases since a polygon can be anything from 3 to &lt;em&gt;n&lt;/em&gt; points. The narrow phase algorithm needs to find the following information:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Does a collision exist &lt;/li&gt;    &lt;li&gt;Position &lt;/li&gt;    &lt;li&gt;Normal &lt;/li&gt;    &lt;li&gt;Distance &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The last 3 items are vital for the collision response phase. The information is used to generate a contact; it contains the previous gathered information and can be persisted over several time steps.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Srz4d_t_faI/AAAAAAAAAJ4/ohg0_wS_xh4/s1600-h/ContactPoint%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ContactPoint" border="0" alt="ContactPoint" src="http://lh3.ggpht.com/_Dhwvn65yBx0/Srz4ecmpV8I/AAAAAAAAAJ8/D9CsHd1Gbao/ContactPoint_thumb.png?imgmax=800" width="318" height="322" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;font color="#008000"&gt;Green&lt;/font&gt;: Normal of contact point     &lt;br /&gt;&lt;font color="#ff0000"&gt;Red&lt;/font&gt;: Centroid     &lt;br /&gt;&lt;strong&gt;Black&lt;/strong&gt;: Shortest distance to collision point&lt;/p&gt;  &lt;p&gt;Just like the broad phase collision detection system, there are a lot of narrow phase algorithms:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Gilbert%E2%80%93Johnson%E2%80%93Keerthi_distance_algorithm" target="_blank"&gt;GJK&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.codersnotes.com/notes/signed-distance-fields" target="_blank"&gt;Signed Distance Field&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://lab.polygonal.de/2009/01/11/feature-based-geometrical-algorithms/" target="_blank"&gt;VClip&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Separating_axis_theorem" target="_blank"&gt;SAT&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm" target="_blank"&gt;Raycasting&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Improved overview&lt;/h4&gt;  &lt;p&gt;Now that the collision detection system has been identified, the new overview looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/Srz4egSPhmI/AAAAAAAAAKA/fCwXI3TcjDc/s1600-h/image%5B5%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_Dhwvn65yBx0/Srz4e3jrJcI/AAAAAAAAAKE/CLQb9-WGtTk/image_thumb%5B1%5D.png?imgmax=800" width="464" height="255" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-7584087166048534060?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-2.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7584087166048534060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7584087166048534060'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-2.html' title='2D Physics Engine Tutorial – Part 2'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/Srz4ctuUrRI/AAAAAAAAAJk/H0P0kRvc36I/s72-c/Drawing1_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5896991227767720311</id><published>2009-09-25T15:39:00.001+02:00</published><updated>2009-09-26T20:32:20.415+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Physics'/><title type='text'>2D Physics Engine Tutorial – Part 1</title><content type='html'>&lt;p&gt;In this article series the focus will be on identifying the different parts of a physics engine and then how we can implement those parts as simple as possible. There are tons of &lt;a href="http://en.wikipedia.org/wiki/Physics_engine#Real-time_physics_engines" target="_blank"&gt;2D and 3D engines available&lt;/a&gt; on the internet – this is not going to be a contestant to any of those engines, it will purely function as an educational physics engine to better grasp the concepts behind it.&lt;/p&gt;  &lt;h4&gt;What does a physics engine do&lt;/h4&gt;  &lt;p&gt;Almost all games need some way of detecting if two objects collide and respond using the proper reaction. It might be Mario standing on top of a platform or Max Payne shooting a bad guy – they both need collision detection and physics.&lt;/p&gt;  &lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; background-color: #eeeeee; padding-left: 5px; width: 550px; padding-right: 5px; margin-left: auto; border-top: black 1px solid; margin-right: auto; border-right: black 1px solid; padding-top: 5px"&gt;&lt;b&gt;Wikipedia definition&lt;/b&gt;     &lt;br /&gt;A physics engine is a computer program that simulates physics models, using variables such as mass, velocity, friction, and wind resistance. It can simulate and predict effects under different conditions that would approximate what happens in real life or in a fantasy world. Its main uses are in scientific simulation and in video games. &lt;/div&gt;  &lt;p&gt;Physics engines can be used for so much more than just fun and games:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=-yoXkWpcOu8&amp;amp;feature=PlayList&amp;amp;p=C5DFB616BF8042CA&amp;amp;playnext=1&amp;amp;playnext_from=PL&amp;amp;index=21" target="_blank"&gt;Robot dynamics&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.custom-logic.com/exp/cloth/cloth.html" target="_blank"&gt;Cloth simulation&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=L7PR58fqxgg" target="_blank"&gt;Transport security&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=mSR2z6naFtI" target="_blank"&gt;Fluid Simulations&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.youtube.com/watch?v=kwNvXPEzO-Q" target="_blank"&gt;Wind tunnel testing&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Much more… &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;To us it is naturally that if we toss a ball against a wall, it will hit the wall and bounce back. In the computer world all this has to be simulated.&lt;/p&gt;  &lt;h4&gt;Types of physics engines&lt;/h4&gt;  &lt;p&gt;There are two different kinds of physics engines. One of them is used for soft body (deformable) objects and the other is used for rigid body objects (hard/non-deformable)&lt;/p&gt;  &lt;h5&gt;Soft body physics&lt;/h5&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Soft_body_dynamics" target="_blank"&gt;Soft body engines&lt;/a&gt; are used for deformable physics such as cloth, rubber, jelly or balloons. You can enlarge, rip or puncture a soft body in any way you want. There are both &lt;a href="http://www.youtube.com/watch?v=JncQOCg9FS0" target="_blank"&gt;3D soft body engines&lt;/a&gt; and &lt;a href="http://walaber.com/index.php?action=showitem&amp;amp;id=17" target="_blank"&gt;2D soft body engines&lt;/a&gt;. Most of them define their shapes using triangles (or particles) that can change properties (side lengths and angles) and thus deform the body that contains the triangle.&lt;/p&gt;  &lt;p&gt;Soft body dynamics are hard to work with because of the deformations applied to a body. If a body needs to try and &lt;a href="http://www.youtube.com/watch?v=exss517n1I0" target="_blank"&gt;keep its original shape&lt;/a&gt;, all the deformations will have to be kept track off and slowly be resolved to gain its original shape.&lt;/p&gt;  &lt;h5&gt;Rigid body physics&lt;/h5&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Rigid_body_dynamics" target="_blank"&gt;Rigid body engines&lt;/a&gt; are used for non-deformable physics such as spacecrafts, buildings, terrain, player characters and more. They can’t be deformed in any way and only support linear (movement) and angular (rotation)&amp;#160; motion.&lt;/p&gt;  &lt;p&gt;Rigid body engines are a lot easier to work with compared to soft body physics. You only have to keep track of movement on the x, y and z-axis and rotation around the &lt;a href="http://en.wikipedia.org/wiki/Centroid" target="_blank"&gt;centroid&lt;/a&gt; of the object.&lt;/p&gt;  &lt;p&gt;Play Doh (Soft) and a metal box (Rigid):&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SrzLOm-WjSI/AAAAAAAAAJQ/irt-VXfGCmc/s1600-h/SoftRigid%5B20%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Soft versus rigid body" border="0" alt="Soft versus rigid body" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SrzLO7yKvuI/AAAAAAAAAJU/8tgRiZdb-_Y/SoftRigid_thumb%5B12%5D.png?imgmax=800" width="534" height="200" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h4&gt;Real-time vs. High-precision&lt;/h4&gt;  &lt;p&gt;How all this is calculated depends on the type of engine used. There are generally two different types of engines:&lt;/p&gt;  &lt;h5&gt;Real-Time&lt;/h5&gt;  &lt;p&gt;Real-time engines are typically used in games and other real time applications. They are used to simulate the game environment, vehicle dynamics, player interactions and more. Real-time engines are usually more focused on performance than accuracy – when a tree falls on a vehicle, we don’t need to know where every single fiber of the tree hits the vehicle with a accuracy of 0.01 mm.&lt;/p&gt;  &lt;p&gt;They are identified by the following characterizes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Iterative_method" target="_blank"&gt;Iterative&lt;/a&gt; algorithms &lt;/li&gt;    &lt;li&gt;Low accuracy &lt;/li&gt;    &lt;li&gt;High number of concurrent objects &lt;/li&gt;    &lt;li&gt;Game oriented tools &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;High-Precision&lt;/h5&gt;  &lt;p&gt;This kind of engine is mostly used in scientific applications and animated movies. They are used to simulate weather, train collisions, explosions and space shuttle trajectory. They can’t be used for real-time applications because they are too expensive in their computations.&lt;/p&gt;  &lt;p&gt;They are identified by the following characterizes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Single pass algorithms &lt;/li&gt;    &lt;li&gt;High accuracy and precision &lt;/li&gt;    &lt;li&gt;Low number of concurrent objects &lt;/li&gt;    &lt;li&gt;Scientific application tools &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5896991227767720311?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5896991227767720311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5896991227767720311'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/09/2d-physics-engine-tutorial-part-1.html' title='2D Physics Engine Tutorial – Part 1'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_Dhwvn65yBx0/SrzLO7yKvuI/AAAAAAAAAJU/8tgRiZdb-_Y/s72-c/SoftRigid_thumb%5B12%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8414251596426073689</id><published>2009-09-20T00:34:00.001+02:00</published><updated>2009-09-21T19:59:07.090+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Physics'/><title type='text'>Hybrid narrow phase using convexity detection</title><content type='html'>&lt;p&gt;While writing &lt;a href="http://ianqvist.blogspot.com/2009/09/convex-polygon-based-collision.html" target="_blank"&gt;Convex polygon based collision detection&lt;/a&gt; I came up with the idea of using a hybrid narrow phase to maximize usability and performance. It might have been thought of before and if you stumble upon this, I would like to hear your thoughts about it.&lt;/p&gt;  &lt;p&gt;It basically consist of taking the pairs found in the broad phase and checking the convexity of the polygons before sending them down to the narrow phase. As I described in the earlier post, SAT only works on convex polygons because it uses the separating axis between two non-colliding convex polygons. This limits the users of the engine to use convex polygons only and thus resort to methods of convex decomposition to get concave polygon support.&lt;/p&gt;  &lt;p&gt;If the polygons were checked for their convexity before being send to the narrow phase, the engine could send the pair of potentially colliding polygons to a narrow phase of its choice - depending on the composition of the pair:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Convex vs. concave – Send to concave narrow phase &lt;/li&gt;    &lt;li&gt;Convex vs. convex – Send to convex narrow phase &lt;/li&gt;    &lt;li&gt;Concave vs. concave – Send to concave narrow phase &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The convexity check could even be done at tool-time or engine startup. Whenever the vertices of an object changes it needs to redo the convexity check.&lt;/p&gt;  &lt;h4&gt;Problems that it would solve:&lt;/h4&gt;  &lt;h5&gt;Small angles &lt;/h5&gt;  &lt;p&gt;Some triangulation algorithms try to maximize the minimum angle of the triangles (like &lt;a href="http://en.wikipedia.org/wiki/Delaunay_triangulation" target="_blank"&gt;Delaunay Triangulation&lt;/a&gt;). But most will come up with a result that contains narrow triangle and thus it can cause tunneling problems.&lt;/p&gt;  &lt;h5&gt;Convex seems &lt;/h5&gt;  &lt;p&gt;Composing a concave polygon from several convex polygons will create a lot of seems (part where the polygons meet) and that can cause trouble for most 2D physics engines. Unrealistic collisions and hiccups can occur in the middle of a collision.&lt;/p&gt;  &lt;h5&gt;Holes&lt;/h5&gt;  &lt;p&gt;Because of the precision and accuracy of algorithms (due to iterative nature and float errors) – cases of no-intersection can happen when an intersection is expected. Imagine two narrow triangles where the narrow part are up against each other. A small gap can exist between the triangles and a ray cast in between the two triangles would go right though it. This can of course be solved by extending the edges a little.&lt;/p&gt;  &lt;h4&gt;Problems that it would create:&lt;/h4&gt;  &lt;p&gt;&lt;strong&gt;Memory issue&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The main issue would be memory consumption. Instead of a single narrow phase algorithm you would now have a dual algorithm. Using a narrow phase collider like the Signed Distance Field can consume a lot of memory.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Expensive to change polygons&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Again, if you use a narrow phase collider like the SDF you need to recalculate both the convexity check and the cached grid containing the narrow phase data for the physics object. Most games don’t change polygons on the fly, so this should not be a major issue.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8414251596426073689?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/09/hybrid-narrow-phase-using-convexity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8414251596426073689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8414251596426073689'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/09/hybrid-narrow-phase-using-convexity.html' title='Hybrid narrow phase using convexity detection'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6278024262114070586</id><published>2009-09-20T00:12:00.001+02:00</published><updated>2009-09-20T00:12:47.922+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Physics'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Convex polygon based collision detection</title><content type='html'>&lt;p&gt;A lot of people have asked me: Why use a convex polygon only engine like Box2D? In this post I will provide some info on why convex polygons is the optimal polygon type to use.&lt;/p&gt;  &lt;h4&gt;What does convex mean?&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Convex_polygon" target="_blank"&gt;Convex polygons&lt;/a&gt; needs to satisfy the following requirements:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;All internal angles must be below 180 degrees&lt;/li&gt;    &lt;li&gt;Every line segment between two vertices can be contained fully inside or at the edge the polygon&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SrVXWlskp3I/AAAAAAAAAIw/vFgA2HaEwqw/s1600-h/Convex-Concave%5B11%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Convex-Concave" border="0" alt="Convex-Concave" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SrVXXJORk3I/AAAAAAAAAI0/ZPBCCIFaATw/Convex-Concave_thumb%5B7%5D.png?imgmax=800" width="296" height="137" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;A non-convex polygon is called a concave polygon and it must have an internal angle measuring greater than 180 degrees. As you might have thought about yourself; concave polygons can be quite handy. Convex-only engines can’t represent a simple player polygon like &lt;a href="http://en.wikipedia.org/wiki/Pac-Man" target="_blank"&gt;Pac-Man&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Why use convex-only?&lt;/h4&gt;  &lt;p&gt;There are really only one big juicy reason: &lt;strong&gt;performance&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Physics engines are able to take quite a few shortcuts and use cheap algorithms to determine the closest vertex, shortest distance and a lot more. An algorithm like &lt;a href="http://en.wikipedia.org/wiki/Separating_axis_theorem" target="_blank"&gt;Separating Axis Theorem&lt;/a&gt; and the &lt;a href="http://www.google.dk/url?sa=t&amp;amp;source=web&amp;amp;ct=res&amp;amp;cd=3&amp;amp;url=http%3A%2F%2Fwww.cosy.sbg.ac.at%2F~held%2Fteaching%2Fbakk_seminar%2Fse_arbeiten_07-08%2FKollisionserkennungGJK.pdf&amp;amp;ei=qj-1SvCmI4ul4Qablql8&amp;amp;rct=j&amp;amp;q=GJK+algorithm&amp;amp;usg=AFQjCNFKqrM_oKLDo2rtjsMwyroi802FgA" target="_blank"&gt;Gilbert – Johnson – Keerthi (GJK)&lt;/a&gt; (pdf) algorithm both operate on convex polygons and provide fast, yet robust methods of getting collision information. Fundamentally there are two great features of convex polygons:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The existence of a separating plane between two non-colliding convex polygons&lt;/li&gt;    &lt;li&gt;When two points on two different geometries are at a minimum, they are at a &lt;a href="http://en.wikipedia.org/wiki/Convex_function#Properties" target="_blank"&gt;global minimum&lt;/a&gt;.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;That might sound like gibberish for the layman. I’m not going to explain what those two characteristics involve, but suffice to say that you can cut down on the complexity of the algorithms used.&lt;/p&gt;  &lt;h4&gt;Problems with using convex-only engines&lt;/h4&gt;  &lt;p&gt;In a performance point of view there are really no problems with using convex-only algorithms. The problems that arise are mainly usability (ease of use and convenience for the users). If the user supply the engine with a concave polygon, all kinds of weird collisions will happen. A check is needed to make sure the supplied polygon is of convex nature. But that topic is reserved for another blog post.&lt;/p&gt;  &lt;p&gt;The main approach for supporting concave polygons in a convex-only engines is described below.&lt;/p&gt;  &lt;h5&gt;Convex decomposition&lt;/h5&gt;  &lt;p&gt;This method involves the use of either triangulation algorithms or algorithms that finds a number of convex polygons from a convex polygon. The idea behind convex decomposition is to simply split a concave polygon into smaller convex polygons. This way a convex-only engine can support concave polygons. A lot of algorithms exist to do this. To name a few: &lt;a href="http://en.wikipedia.org/wiki/Polygon_triangulation#Subtracting_ears_method" target="_blank"&gt;Earclip&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Delaunay_triangulation" target="_blank"&gt;Delaunay triangulation&lt;/a&gt; and &lt;a href="http://www.gamedev.net/reference/articles/article408.asp" target="_blank"&gt;Seidel’s triangulation algorithm&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Here is an example of a triangulated concave polygon using a &lt;a href="http://code.google.com/p/poly2tri/" target="_blank"&gt;Constrained Delaunay Triangulation&lt;/a&gt; algorithm.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SrVXXbq-vOI/AAAAAAAAAI4/c45eQz5eCAI/s1600-h/cdt-dude%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="cdt-dude" border="0" alt="cdt-dude" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SrVXXon5UNI/AAAAAAAAAI8/XG9Q89o2YCA/cdt-dude_thumb%5B1%5D.png?imgmax=800" width="169" height="299" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6278024262114070586?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/09/convex-polygon-based-collision.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6278024262114070586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6278024262114070586'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/09/convex-polygon-based-collision.html' title='Convex polygon based collision detection'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/SrVXXJORk3I/AAAAAAAAAI0/ZPBCCIFaATw/s72-c/Convex-Concave_thumb%5B7%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6472528857323059535</id><published>2009-09-03T23:40:00.001+02:00</published><updated>2010-08-20T00:45:42.207+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Performance tips and tricks – part 4</title><content type='html'>&lt;p&gt;In &lt;a href="http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-3.html" target="_blank"&gt;part 3&lt;/a&gt; I explained some common manual compiler optimization tricks. This time we go back to the code itself to find places where optimizations does a difference.&lt;/p&gt;  &lt;h4&gt;Boxing and unboxing&lt;/h4&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx" target="_blank"&gt;Boxing&lt;/a&gt; is the process of encapsulating a value type into a reference type. Unboxing is the reverse process. They both take some time and might happen several times in your application without your knowledge. Here is some example code on boxing/unboxing:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SqA35alzqwI/AAAAAAAAAII/crJNc50S0Fc/s1600-h/Boxunbox5.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Box-unbox" border="0" alt="Box-unbox" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SqA35mZItrI/AAAAAAAAAIM/_IQxj4Veuuc/Boxunbox_thumb1.png?imgmax=800" width="316" height="45" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Since &lt;a href="&amp;quot;C:\Users\genbox\Desktop\Box-unbox.PNG&amp;quot;" target="_blank"&gt;int&lt;/a&gt; is a primitive and thus a value type, it gets boxed and stored on the heap (where reference types live, compared to stack where value types live). This makes our lifes easy, but it also comes at a &lt;a href="http://msdn.microsoft.com/en-us/library/ms973852.aspx" target="_blank"&gt;performance penalty&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;You can easily identify boxing and unboxing operations by their IL code names:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SqA36Ihc_qI/AAAAAAAAAIQ/bB_Ffh8Mupg/s1600-h/ILCode2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ILCode" border="0" alt="ILCode" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SqA36aoUI7I/AAAAAAAAAIU/3AfZUyyFAQo/ILCode_thumb.png?imgmax=800" width="561" height="291" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Boxing is called &lt;strong&gt;box&lt;/strong&gt; and unboxing is called &lt;strong&gt;unbox&lt;/strong&gt; in IL code. You can use &lt;a href="http://www.red-gate.com/products/reflector/" target="_blank"&gt;Reflector&lt;/a&gt; to have a look at the IL code generated by your application.&lt;/p&gt;  &lt;p&gt;Boxing is very expensive performance wise. Try to avoid encapsulating value types into reference types. Try to find other ways of doing the same, you can use &lt;a href="http://msdn.microsoft.com/en-us/library/ms379564%28VS.80%29.aspx" target="_blank"&gt;generics&lt;/a&gt; as an example.&lt;/p&gt;  &lt;h4&gt;Exception handling&lt;/h4&gt;  &lt;p&gt;Exceptions are great for reporting problems. Many logging systems catch exceptions thrown and log them to a file. The problem is that exceptions are &lt;a href="http://www.codeproject.com/KB/exception/ExceptionPerformance.aspx" target="_blank"&gt;expensive to use and catch&lt;/a&gt;. In high performance applications they should not be used in performance critical parts of the code. All data should be sanitized, checked and exceptions should be thrown before the data enters the performance critical part of the code.&lt;/p&gt;  &lt;p&gt;A few things you should think about when using exceptions:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Do not throw exceptions inside loops &lt;/li&gt;    &lt;li&gt;Do not throw exceptions inside performance critical code &lt;/li&gt;    &lt;li&gt;Do throw exceptions in helpers, managers and data layers and other run-once and use-multiple times code. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The last item can be a bit of a gray area since you can use helpers, managers and data layers inside performance critical code. I trust you to figure that part out yourself.&lt;/p&gt;  &lt;h4&gt;String operations&lt;/h4&gt;  &lt;p&gt;Strings can be your best friend or worst nightmare. They are easy to use and easy to manipulate. What could be wrong with using strings?&lt;/p&gt;  &lt;p&gt;They are &lt;a href="http://codebetter.com/blogs/patricksmacchia/archive/2008/01/13/immutable-types-understand-them-and-use-them.aspx" target="_blank"&gt;immutable&lt;/a&gt;. Memory allocations and thus garbage collections can become a problem. C# does a really &lt;a href="http://en.csharp-online.net/CSharp_String_Theory%E2%80%94String_intern_pool" target="_blank"&gt;great job&lt;/a&gt; of optimizing strings in such a way that minimum memory allocations take place. But even then there are still quite an overhead of using strings. Because they are immutable, all string operations create a new string instead of manipulating the old one. The new string take up some space (2 bytes for each character) and the whole memory copying operation also take some time. Lets take a look at some string concatenations:&lt;/p&gt;  &lt;h5&gt;Normal string&lt;/h5&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SqvDDjwGrJI/AAAAAAAAAIY/6TD9dYwy-0w/s1600-h/StringForLoop%5B5%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="StringForLoop" border="0" alt="StringForLoop" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SqvDDw1hGiI/AAAAAAAAAIc/43_YyVgftzk/StringForLoop_thumb%5B1%5D.png?imgmax=800" width="230" height="120" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Using this code you will get the string “0123456789”. Problem with this code is that you allocate 11 strings. Yes, that is right, 11 strings:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;initial allocation = 1 &lt;/li&gt;    &lt;li&gt;appending = 10 &lt;/li&gt;    &lt;li&gt;final result = 1 &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The allocation, the representation and writing the string to the console in C# takes up nearly 4 kb. The string operation itself takes up a couple of 100 bytes. &lt;/p&gt;  &lt;h5&gt;StringBuilder object&lt;/h5&gt;  &lt;p&gt;A better solution compared to normal strings is to this is to use the StringBuilder object. it contains a mutable (changeable) array.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SqvDEZJBHRI/AAAAAAAAAIg/hOH3tyuBwFk/s1600-h/StringBuilder%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="StringBuilder" border="0" alt="StringBuilder" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SqvDElE2GnI/AAAAAAAAAIk/w-nyU9cEzxo/StringBuilder_thumb.png?imgmax=800" width="358" height="136" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The StringBuilder object allocates a lot less, but it still has an overhead. It is an object, it contains a resizable array, it has some a lot of functionality. Allocating a StringBuilder object often can &lt;a href="http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/" target="_blank"&gt;actually be slower&lt;/a&gt; than normal strings.&lt;/p&gt;  &lt;h5&gt;Char arrays&lt;/h5&gt;  &lt;p&gt;Char arrays can be &lt;a href="http://blogs.msdn.com/cisg/archive/2008/09/09/performance-analysis-reveals-char-array-is-better-than-stringbuilder.aspx" target="_blank"&gt;even faster&lt;/a&gt;. They are mutable and they contain no overhead.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SqvDE_bG_PI/AAAAAAAAAIo/3phKLEFAtYM/s1600-h/CharArray%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="CharArray" border="0" alt="CharArray" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SqvDFIcY8XI/AAAAAAAAAIs/UdZHe3RhgQA/CharArray_thumb.png?imgmax=800" width="259" height="133" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;It can be up to 10 times faster than a StringBuilder object (depending on how it is used) but it also has some disadvantages:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;You have to know the maximum size of the string (char array is fixed size) &lt;/li&gt;    &lt;li&gt;Can only be used in simple manipulation scenarios. &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6472528857323059535?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/09/performance-tips-and-tricks-part-4.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6472528857323059535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6472528857323059535'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/09/performance-tips-and-tricks-part-4.html' title='Performance tips and tricks – part 4'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/SqA35mZItrI/AAAAAAAAAIM/_IQxj4Veuuc/s72-c/Boxunbox_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-7113547740748570183</id><published>2009-09-01T14:34:00.001+02:00</published><updated>2009-09-01T14:34:19.004+02:00</updated><title type='text'>New Farseer Physics Engine based game – FreeGoo</title><content type='html'>&lt;p&gt;For those of you who don’t know about &lt;a href="http://2dboy.com/games.php"&gt;World Of Goo&lt;/a&gt;, the best advice you get today is to buy it and try it out. It is one of my favorite games, complete with a great story, nice graphics and dynamic gameplay. &lt;a href="http://freegoo.codeplex.com/"&gt;FreeGoo&lt;/a&gt; is a Farseer Physics Engine based clone of World Of Goo. Try it out.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-7113547740748570183?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/09/new-farseer-physics-engine-based-game.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7113547740748570183'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7113547740748570183'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/09/new-farseer-physics-engine-based-game.html' title='New Farseer Physics Engine based game – FreeGoo'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-3230463673347520821</id><published>2009-08-26T19:45:00.001+02:00</published><updated>2010-01-15T17:47:29.912+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Raycasting explained</title><content type='html'>&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Raycasting" target="_blank"&gt;Raycasting&lt;/a&gt; can be an extremely useful tool in computer games. There is a lot of confusion on what raycasting really is and how it can be used. I’ll try to explain some it in simple terms and give some simple examples.&lt;/p&gt;  &lt;p&gt;Raycasting - as the name suggests involves a ray – but what exactly is a ray?&lt;/p&gt;  &lt;div style="border-bottom: black 1px solid; border-left: black 1px solid; padding-bottom: 5px; background-color: lightgray; padding-left: 5px; padding-right: 5px; border-top: black 1px solid; border-right: black 1px solid; padding-top: 5px"&gt;A ray is part of a line which is finite in one direction, but infinite in the other. It can be defined by two points, the initial point, A, and one other, B.    &lt;br /&gt;    &lt;br /&gt;Source: &lt;a href="http://en.wikipedia.org/wiki/Line_%28mathematics%29#Ray" target="_blank"&gt;Wikipedia&lt;/a&gt; &lt;/div&gt;  &lt;p&gt;In &lt;a href="http://farseerphysics.codeplex.com/" target="_blank"&gt;Farseer Physics Engine&lt;/a&gt; we define a ray as two vectors; start and end. We can for obvious reasons not have an infinite length ray, we have to have some kind of boundary where the ray stops. This means that rays essentially become lines and then we simply use those lines to test for collisions with other stuff like other lines, &lt;a href="http://en.wikipedia.org/wiki/Axis-aligned_bounding_box" target="_blank"&gt;AABB&lt;/a&gt; or geometries.&lt;/p&gt;  &lt;h4&gt;Collision testing&lt;/h4&gt;  &lt;p&gt;There are 4 test cases that can be performed:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Point &lt;/li&gt;    &lt;li&gt;Line &lt;/li&gt;    &lt;li&gt;AABB &lt;/li&gt;    &lt;li&gt;Geometry &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The great thing about all those (except number 1) is that they can be reduced to simple line vs. line tests. An AABB is made up of 4 lines and a geometry is made of N (where N &amp;gt; 2) lines. With this in mind we just have to know how to test two lines against each other.&lt;/p&gt;  &lt;p&gt;This is done simply by using a &lt;a href="http://en.wikipedia.org/wiki/Linear_equation" target="_blank"&gt;linear equation&lt;/a&gt; from basic algebra:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SpV0mrWWBZI/AAAAAAAAAHo/Km_14TUcsYE/s1600-h/d24ebc87176b242c935535a363c5fc10%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="d24ebc87176b242c935535a363c5fc10" border="0" alt="d24ebc87176b242c935535a363c5fc10" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SpV0mx3fVgI/AAAAAAAAAHs/80UQR_z_Jvk/d24ebc87176b242c935535a363c5fc10_thumb.png?imgmax=800" width="100" height="18" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Using this equation we can create a line. &lt;em&gt;m&lt;/em&gt; is the amount that the y-value grows or shrinks with each time x increases by 1. &lt;em&gt;b&lt;/em&gt; is point on which the line crosses the y-axis. With this knowledge we can draw a line like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SpV0nEA8vTI/AAAAAAAAAHw/F6xSTBmljHA/s1600-h/OneLine%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="OneLine" border="0" alt="OneLine" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SpV0nkM6sSI/AAAAAAAAAH0/ZekZY52M3hY/OneLine_thumb.png?imgmax=800" width="266" height="266" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;It has the equation: y = 2*x+1&lt;/p&gt;  &lt;p&gt;Now that we know how to create a line, we need a second one to test against:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SpV0oI3Zk3I/AAAAAAAAAH4/CmvlJtYiM8U/s1600-h/TwoLines%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="TwoLines" border="0" alt="TwoLines" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SpV0oTdgJBI/AAAAAAAAAH8/-TrcsQY_IvI/TwoLines_thumb.png?imgmax=800" width="266" height="266" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;This line has the equation y = –1*x+1. From what we gathered earlier, &lt;em&gt;b&lt;/em&gt; was the point where the line crosses the y-axis. Since both linear equations has a &lt;em&gt;b &lt;/em&gt;value of 1, they must be intersecting each other there at (0, 1).&lt;/p&gt;  &lt;p&gt;To check for intersections, we take the two equations and simply does an equality check between them and input the result (the value of x) into one of our equations:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SpV0os6DmsI/AAAAAAAAAIA/6GSc_SBApkc/s1600-h/image%5B14%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SpV0oyONQvI/AAAAAAAAAIE/bwQhe2Op8iY/image_thumb%5B4%5D.png?imgmax=800" width="410" height="39" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;So our intersection point is at (0,1). Exactly how this is done in code is a little more complicated. In Farseer Physics Engine we implemented line intersection like described here: &lt;a href="http://ozviz.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/" target="_blank"&gt;Intersection Point Of Two Lines&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Usage&lt;/h4&gt;  &lt;p&gt;Now we know that raycasting operates on lines, but how can this be applied to games? Here is a list of a few examples:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Collision detection &lt;/li&gt;    &lt;li&gt;Distance calculation &lt;/li&gt;    &lt;li&gt;Jumping &lt;/li&gt;    &lt;li&gt;Lasers &lt;/li&gt;    &lt;li&gt;Field of view &lt;/li&gt;    &lt;li&gt;Lightning &lt;/li&gt;    &lt;li&gt;Suspension &lt;/li&gt;    &lt;li&gt;Many more… &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;You can use rays for collision detection and check the distance between the two objects. You can also use it for &lt;a href="http://boxycraft.wordpress.com/2009/06/30/behind-boxboy/" target="_blank"&gt;smooth jumping&lt;/a&gt; on to platforms and even &lt;a href="http://www.newtondynamics.com/wiki/index.php5?title=Making_a_raycast_car" target="_blank"&gt;car suspension&lt;/a&gt;. Another common usage is finding the &lt;a href="http://www.permadi.com/tutorial/raycast/rayc4.html" target="_blank"&gt;field of view&lt;/a&gt;. The only limit is your imagination.&lt;/p&gt;  &lt;p&gt;Ray casts are cheap, but they should not be used for everything. Some physics engines incorporate rays into their &lt;a href="http://farseerphysics.codeplex.com/Wiki/View.aspx?title=DifferentPhases" target="_blank"&gt;broad phase collider&lt;/a&gt; to speed up permanent rays. This will soon be implemented into Farseer Physics Engine too.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-3230463673347520821?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/raycasting-explained.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3230463673347520821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/3230463673347520821'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/raycasting-explained.html' title='Raycasting explained'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Dhwvn65yBx0/SpV0mx3fVgI/AAAAAAAAAHs/80UQR_z_Jvk/s72-c/d24ebc87176b242c935535a363c5fc10_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5801526985438877913</id><published>2009-08-22T17:34:00.001+02:00</published><updated>2009-08-22T17:34:30.300+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Physics Game'/><title type='text'>New game using Farseer Physics – Zombies 2.0</title><content type='html'>&lt;p&gt;A new game just got posted on the Farseer Physics Engine forums, this time it is a zombie survival game. You are the lone protector of a science team, but you do have the choice of 16 different base upgrades and 15 different weapons to help you out. It features real-time lightning and pure action. &lt;a href="http://www.2point0studios.com/zombies.htm" target="_blank"&gt;Check out out!&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5801526985438877913?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/new-game-using-farseer-physics-zombies.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5801526985438877913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5801526985438877913'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/new-game-using-farseer-physics-zombies.html' title='New game using Farseer Physics – Zombies 2.0'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8790623006881842764</id><published>2009-08-22T17:21:00.001+02:00</published><updated>2009-08-22T17:21:03.080+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Simulators And Determinism</title><content type='html'>&lt;p&gt;When working with simulators, it is important to understand &lt;a href="http://en.wikipedia.org/wiki/Deterministic_system" target="_blank"&gt;determinism &lt;/a&gt;and why we have trouble with determinism across different platform and configurations. Simulators that are iterative converge their solution over multiple iterations and can accumulate system-inherited errors and thus can become unstable over time. &lt;/p&gt;  &lt;h4&gt;Why is determinism important&lt;/h4&gt;  &lt;p&gt;Does determinism in simulation systems even matter? The short answer is yes, very important. The long answer is that simulations systems usually base their current world on the previous world. It takes one step at the time (time step) and calculate everything based on the previous step. If you shoot a projectile towards a target it, the &lt;a href="http://en.wikipedia.org/wiki/Trajectory_of_a_projectile" target="_blank"&gt;trajectory of the projectile&lt;/a&gt; will travel in a certain curve. If you run the same simulation on a different platform, the projectile might end up somewhere totally different than the first simulation.&lt;/p&gt;  &lt;p&gt;Take the following example with a projectile trajectory. They both have the same initial conditions.&lt;/p&gt;  &lt;p&gt;Simulation on platform 1:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SpAMzjbEFHI/AAAAAAAAAGw/-HUf4GdIqzE/s1600-h/BulletHit7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="BulletHit" border="0" alt="BulletHit" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SpAMz8-YxlI/AAAAAAAAAG0/eK3FTDhRy6o/BulletHit_thumb3.png?imgmax=800" width="330" height="70" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Simulation on platform 2:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SpAM0B7k6iI/AAAAAAAAAG4/LrSd4Y2J-0I/s1600-h/BulletPassed7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="BulletPassed" border="0" alt="BulletPassed" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SpAM0jMqzfI/AAAAAAAAAG8/0u1K4Mt5j6k/BulletPassed_thumb3.png?imgmax=800" width="330" height="70" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;You would expect the results to be the same on both platforms, but they are not.&lt;/p&gt;  &lt;h4&gt;What can affect determinism&lt;/h4&gt;  &lt;p&gt;There are several things that can affect the determinism of a simulation, the order of elements, the rounding of floats, the low level instructions and much more. Here is a list of some examples on what can impact determinism:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Sorting      &lt;ul&gt;       &lt;li&gt;Stable vs. unstable sorting &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Float operations      &lt;ul&gt;       &lt;li&gt;Rounding methods &lt;/li&gt;        &lt;li&gt;Optimizations &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Hardware instructions      &lt;ul&gt;       &lt;li&gt;Some hardware has higher accuracy than others. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The list is by no means complete, there are hundreds of factors that can affect determinism; the list only contains those we focus on in this post.&lt;/p&gt;  &lt;h5&gt;Sorting&lt;/h5&gt;  &lt;p&gt;In &lt;a href="http://farseerphysics.codeplex.com/" target="_blank"&gt;Farseer Physics Engine&lt;/a&gt; we sort the contacts (where two shapes touch) by the amount two shapes overlap. This way we can resolve the deepest contacts first and get a more realistic simulation. We used to use Array.Sort() that is based on &lt;a href="http://en.wikipedia.org/wiki/Quicksort" target="_blank"&gt;quick sort&lt;/a&gt;, but quick sort is not a stable sorting algorithm. &lt;a href="http://en.wikipedia.org/wiki/Sorting_algorithm#Stability" target="_blank"&gt;Stable&lt;/a&gt; in this case just means that the order of elements are preserved if the keys that are equal are in the same order before and after sorting. If two contacts had the same amount of penetration, they might get shuffled around and the order of IDs will be out of order. We switched to an &lt;a href="http://en.wikipedia.org/wiki/Insertion_sort" target="_blank"&gt;insertion sort&lt;/a&gt; algorithm instead and suddenly the whole simulation acted differently. Not a big problem since it would do that across all platforms, but simulations recorded from previous version of the physics simulator did not match newer versions anymore.&lt;/p&gt;  &lt;h5&gt;Floating point operations&lt;/h5&gt;  &lt;p&gt;Floats can be tricky to work with. I took the following example from &lt;a href="http://www.yoda.arachsys.com/csharp/floatingpoint.html" target="_blank"&gt;this article on floating points in .net&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SpAM0yx-xPI/AAAAAAAAAHA/X0KMd5CK0B8/s1600-h/Floatingpoint2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Floatingpoint" border="0" alt="Floatingpoint" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SpAM1Df-9QI/AAAAAAAAAHE/sQkRk4lxjyU/Floatingpoint_thumb.png?imgmax=800" width="288" height="220" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;You would guess that the program always return true - but that is &lt;strong&gt;not the case&lt;/strong&gt;. If compiled under release mode (to enable optimizations) and x86, it will return false. Even though you can represent two values exact, the result of an operation on the values might not be exact. There is a &lt;a href="http://en.wikipedia.org/wiki/IEEE_floating-point_standard" target="_blank"&gt;standard&lt;/a&gt; for floating point operations, but it allows different platforms to return different values. This means that even if two systems follow the same standard, they might return different values. You can always be sure that the same value is always returned from a float operation on the same platform.&lt;/p&gt;  &lt;p&gt;Let us look at what happens under the hood.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SpAM1fZ1MoI/AAAAAAAAAHI/5DgZ-KGSec4/s1600-h/Truncate%5B8%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Truncate" border="0" alt="Truncate" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SpAM1mVAuDI/AAAAAAAAAHM/YFs2MzLbpDQ/Truncate_thumb%5B2%5D.png?imgmax=800" width="507" height="163" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The float operations are stored in a 80 bit register while the memory is only 64 bit. The value gets calculated with high precision inside the register, but gets truncated in the register. Some compilers optimize your code in such a way that the value in the register gets compared to the value in memory. Since the memory value is truncated, it is not equal to the non-truncated value. This is what happens in the C# example above. To combat this we can do some tricks to disable float optimizations (by making the float not eligible to the optimization), but the simplest thing is to check if the float is in the range of epsilon. More on this further down.&lt;/p&gt;  &lt;h5&gt;Hardware Instructions&lt;/h5&gt;  &lt;p&gt;Let us take the &lt;a href="http://en.wikipedia.org/wiki/Multiply-accumulate" target="_blank"&gt;fused multiply-accumulate&lt;/a&gt; instruction as an example. This instruction can be found in IBM PowerPC or Intel Itanium processors that can compute ax±b with a single rounding instead of multiple. This increase accuracy (and performance because of the fewer rounding instructions) and thus a simulation will run with higher accuracy on the PowerPC or Intel Itanium platform compared to the PC platform.&lt;/p&gt;  &lt;p&gt;This is just one out of many instructions. Some platforms have lower accuracy some have higher. If you develop a simulation that runs on PC, make sure to test it on other platforms if you officially support them.&lt;/p&gt;  &lt;h4&gt;What can we do about it&lt;/h4&gt;  &lt;p&gt;Now that we know some of the factors that influence the determinism of a simulation we can implement some techniques to increase the determinism.&lt;/p&gt;  &lt;p&gt;The first thing is obvious, use stable sorting methods, it is as simple as that. Anything float related is a little more complicated. There are 3 methods of getting more accuracy:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Use doubles &lt;/li&gt;    &lt;li&gt;Use decimal&lt;/li&gt;    &lt;li&gt;Epsilon&lt;/li&gt;    &lt;li&gt;Don’t use floats &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Double and decimal&lt;/h5&gt;  &lt;p&gt;Using doubles simply just shift the problem. It might now be as visible as before, but it is still there. Floats have a precision of 7 digits while double have 15-16 digits. Decimal on the other hand is very accurate and modeled in such a way that no errors are involved. (They have a precision of 28-29 digits by the way). Take a look at the following example:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SpAM1-g1y7I/AAAAAAAAAHQ/El79xP13njw/s1600-h/Float%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Float" border="0" alt="Float" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SpAM2YVeIjI/AAAAAAAAAHU/P1vnUAvlgL0/Float_thumb.png?imgmax=800" width="434" height="66" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The code above will write false for reasons described earlier in this post. The same code using the &lt;a href="http://msdn.microsoft.com/en-us/library/364x0z75%28VS.80%29.aspx" target="_blank"&gt;decimal data type&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SpAM2x8ZWLI/AAAAAAAAAHY/_i1bf8sYVys/s1600-h/Decimal%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Decimal" border="0" alt="Decimal" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SpAM3G1wrgI/AAAAAAAAAHc/hEhEnEkXowY/Decimal_thumb.png?imgmax=800" width="436" height="68" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The above example will return true, just like we would expect. Performance of decimals are not as high as with floats or integers because of the added precision. But places where accuracy is paramount, it might be the only solution.&lt;/p&gt;  &lt;h5&gt;Epsilon&lt;/h5&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Machine_epsilon" target="_blank"&gt;Epsilon&lt;/a&gt; is the smallest positive float value greater than zero (in .net) and can be used to check the equality between two floats, even after they have been rounded. &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SpAM3Xq2N4I/AAAAAAAAAHg/4b-Zno6wmQk/s1600-h/Epsilon%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Epsilon" border="0" alt="Epsilon" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SpAM3mhu9TI/AAAAAAAAAHk/cOfWaEzb46Y/Epsilon_thumb.png?imgmax=800" width="531" height="67" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Using this will always make the equality check between two floats return the correct value.&lt;/p&gt;  &lt;h5&gt;Fixed point&lt;/h5&gt;  &lt;p&gt;The last thing is to simply not use floats and use integers instead. This is also called &lt;a href="http://en.wikipedia.org/wiki/Fixed-point_arithmetic" target="_blank"&gt;fixed point arithmetic&lt;/a&gt;. In fixed point math you have fixed number of digits after the &lt;a href="http://en.wikipedia.org/wiki/Radix_point" target="_blank"&gt;radix point&lt;/a&gt;. It is basically an integer that you scale using some scale factor. Take the number 1.595 as an example. That is the same as 1595/1000 – so 1000 is the scale factor here. Not only can this improve accuracy, but it can also improve performance on devices without a &lt;a href="http://en.wikipedia.org/wiki/Floating_point_unit" target="_blank"&gt;FPU&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Conclusion&lt;/h4&gt;  &lt;p&gt;Use stable sorting methods if the order of elements are important and make sure to take great care with floats in algorithms that are sensitive to small errors. Use doubles if you simply need more precision or use fixed point math if you need exact values. Floating point values are not evil, they are a trade off between performance an accuracy, but you might need to do equality checks in places where you do float operations.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8790623006881842764?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/simulators-and-determinism.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8790623006881842764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8790623006881842764'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/simulators-and-determinism.html' title='Simulators And Determinism'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Dhwvn65yBx0/SpAMz8-YxlI/AAAAAAAAAG0/eK3FTDhRy6o/s72-c/BulletHit_thumb3.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-2824229380223278400</id><published>2009-08-20T02:18:00.001+02:00</published><updated>2010-08-19T23:56:56.117+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Performance tips and tricks – part 3</title><content type='html'>&lt;p&gt;In &lt;a href="http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-2.html" target="_blank"&gt;part 2&lt;/a&gt; I gave a list of the different C# keywords that could potentially increase the performance of your code. This time we take a look at the different manual inlining techniques – it will not be like the two previous posts as this one can’t be presented in simple code snippets. The compiler is normally in charge of doing those kinds of optimizations, but sometimes it might not because of some requirements. First off, let’s get an overview of the different optimizations done by the C# compiler:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Constant_folding" target="_blank"&gt;Constant folding&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Copy_propagation" target="_blank"&gt;Constant and copy propagation&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Common_subexpression_elimination" target="_blank"&gt;Common subexpression elimination&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Loop-invariant_code_motion" target="_blank"&gt;Code motion of loop invariants&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Dead_store" target="_blank"&gt;Dead store&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Dead_code_elimination" target="_blank"&gt;dead code elimination&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Register_allocation" target="_blank"&gt;Register allocation&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Inline_function" target="_blank"&gt;Method inlining&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Loop_unwinding" target="_blank"&gt;Loop unrolling&lt;/a&gt; (small loops with small bodies) &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.codeproject.com/KB/dotnet/JITOptimizations.aspx" target="_blank"&gt;More…&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;As you see, it is quite effective and contains the mostly used optimization techniques required by modern compilers.&lt;/p&gt;  &lt;h4&gt;Why manually optimize?&lt;/h4&gt;  &lt;p&gt;Well, the problem is that while the compiler almost always takes the right path, there are times where manual inlining is necessary. One example is when you are using an old .net version like 2.0; It will &lt;a href="https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93858" target="_blank"&gt;not inline methods&lt;/a&gt; that contain a value type parameter.&lt;/p&gt;  &lt;p&gt;Another example is automatic properties. They will get inlined in release mode and all that, but they are considered regular methods by the compiler and thus still fall under the requirements of the compiler (see them further down).&lt;/p&gt;  &lt;h4&gt;Method inlining&lt;/h4&gt;  &lt;p&gt;The compiler has a &lt;a href="http://blogs.msdn.com/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx" target="_blank"&gt;few requirements&lt;/a&gt; to a method before it can be inlined:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Methods that are greater than 32 bytes of IL will not be inlined. &lt;/li&gt;    &lt;li&gt;Virtual functions are not inlined. &lt;/li&gt;    &lt;li&gt;Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than &lt;code&gt;if/then/else;&lt;/code&gt; in this case, &lt;code&gt;switch&lt;/code&gt; or &lt;code&gt;while&lt;/code&gt;. &lt;/li&gt;    &lt;li&gt;Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining. &lt;/li&gt;    &lt;li&gt;If any of the method's formal arguments are structs, the method will not be inlined. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;While all of them are great requirements and suffice to say that the compiler is really clever in this area (it determines inlining depending on cache size etc.) a few of those items can pose as limitations in your application. More precisely: Virtual functions, struct arguments and exception handling. I’m going to take each of them separately.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Virtual calls      &lt;br /&gt;&lt;/strong&gt;The only way to get around this one is to simply not use virtual calls. If you have a way of getting rid of virtual methods, do it. Virtual calls are up to 40% slower than static or instance method calls. If you get rid of them, the compiler might also inline more methods.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Struct arguments      &lt;br /&gt;&lt;/strong&gt;.Net 3.5 SP1 brought some improvements to this area and it now consider methods with struct arguments as candidates for inlining. However, if you use &amp;lt; .net 3.5 SP1, you will need to identify the methods yourself and inline then manually.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Exception handling      &lt;br /&gt;&lt;/strong&gt;I’m not going to tell you not to do exception handling. While there are other ways of reporting errors, you might be forced to use try/catch. To get around this you need to make sure that the operation expensive methods does not contain exception handling code. Always test input once and then send it off to be calculated on.&lt;/p&gt;  &lt;p&gt;Another thing is properties. You might have a ListCapacity property that checks if the list capacity is &amp;lt; 0 and throw an error if that is the case. Using that property directly in a loop can give you a performance penalty. Instead you should have a backing field (a simple variable) that contains the value and get/set from/to that instead.&lt;/p&gt;  &lt;h4&gt;Loop unrolling&lt;/h4&gt;  &lt;p&gt;As I mentioned in &lt;a href="http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-1.html" target="_blank"&gt;part 1&lt;/a&gt;, you should move your work outside of loops and you should not even use loops if you don’t need to. Loop unrolling is (almost) the same thing. A classic example of loop unrolling:&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SoyWPKZkjPI/AAAAAAAAAGg/hqlbq9gvxjo/s1600-h/LoopUnroll%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="LoopUnroll" border="0" alt="LoopUnroll" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SoyWPUoswUI/AAAAAAAAAGk/8D_5CtPF2JE/LoopUnroll_thumb.png?imgmax=800" width="222" height="77" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SoyWQNBuqjI/AAAAAAAAAGo/3CaaQEhf1bI/s1600-h/LoopUnroll-optimized%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="LoopUnroll-optimized" border="0" alt="LoopUnroll-optimized" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SoyWQQvgRlI/AAAAAAAAAGs/bP6hnMQl2mw/LoopUnroll-optimized_thumb.png?imgmax=800" width="185" height="64" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The C# compiler only inlines small loops with small bodies. Inlining a huge loop is very inefficient since the code size would increase and thus you will get slower code execution. But intelligently unrolling a loop can greatly increase performance, so beware of what you inline and remember to profile it.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-2824229380223278400?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2824229380223278400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2824229380223278400'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-3.html' title='Performance tips and tricks – part 3'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_Dhwvn65yBx0/SoyWPUoswUI/AAAAAAAAAGk/8D_5CtPF2JE/s72-c/LoopUnroll_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-2552064837963285501</id><published>2009-08-19T20:33:00.001+02:00</published><updated>2009-08-19T20:33:21.476+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Performance tips and tricks – part 2</title><content type='html'>&lt;p&gt;In part 1 I presented you with some tricks on loop optimizations and constants. This time I’ll show you some simple keywords in C# that can speed up the execution of your code for the various reasons.&lt;/p&gt;  &lt;h4&gt;Sealed keyword&lt;/h4&gt;  &lt;p&gt;Marking a class as &lt;a href="http://msdn.microsoft.com/en-us/library/88c54tsw%28VS.71%29.aspx" target="_blank"&gt;sealed&lt;/a&gt; makes it it unable to be used as a base class. This is primarily used to prevent other classes from deriving from it. This can unlock some run-time optimizations.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SoxFWawHsRI/AAAAAAAAAFA/sQ-JJMp7FOo/s1600-h/UseSealedClass%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseSealedClass" border="0" alt="UseSealedClass" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFWi2zu2I/AAAAAAAAAFE/u9POScRuHZI/UseSealedClass_thumb.png?imgmax=800" width="168" height="52" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SoxFW5zs9mI/AAAAAAAAAFI/N_P1Sw5v5Cw/s1600-h/UseSealedClass-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseSealedClass-optimized" border="0" alt="UseSealedClass-optimized" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SoxFXIe_joI/AAAAAAAAAFM/PPziVFjrhE0/UseSealedClass-optimized_thumb.png?imgmax=800" width="227" height="53" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Static keyword&lt;/h4&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;You can use the &lt;a href="http://msdn.microsoft.com/en-us/library/98f28cdx%28VS.71%29.aspx" target="_blank"&gt;static&lt;/a&gt; keyword to instantiate a copy of a class at run-time and only keep that one copy in memory. You can read more about the static keyword in the link – be careful with it, you should only use it where appropriate.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SoxFXWwV_3I/AAAAAAAAAFQ/LvW03QhgpIg/s1600-h/UseStatic%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseStatic" border="0" alt="UseStatic" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFXuYTRUI/AAAAAAAAAFU/PxZSQASk--g/UseStatic_thumb.png?imgmax=800" width="205" height="45" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SoxFX4rD5HI/AAAAAAAAAFY/FC5uUYxzHBE/s1600-h/UseStatic-optimized%5B5%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseStatic-optimized" border="0" alt="UseStatic-optimized" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SoxFYIWDm2I/AAAAAAAAAFc/Hhu7AfX2HG0/UseStatic-optimized_thumb%5B1%5D.png?imgmax=800" width="250" height="51" /&gt;&lt;/a&gt;&amp;#160; &lt;/p&gt;  &lt;h4&gt;Struct keyword&lt;/h4&gt;  &lt;p&gt;There are two types of allocations in C#: &lt;a href="http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_memory.aspx" target="_blank"&gt;Stack and heap&lt;/a&gt;    &lt;br /&gt;The stack is where all the value types go: int, char, enum, structs and the like.    &lt;br /&gt;The heap is where all the reference types go: class, interface, string and the like.&lt;/p&gt;  &lt;p&gt;The stack does not get &lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29" target="_blank"&gt;garbage collected&lt;/a&gt; and allocations in that memory space is a lot quicker. When the data structure &lt;a href="http://msdn.microsoft.com/en-us/library/ms229017.aspx" target="_blank"&gt;allow it&lt;/a&gt;, we should allocate our data on the stack.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SoxFYTV3IRI/AAAAAAAAAFg/eY6ACXNMvUY/s1600-h/UseStruct%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseStruct" border="0" alt="UseStruct" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFYtu_EmI/AAAAAAAAAFk/O8EdTT8bgiQ/UseStruct_thumb.png?imgmax=800" width="182" height="84" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFYxrCeTI/AAAAAAAAAFo/dppMgFFAsqw/s1600-h/UseStruct-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseStruct-optimized" border="0" alt="UseStruct-optimized" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SoxFZAubNKI/AAAAAAAAAFs/CJEDvFEPVJ8/UseStruct-optimized_thumb.png?imgmax=800" width="194" height="88" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h4&gt;Ref keyword&lt;/h4&gt;  &lt;p&gt;Using &lt;a href="http://msdn.microsoft.com/en-us/library/14akc2c7%28VS.71%29.aspx" target="_blank"&gt;ref&lt;/a&gt; can sometimes greatly improve performance. It copies the value type by &lt;u&gt;reference&lt;/u&gt; instead of by &lt;u&gt;value&lt;/u&gt;. If this sounds like gibberish to you, take a look at the following article: &lt;a href="http://www.yoda.arachsys.com/csharp/parameters.html" target="_blank"&gt;Parameter passing in C#&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Beware that the before example does actually not change the unit data. It only changes a &lt;u&gt;copy&lt;/u&gt; of the data. The calling class will not upgrade the unit.&lt;/p&gt;  &lt;p&gt;Also, have in mind that this can also decrease performance. The overhead of dereferencing the value type can exceed the overhead of copying by value. Always test if you actually get more performance.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFZf_U_xI/AAAAAAAAAFw/S9_lUqqRugE/s1600-h/UseRef%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseRef" border="0" alt="UseRef" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFZrGDkcI/AAAAAAAAAF0/2vvSToT-zes/UseRef_thumb.png?imgmax=800" width="349" height="235" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFZh0bIaI/AAAAAAAAAF4/gnTy_3F-l44/s1600-h/UseRef-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseRef-optimized" border="0" alt="UseRef-optimized" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SoxFZ9GLAyI/AAAAAAAAAF8/W9tUhDbOp68/UseRef-optimized_thumb.png?imgmax=800" width="375" height="239" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h4&gt;Out keyword&lt;/h4&gt;  &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/t3c3bfhx%28VS.71%29.aspx" target="_blank"&gt;out&lt;/a&gt; keyword is almost exactly like the ref keyword. The ref keyword needs the object to be instantiated before you pass it as a parameter, the out keyword does not.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SoxFaBQojaI/AAAAAAAAAGA/9oB7qgE8StQ/s1600-h/UseRef%5B5%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseRef" border="0" alt="UseRef" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFac98nGI/AAAAAAAAAGE/j56srX_olFM/UseRef_thumb%5B1%5D.png?imgmax=800" width="349" height="235" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SoxFarPe_QI/AAAAAAAAAGI/FbYR_r_MaLA/s1600-h/UseOut-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UseOut-optimized" border="0" alt="UseOut-optimized" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SoxFbILf_iI/AAAAAAAAAGM/IDWU55eYJfU/UseOut-optimized_thumb.png?imgmax=800" width="374" height="258" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note: As you see, the responsibility of instantiating the UnitData has been shifted to the UpgradeUnit() method. Before it had to be instantiated before it was passed to the method.&lt;/p&gt;  &lt;h4&gt;Unsafe keyword&lt;/h4&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;The &lt;a href="http://msdn.microsoft.com/en-us/library/chfa2zb8%28VS.71%29.aspx" target="_blank"&gt;unsafe&lt;/a&gt; keyword is not used very often because of its nature and a name that can scare away most developers. Not to worry, the unsafe keyword enables the use of C concepts like &lt;a href="http://en.wikipedia.org/wiki/Pointer_%28computing%29" target="_blank"&gt;pointers&lt;/a&gt;. Pointers are not just grab and go knowledge and it can cause havoc if used incorrectly. &lt;/p&gt;  &lt;p&gt;Remember to turn on unsafe code in the project build properties. Also remember to use the &lt;a href="http://msdn.microsoft.com/en-us/library/f58wzh21%28VS.71%29.aspx" target="_blank"&gt;fixed&lt;/a&gt; keyword to pin the memory location of variables or use the &lt;a href="http://msdn.microsoft.com/en-us/library/cx9s2sy4%28VS.71%29.aspx" target="_blank"&gt;stackalloc&lt;/a&gt; keyword to allocate memory outside of the garbage collected memory.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFbdyIflI/AAAAAAAAAGQ/J7lsGbtBg4g/s1600-h/UnsafeCode%5B5%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UnsafeCode" border="0" alt="UnsafeCode" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SoxFboTm-OI/AAAAAAAAAGU/_his2Bt5u-g/UnsafeCode_thumb%5B1%5D.png?imgmax=800" width="401" height="340" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SoxFb3yM6fI/AAAAAAAAAGY/L864DjMeR5M/s1600-h/UnsafeCode-Optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="UnsafeCode-Optimized" border="0" alt="UnsafeCode-Optimized" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SoxFcFxvDNI/AAAAAAAAAGc/F7XKdjhjCAA/UnsafeCode-Optimized_thumb.png?imgmax=800" width="442" height="394" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note how the arrow (-&amp;gt;) is used instead of the dot (.) when accessing members.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-2552064837963285501?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2552064837963285501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2552064837963285501'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-2.html' title='Performance tips and tricks – part 2'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_Dhwvn65yBx0/SoxFWi2zu2I/AAAAAAAAAFE/u9POScRuHZI/s72-c/UseSealedClass_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-6465001582483811732</id><published>2009-08-18T22:51:00.001+02:00</published><updated>2009-08-18T22:51:45.106+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Performance tips and tricks – part 1</title><content type='html'>&lt;p&gt;In this post series I will take a look at the different tips and tricks that can increase the performance of your application. You probably already know some of them and some of them are even just a bit of logical thinking. In any case, it should help you remember the different techniques. I took all these tips and tricks out of my article High Performance Game Development (The revised version – coming out soon) since they apply to almost all languages.&lt;/p&gt;  &lt;h4&gt;Move work out of loops&lt;/h4&gt;  &lt;p&gt;This one is kind of obvious, but it can be hard to identify in some cases. You simply move work from inner loops to outer loops or even out of a loop altogether. I’ve made some simple examples of this:&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SosUNGWxq7I/AAAAAAAAAEA/juGjk3jKNQQ/s1600-h/MoveOutOfLoop%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="MoveOutOfLoop" border="0" alt="MoveOutOfLoop" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SosUNaH-caI/AAAAAAAAAEE/8CSj6NwakRc/MoveOutOfLoop_thumb.png?imgmax=800" width="290" height="136" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After: &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SosUNjRyFAI/AAAAAAAAAEI/xQV_jreL_9Y/s1600-h/MoveOutOfLoop-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="MoveOutOfLoop-optimized" border="0" alt="MoveOutOfLoop-optimized" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SosUNwvhcWI/AAAAAAAAAEM/jqVHVOJaaLk/MoveOutOfLoop-optimized_thumb.png?imgmax=800" width="284" height="138" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Don’t use loops&lt;/h4&gt;  &lt;p&gt;This is much like the previous one. One important difference is that you don’t use loops at all. You will save a lot of instructions and thus you will have better performance.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SosUOJwwiZI/AAAAAAAAAEQ/vW-sxkeXzz8/s1600-h/DontUseLoops%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="DontUseLoops" border="0" alt="DontUseLoops" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SosUOYUJfRI/AAAAAAAAAEU/ygQUfJpKWaE/DontUseLoops_thumb.png?imgmax=800" width="280" height="83" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SosUOgfWSII/AAAAAAAAAEY/bU_rHGq8hck/s1600-h/DontUseLoops-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="DontUseLoops-optimized" border="0" alt="DontUseLoops-optimized" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SosUOteSwWI/AAAAAAAAAEc/4XIxXSQh7K8/DontUseLoops-optimized_thumb.png?imgmax=800" width="229" height="37" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h4&gt;Use constants whenever possible&lt;/h4&gt;  &lt;p&gt;Using constants can greatly improve performance. The compiler can make better decisions about your code and make use of low level optimizations that speed up the execution of the code. &lt;/p&gt;  &lt;p&gt;Before: &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SosUO5Isr7I/AAAAAAAAAEg/3kU6QmBxWkM/s1600-h/Constants%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Constants" border="0" alt="Constants" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SosUPBChDTI/AAAAAAAAAEk/_Hg-1YwqQ-8/Constants_thumb.png?imgmax=800" width="247" height="52" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_Dhwvn65yBx0/SosUPUll-FI/AAAAAAAAAEo/iN5iktoZ_tQ/s1600-h/Constants-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Constants-optimized" border="0" alt="Constants-optimized" src="http://lh5.ggpht.com/_Dhwvn65yBx0/SosUP2WOKBI/AAAAAAAAAEs/PlSz0L5GkQ0/Constants-optimized_thumb.png?imgmax=800" width="298" height="57" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note how we can use the const keyword on the addition variable. This is only possible when the depending variables are also marked with the const keyword.&lt;/p&gt;  &lt;h4&gt;Simplify variables&lt;/h4&gt;  &lt;p&gt;Whenever you can, make sure to simplify variables to removing redundant operations. This might not always be possible and sometimes it can severely decrease the code readability. In this specific case you can maintain the readability by simply using the const keyword. The compiler will then simplify the variables for you.&lt;/p&gt;  &lt;p&gt;Before:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SosUQDkfd5I/AAAAAAAAAEw/ekBZY49qJOU/s1600-h/SimplifyVariables%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="SimplifyVariables" border="0" alt="SimplifyVariables" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SosUQicafhI/AAAAAAAAAE0/1HMpfOVTpsc/SimplifyVariables_thumb.png?imgmax=800" width="600" height="78" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;After:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SosUQjgDzUI/AAAAAAAAAE4/DUi0vYz3igY/s1600-h/SimplifyVariables-optimized%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="SimplifyVariables-optimized" border="0" alt="SimplifyVariables-optimized" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SosURAxvnLI/AAAAAAAAAE8/Kq73pTJXIX4/SimplifyVariables-optimized_thumb.png?imgmax=800" width="313" height="20" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-6465001582483811732?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-1.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6465001582483811732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/6465001582483811732'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/performance-tips-and-tricks-part-1.html' title='Performance tips and tricks – part 1'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/SosUNaH-caI/AAAAAAAAAEE/8CSj6NwakRc/s72-c/MoveOutOfLoop_thumb.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-106825626993690142</id><published>2009-08-18T00:53:00.001+02:00</published><updated>2009-08-18T00:53:00.454+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>The famous inverse square root</title><content type='html'>&lt;p&gt;I’ve already mentioned before that you can approximate divisions using a division-free &lt;a href="http://en.wikipedia.org/wiki/Newton-Raphson" target="_blank"&gt;Newton-Raphson&lt;/a&gt; approximation. You can also use the Newton-Raphson method for approximating the square root and the inverse square root function.&lt;/p&gt;  &lt;p&gt;But first, what do we actually use inverse square root and square root for? A lot really – everything that uses a normalized vector; collision responses, lightning and reflection to mention a few. It is an important part of any game and the operation has to be as fast as possible. Back in the day when computers had weaker CPUs and no specialized hardware to handle floating point operations (Today we even have specialized physics cards and specialized lightning circuits), some steps had to be taken to compute the inverse square root a million times each second as quickly as possible.&lt;/p&gt;  &lt;p&gt;And here it is:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_Dhwvn65yBx0/SonfSuCtq8I/AAAAAAAAAC4/xYSooVe6oyU/s1600-h/normalize%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="normalize" border="0" alt="normalize" src="http://lh4.ggpht.com/_Dhwvn65yBx0/SonfS5WPKeI/AAAAAAAAAC8/53xZ3UCK7mk/normalize_thumb.png?imgmax=800" width="335" height="147" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I could go into details on how this works, but I think it has been described sufficiently on Wikipedia's article &lt;a href="http://en.wikipedia.org/wiki/Fast_inverse_square_root" target="_blank"&gt;Fast inverse square root&lt;/a&gt;. Suffice to say that the line with &lt;strong&gt;0x5f3759df&lt;/strong&gt; is the interesting one, and even to this day we don’t know the origin of it. &lt;a href="http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf" target="_blank"&gt;Several&lt;/a&gt; different &lt;a href="www.mceniry.net/papers/Fast%20Inverse%20Square%20Root.pdf" target="_blank"&gt;papers&lt;/a&gt; has been written to try and explain where this magic hex code came from.&lt;/p&gt;  &lt;p&gt;I included this fast inverse square root function in the &lt;a href="http://cid-f116593ba64184a2.skydrive.live.com/self.aspx/.Public/Approx.net.zip" target="_blank"&gt;Approx.net&lt;/a&gt; library (C#). &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-106825626993690142?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/famous-inverse-square-root.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/106825626993690142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/106825626993690142'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/famous-inverse-square-root.html' title='The famous inverse square root'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Dhwvn65yBx0/SonfS5WPKeI/AAAAAAAAAC8/53xZ3UCK7mk/s72-c/normalize_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8011683291178371610</id><published>2009-08-17T00:54:00.001+02:00</published><updated>2009-08-17T23:58:42.594+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>Mathematical operations and micro-benchmarking</title><content type='html'>&lt;p&gt;You might have heard that the &lt;a href="http://en.wikipedia.org/wiki/Division_%28digital%29" target="_blank"&gt;division operation&lt;/a&gt; on a modern FPU is slower than a multiplication operation. If you have not heard this before; it’s true – divisions are indeed slower. But why?&lt;/p&gt;  &lt;p&gt;Without going into the technical details, the divide operation is an iterative algorithm and the multiplication operation is computed directly. One of the more common ways of doing divide operations on a FPU is to use a divide-free &lt;a href="http://en.wikipedia.org/wiki/Newton-Raphson" target="_blank"&gt;Newton-Raphson&lt;/a&gt; approximation to get the reciprocal of the denominator and then multiply with the numerator. More on this will come in a later post.&lt;/p&gt;  &lt;p&gt;Let’s put it to the test.   &lt;br /&gt; Here we run 10.000.000 iterations where we divide 500 by 11.5&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/SonQ7VJUvNI/AAAAAAAAACo/tedCpWnsPS0/s1600-h/Divide%5B4%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Divide" border="0" alt="Divide" src="http://lh3.ggpht.com/_Dhwvn65yBx0/SonQ7sYv8cI/AAAAAAAAACs/Nl4UctNgr6U/Divide_thumb%5B2%5D.png?imgmax=800" width="374" height="132" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Here we multiply 500 by the multiplicative inverse (reciprocal) of 11.5 &lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/SonQ7x03ZAI/AAAAAAAAACw/lCF4z3GwVBs/s1600-h/InverseDivide%5B2%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="InverseDivide" border="0" alt="InverseDivide" src="http://lh6.ggpht.com/_Dhwvn65yBx0/SonQ8dXvreI/AAAAAAAAAC0/OrNcJkjwX5s/InverseDivide_thumb.png?imgmax=800" width="334" height="111" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;From what I described earlier our multiplication example (code example 2) should perform better than the division example. Here are the results:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Division&lt;/strong&gt;: 00:00:00.0010787    &lt;br /&gt;&lt;strong&gt;Multiplication&lt;/strong&gt;: 00:00:00.0010871&lt;/p&gt;  &lt;p&gt;&lt;u&gt;Something is clearly wrong&lt;/u&gt;. First off all, they have virtually no difference in the time it took to compute the results. Second of all, the time it took to do the operations is really small. Don’t worry, there is a perfectly good reason for this:&lt;/p&gt;  &lt;p&gt;We used constants to represent the numbers we needed to divide and multiply. The compiler knows this and use the approximation instructions on the FPU – we also did the same operation 10.000.000 times. This leads us to the next section of this post:&lt;/p&gt;  &lt;h4&gt;Micro-benchmarking&lt;/h4&gt;  &lt;p&gt;Micro-benchmarking is where you test a single or multiple operations to see what takes the most time. In this case, all we tested was that the division and multiplication examples took the same amount of time and we simply timed the cache and not the operations themselves.&lt;/p&gt;  &lt;p&gt;There are &lt;a href="http://blogs.microsoft.co.il/blogs/sasha/archive/2009/05/08/micro-benchmarking-considered-harmful.aspx" target="_blank"&gt;a bunch&lt;/a&gt; of &lt;a href="http://blogs.msdn.com/shawnhar/archive/2009/07/14/the-perils-of-microbenchmarking.aspx" target="_blank"&gt;examples&lt;/a&gt; on the internet that shows us exactly how micro-benchmarking can deceive us. In this case, the compiler simply optimizes the code and CPU cache helped us to get the results fast. To truly test the performance of the divide and multiply operators, we need to make the compiler second guess; simply remove the const keyword and rerun the code. You will see that the multiply operator is up to 10 times faster (depending on platform and compiler mode).    &lt;p&gt;&lt;/p&gt;    &lt;h4&gt;Conclusion&lt;/h4&gt;    &lt;p&gt;Divisions are really slower than multiplication, but the CPU uses precise approximations by either using lookup tables or iterative algorithms. It is a clever piece of hardware that always tries to speed up your the execution of your code where ever possible. When you do micro-benchmarking, make sure the compiler generates the code you actually want to test. Often the compiler even strips away your for-loop and simply run the code once. If there is no way to get around this, simply run the code once yourself and use StopWatch.ElapsedTicks as measuring tool and it will tell you of any speed differences.&lt;/p&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8011683291178371610?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/mathematical-operations-and-micro.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8011683291178371610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8011683291178371610'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/mathematical-operations-and-micro.html' title='Mathematical operations and micro-benchmarking'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/SonQ7sYv8cI/AAAAAAAAACs/Nl4UctNgr6U/s72-c/Divide_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-157055722040823332</id><published>2009-08-14T20:23:00.001+02:00</published><updated>2009-08-14T20:24:27.294+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Physics Game'/><title type='text'>New game using Farseer Physics Engine – Superspace</title><content type='html'>&lt;p&gt;Another game got posted on our forums. This time it is a space shooter game with cooperative, death match and racing modes. It has 36 different levels for you to play with. The game has great particle effects, nice dynamics and classic sounds.&lt;/p&gt;  &lt;p&gt;You can view a trailer of the game on youtube: &lt;a href="http://www.youtube.com/watch?v=g6ct2OOOcBQ" target="_blank"&gt;Superspace trailer&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-157055722040823332?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/game-using-farseer-physics-engine.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/157055722040823332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/157055722040823332'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/game-using-farseer-physics-engine.html' title='New game using Farseer Physics Engine – Superspace'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-9126346156497595286</id><published>2009-08-11T20:55:00.001+02:00</published><updated>2009-08-14T20:16:45.089+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Physics Game'/><title type='text'>Another game using Farseer Physics Engine – Square Off</title><content type='html'>&lt;p&gt;A new game called Square off just got posted on the Farseer Physics Engine forums. It is created by &lt;a href="http://www.gnomicstudios.com/blog/" target="_blank"&gt;Gnomic Studios&lt;/a&gt; and has entered the &lt;a href="http://www.dreambuildplay.com/main/default.aspx" target="_blank"&gt;Dream Build Play&lt;/a&gt; competition.&lt;/p&gt;  &lt;p&gt;It features great graphics, multiplayer and a huge fun-factor. Take a look at &lt;a href="http://www.youtube.com/watch?v=phMS3B3U5Tk" target="_blank"&gt;this video&lt;/a&gt; to see what I mean.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-9126346156497595286?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/another-game-using-farseer-physics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/9126346156497595286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/9126346156497595286'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/another-game-using-farseer-physics.html' title='Another game using Farseer Physics Engine – Square Off'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-4562617735708158711</id><published>2009-08-11T20:48:00.001+02:00</published><updated>2009-08-14T20:16:28.654+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Physics Game'/><title type='text'>New game using Farseer Physics Engine - Ninjic</title><content type='html'>&lt;p&gt;We have about 1300 daily pageviews and&amp;#160; 200 downloads each day over at the &lt;a href="http://farseerphysics.codeplex.com/" target="_blank"&gt;Farseer Physics Engine&lt;/a&gt; project. We also have a quite a few users posting their games for others to review and to show off how they used the engine.&lt;/p&gt;  &lt;p&gt;A lot of the games are good, but Ninjics surpassed my expectations. The graphics is from &lt;a href="http://upstudiodp.com/" target="_blank"&gt;UP Studio&lt;/a&gt; and the designer and a guy teamed up to create a ninja-style game.&lt;/p&gt;  &lt;p&gt;See the &lt;a href="http://www.youtube.com/watch?v=78xjHnicYCA" target="_blank"&gt;video of Ninjic&lt;/a&gt; on youtube.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-4562617735708158711?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/new-game-using-farseer-physics-engine.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/4562617735708158711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/4562617735708158711'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/new-game-using-farseer-physics-engine.html' title='New game using Farseer Physics Engine - Ninjic'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-4002034583087506465</id><published>2009-08-10T18:54:00.001+02:00</published><updated>2009-08-11T20:56:43.798+02:00</updated><title type='text'>Google analytics and Blogspot</title><content type='html'>&lt;p&gt;I looked around for some statistics to get an idea on the amount of visitors that read my blog. I was surprised that nothing like that existed by default. Google is the owner of Blogspot and they are known for their detailed analytics of the internet and reliable site tracking, so I thought that it was a joke that Blogspot did not have a statistics module by default.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Google took the right path.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;So why not include a statistics module by default? I’ll tell you why; the best sites in the world are defined by their functionality and ease of use. By &lt;u&gt;not&lt;/u&gt; including a default statistics module and let the users choose what they like is very clever and gives your users an extremely flexible service.&lt;/p&gt;  &lt;p&gt;I personally went with &lt;a href="http://www.google.com/analytics/" target="_blank"&gt;Google Analytics&lt;/a&gt;. There are several &lt;a href="http://www.statcounter.com/blogger/" target="_blank"&gt;other services&lt;/a&gt; that tracks sites statistics. The choice is up to you.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-4002034583087506465?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/google-analytics-and-blogspotcom.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/4002034583087506465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/4002034583087506465'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/google-analytics-and-blogspotcom.html' title='Google analytics and Blogspot'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-7839905160223857931</id><published>2009-08-09T20:51:00.001+02:00</published><updated>2009-08-18T00:04:50.475+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>The accuracy and speed of function approximations – part 3</title><content type='html'>&lt;p&gt;In &lt;a href="http://ianqvist.blogspot.com/2009/08/accuracy-and-speed-of-function.html" target="_blank"&gt;part 2&lt;/a&gt; we had a look at the accuracy of the approximated functions. In this part we will take a look at the speed of the same approximated functions.&lt;/p&gt;  &lt;p&gt;There is no reason to use approximation unless you gain something from it. Usually the gain will be in the form of a speed improvement over the real function. Embedded devices with low memory and low frequency CPU can benefit greatly from approximation – even new computers can benefit from it. Lets test it out:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sn8sKoihG0I/AAAAAAAAACg/pcTbyX_MaY4/s1600-h/ApproxSineTable%5B2%5D.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ApproxSineTable" border="0" alt="ApproxSineTable" src="http://lh3.ggpht.com/_Dhwvn65yBx0/Sn8sK5soN5I/AAAAAAAAACk/t2XBHHmn3bc/ApproxSineTable_thumb.png?imgmax=800" width="584" height="78" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The timing depends a lot on the platform and settings. This is compiled under .Net 3.5 SP1 x64 in release mode. Timing is based on 1000000 iterations.&lt;/p&gt;  &lt;p&gt;The results are clear – the quadratic curve equation is a lot faster than both the Taylor series and real sine function. The quadratic curve equation is also more accurate than the Taylor series.&lt;/p&gt;  &lt;h4&gt;Conclusion&lt;/h4&gt;  &lt;p&gt;If you are programming for embedded devices such as mobile phones, PDAs or barcode readers, you can gain a lot of function approximations. In this article series we tested the accuracy (true across all platforms – small but consistent variations can occur) and the speed on the PC platform. Using a quadratic curve approximation with added accuracy can give you &lt;strong&gt;10 times better performance&lt;/strong&gt; for a small sacrifice in accuracy.&lt;/p&gt;  &lt;p&gt;You can get the code to the approximation library (written in C#) here: &lt;a href="http://cid-f116593ba64184a2.skydrive.live.com/self.aspx/.Public/Approx.net.zip" target="_blank"&gt;Approx.net&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I managed to improve the performance of the LowSin() function. It now runs at 3 ms on my computer.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-7839905160223857931?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/accuracy-and-speed-of-function_09.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7839905160223857931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/7839905160223857931'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/accuracy-and-speed-of-function_09.html' title='The accuracy and speed of function approximations – part 3'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_Dhwvn65yBx0/Sn8sK5soN5I/AAAAAAAAACk/t2XBHHmn3bc/s72-c/ApproxSineTable_thumb.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5167883669720862125</id><published>2009-08-08T21:21:00.001+02:00</published><updated>2009-08-14T20:17:55.752+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>The accuracy and speed of function approximations – part 2</title><content type='html'>&lt;p&gt;In &lt;a href="http://ianqvist.blogspot.com/2009/08/accuracy-of-function-approximations.html" target="_blank"&gt;part 1&lt;/a&gt; we took a look at two different function approximations; Polynomials and Taylor series. We found out that Taylor series are a lot more accurate than the quadratic equation – or is it?&lt;/p&gt;  &lt;p&gt;The quadratic equation is fine in some cases. If you want to create a swinging hammer, a wave or the movement for a platform; this approximation is fine. But we can add some extra precision to the function and get it to be even more accurate. The new function looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sn3QU3yG7sI/AAAAAAAAACQ/By6yo47P2rk/s1600-h/HighPolySineFunction8.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="HighPolySineFunction" border="0" alt="HighPolySineFunction" src="http://lh4.ggpht.com/_Dhwvn65yBx0/Sn3QVDP-fVI/AAAAAAAAACU/21kSSAo3WH8/HighPolySineFunction_thumb2.png?imgmax=800" width="272" height="43" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;The first function &lt;em&gt;f&lt;/em&gt; defines the sine approximation and the second function &lt;em&gt;g&lt;/em&gt; adds some extra precision. The result will look like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/Sn3QVYWVKhI/AAAAAAAAACY/lT_uiyVYwZw/s1600-h/HighPolySine4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="HighPolySine" border="0" alt="HighPolySine" src="http://lh5.ggpht.com/_Dhwvn65yBx0/Sn3QVmexb3I/AAAAAAAAACc/jh4rE9sBOkU/HighPolySine_thumb16.png?imgmax=800" width="385" height="385" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;We are nearly unable to distinguish the two lines from each other. And remember from part 1, it is exact in 0, π/2 and π. So using this quadratic equation is really more accurate than Taylor series – but accuracy is not everything. We will take a look at the performance in part 3.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Part 3 is &lt;a href="http://ianqvist.blogspot.com/2009/08/accuracy-and-speed-of-function_09.html" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5167883669720862125?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/accuracy-and-speed-of-function.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5167883669720862125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5167883669720862125'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/accuracy-and-speed-of-function.html' title='The accuracy and speed of function approximations – part 2'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_Dhwvn65yBx0/Sn3QVDP-fVI/AAAAAAAAACU/21kSSAo3WH8/s72-c/HighPolySineFunction_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-957479554685148613</id><published>2009-08-08T20:53:00.001+02:00</published><updated>2009-08-14T20:17:24.329+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='Optimization'/><title type='text'>The accuracy and speed of function approximations</title><content type='html'>&lt;p&gt;The hard truth of function approximations is that they are not very accurate – that is why they are called approximations (duh). But just &lt;u&gt;how&lt;/u&gt; accurate are the different approximations? Here I will take a look at the &lt;a href="http://ee.stlcc.info/130/accuracy.htm" target="_blank"&gt;accuracy&lt;/a&gt; of the different sine function approximations.&lt;/p&gt;  &lt;p&gt;First off, what exactly are we going to approximate? Let us take a look at the sine function in a graph:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sn3MeCal-XI/AAAAAAAAABo/wnA94AreOoQ/s1600-h/sine24.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="sine" border="0" alt="sine" src="http://lh5.ggpht.com/_Dhwvn65yBx0/Sn3MeW7mPkI/AAAAAAAAABs/JxQ-ZRKTdbo/sine_thumb22.png?imgmax=800" width="400" height="400" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;The X axis goes from –π to π.&lt;/p&gt;  &lt;p&gt;Let the approximation begin. We start out with a polynomial approximation. We simply use&amp;#160; a &lt;a href="http://en.wikipedia.org/wiki/Quadratic_equation" target="_blank"&gt;quadratic equation&lt;/a&gt; to approximate the curve of the sine function as best as we can. I came &lt;a href="http://www.devmaster.net/forums/showthread.php?t=5784" target="_blank"&gt;across a post&lt;/a&gt; where a guy used –π, -π/2, 0, π/2,π as points of reference and derived a function from that. He came up with:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_Dhwvn65yBx0/Sn3MexBW0RI/AAAAAAAAABw/ZwxXts8-2Ik/s1600-h/image7.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_Dhwvn65yBx0/Sn3MfPJ7TmI/AAAAAAAAAB0/J7O8TmLyMpM/image_thumb3.png?imgmax=800" width="410" height="21" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Without getting too much into the details, this quadratic equation only approximates the curve of the interval [0 ; π]. Putting this equation into a graph with the real sine function gives us this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/Sn3MfVbFFsI/AAAAAAAAAB4/rsQTw-04km8/s1600-h/PolySine3.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="PolySine" border="0" alt="PolySine" src="http://lh6.ggpht.com/_Dhwvn65yBx0/Sn3Mf1Th5oI/AAAAAAAAAB8/IV-B6af-AcM/PolySine_thumb5.png?imgmax=800" width="383" height="385" /&gt;&lt;/a&gt;&amp;#160; &lt;br /&gt;Blue is our sine function and red is our quadratic equation. As you can see, the quadratic function is exact in 0, π/2 and π. Now let us have a look at the good old &lt;a href="http://en.wikipedia.org/wiki/Taylor_series" target="_blank"&gt;Taylor Series&lt;/a&gt; approximation of sine:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_Dhwvn65yBx0/Sn3MgLd6nZI/AAAAAAAAACA/4mpt5mjB6d0/s1600-h/TaylorSine3.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="TaylorSine" border="0" alt="TaylorSine" src="http://lh5.ggpht.com/_Dhwvn65yBx0/Sn3MgV8iJjI/AAAAAAAAACE/AmK_NaeaHQ8/TaylorSine_thumb5.png?imgmax=800" width="384" height="388" /&gt;&lt;/a&gt;&amp;#160; &lt;br /&gt;Blue is our sine function and red is our Taylor series. Pretty neat huh? It is impossible to tell the difference between the two functions from the interval [0;π/2], but then it starts to deviate. Suffice to say that&amp;#160; that we can see from our results that the Taylor series approximation is more accurate – or is it? Stay tuned for part 2.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Update: &lt;/strong&gt;&lt;a href="http://ianqvist.blogspot.com/2009/08/accuracy-and-speed-of-function.html" target="_blank"&gt;part 2 is here&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-957479554685148613?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/accuracy-of-function-approximations.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/957479554685148613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/957479554685148613'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/accuracy-of-function-approximations.html' title='The accuracy and speed of function approximations'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_Dhwvn65yBx0/Sn3MeW7mPkI/AAAAAAAAABs/JxQ-ZRKTdbo/s72-c/sine_thumb22.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-217483806709764281</id><published>2009-08-08T19:59:00.002+02:00</published><updated>2009-08-08T20:01:02.168+02:00</updated><title type='text'>That new code smell - With C# example</title><content type='html'>&lt;p&gt;The High Performance Game Development article is coming along fine. I wrote up some C# code that follows with the article, most of the code is examples on &lt;a href="http://en.wikipedia.org/wiki/Transcendental_function" target="_blank"&gt;transcendental function&lt;/a&gt; approximations.&lt;/p&gt;  &lt;p&gt;Here is a pretty example on a sine function using &lt;a href="http://en.wikipedia.org/wiki/Taylor_series" target="_blank"&gt;Taylor Series&lt;/a&gt;:&lt;/p&gt;  &lt;pre style="border: 1px solid rgb(206, 206, 206); padding: 5px; overflow: auto; background-color: rgb(251, 251, 251); min-height: 40px; width: 500px;"&gt;&lt;pre   style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;float&lt;/span&gt; FastSin(&lt;span style="color: rgb(0, 0, 255);"&gt;float&lt;/span&gt; x)&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%;"&gt;{&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; x - ((x * x * x) / 6) + ((x * x * x * x * x) / 120)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;        - ((x * x * x * x * x * x * x) / 5040);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;Much more to come!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-217483806709764281?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/that-new-code-smell-with-c-example.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/217483806709764281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/217483806709764281'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/that-new-code-smell-with-c-example.html' title='That new code smell - With C# example'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-8514897799002687046</id><published>2009-08-08T19:14:00.001+02:00</published><updated>2009-08-08T20:02:53.386+02:00</updated><title type='text'>Who owns the article?</title><content type='html'>&lt;p&gt;I've been writing an article called &lt;strong&gt;High Performance Game Development&lt;/strong&gt; for quite some while now, and since it (in my opinion) contains a culmination of high quality knowledge about the complicated area of performance, I would like to make it available to the masses. I went looking for a place to post the article, but was surprised to see that most sites simply takes away your rights to the content of the article. Their disclaimer text often goes like this:&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;em&gt;By submitting your article to xxxxxxxx, you are granting to us a permanent, non-exclusive license to use the article in any format we deem appropriate, with the assurance that you will always be given full credit for your work&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;I was also surprised to see that all sites want you to write the article, then upload it to them. You have no way of editing the article by yourself. You will have to contact the site owners to get your article updated. I can understand why they do this - it must be because of vandalism and inappropriate words and so on.     &lt;br /&gt;By why should I write an article, give it to them and essentially give them the rights to do whatever they want with the article?&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;strong&gt;No way...&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;That is why I decided to publish the article myself. I don't know where to host it yet, but hopefully it will get noticed and be passed around forums.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-8514897799002687046?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/who-owns-article.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8514897799002687046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/8514897799002687046'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/who-owns-article.html' title='Who owns the article?'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-2627829737806440473</id><published>2009-08-07T19:50:00.000+02:00</published><updated>2009-08-08T19:50:50.328+02:00</updated><title type='text'>The state of TTS systems</title><content type='html'>&lt;p&gt;I have this semi-blind friend that I used to work together with. He uses an application called Zoomtext for reading online news, install applications and so on. The only problem is that the program is poor in quality - always lagging around the screen, crashing and is really heavy to dance with. Being geek by nature I tried to find alternatives and stumbled upon some online TTS (Text-To-Speech) system with some really good quality voices. One of them was &lt;a href="http://www.ispeech.org/library"&gt;iSpeech&lt;/a&gt;. It is a webservice based application where you can upload your content for free. But free does not necessarily mean easy, here is what I think about it:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; It is online and thus you can only past it some text and then get the speech results. There are no parsing of documents on the fly so you can read while you listen. This can be solved (sort of), read on...&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Building an application that works together with the parsing engine of Zoomtext seems to be pretty easy. Problem is that each upload of text portion will contain an advertisement for the service - You can of course get around that paying a large amount of money, but paying $99 each month (for 600 minutes of audio) for only the voice of a TTS system is not really an option.&lt;/p&gt;  &lt;p&gt;So how come handicapped people have to live without the high quality voice proviced by iSpeech (or &lt;a href="http://www.odiogo.com/"&gt;odiogo&lt;/a&gt;) in a text parser engine like the one from Zoomtext? We are way behind on the field of assistance applications in my opinion and someone needs to put those two together.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-2627829737806440473?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/state-of-tts-systems.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2627829737806440473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/2627829737806440473'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/state-of-tts-systems.html' title='The state of TTS systems'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2077469061561410808.post-5343596435523522320</id><published>2009-08-06T19:51:00.000+02:00</published><updated>2009-08-08T19:51:21.053+02:00</updated><title type='text'>New blog</title><content type='html'>&lt;p&gt;I’ve been thinking about getting a blog, and now it finally happened. Stay tuned…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2077469061561410808-5343596435523522320?l=ianqvist.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='text/html' href='http://ianqvist.blogspot.com/2009/08/new-blog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5343596435523522320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2077469061561410808/posts/default/5343596435523522320'/><link rel='alternate' type='text/html' href='http://ianqvist.blogspot.com/2009/08/new-blog.html' title='New blog'/><author><name>Ian Qvist</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
