<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Execution Unit</title><link href="https://www.executionunit.com/" rel="alternate"></link><link href="https://www.executionunit.com/feeds/all.atom.xml" rel="self"></link><id>https://www.executionunit.com/</id><updated>2024-08-21T00:00:00+01:00</updated><entry><title>How I setup Subversion to work with Unreal.</title><link href="https://www.executionunit.com/blog/2024/08/21/how-i-setup-subversion-to-work-with-unreal/" rel="alternate"></link><published>2024-08-21T00:00:00+01:00</published><updated>2024-08-21T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2024-08-21:/blog/2024/08/21/how-i-setup-subversion-to-work-with-unreal/</id><summary type="html">&lt;p&gt;How we use Unreal and Subversion&amp;nbsp;together.&lt;/p&gt;</summary><content type="html">&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;I have used Perforce, Subversion (&lt;span class="caps"&gt;SVN&lt;/span&gt;) and Git with Unreal on &lt;span class="caps"&gt;AA&lt;/span&gt; Game and Indie Games. I feel that Subversion
is often overlooked as a source control solution for small to medium teams. Subversion has fallen out of favor and
is no longer cool. It definitely earned a reputation for &amp;#8220;screwing up branching&amp;#8221; but this isn&amp;#8217;t an issue
for Unreal projects. Subversion is fast, stable and&amp;nbsp;reliable.&lt;/p&gt;
&lt;p&gt;This is a blog to help you &lt;span class="caps"&gt;IF&lt;/span&gt; you are interested in an alternative to Git+&lt;span class="caps"&gt;LFS&lt;/span&gt; and Perforce+$$$. If you&amp;#8217;re not interested that is&amp;nbsp;fine.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not just me who thinks Git+&lt;span class="caps"&gt;LFS&lt;/span&gt; is bad. Ari Arnbjörnsson also thinks it kinda sucks for
Unreal&amp;nbsp;development.&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/U0RCO0id1kI?si=RDujqesgtAHRMAJh" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h3 id="summary"&gt;Summary&lt;/h3&gt;
&lt;p&gt;For small hobby projects Git/GitHub are fine. Ignore this, carry on using&amp;nbsp;Git.&lt;/p&gt;
&lt;p&gt;For &lt;span class="caps"&gt;AAA&lt;/span&gt; just use Perforce, you&amp;#8217;ve got the&amp;nbsp;money.&lt;/p&gt;
&lt;p&gt;For film or architecture/visualization, just use perforce as your files are likely way to big and your staff less open to&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;For medium to &lt;span class="caps"&gt;AA&lt;/span&gt; games I&amp;#8217;d argue Subversion is fine. Not perfect, but fine. For teams between 5 and 50 members it fine. For 100+ you&amp;#8217;re definitely in the Perforce territory and outside my experience. You might be fine. I&amp;#8217;d hazard a guess that you would be fine but this is outside of my&amp;nbsp;experience.&lt;/p&gt;
&lt;h2 id="why"&gt;Why&lt;/h2&gt;
&lt;p&gt;Opinions, you don&amp;#8217;t have to agree with&amp;nbsp;me.&lt;/p&gt;
&lt;h3 id="gitlfs-is-slow"&gt;Git+&lt;span class="caps"&gt;LFS&lt;/span&gt; is&amp;nbsp;slow&lt;/h3&gt;
&lt;p&gt;It&amp;#8217;s not terrible but it&amp;#8217;s slower than Perforce and Subversion. Locking is also not perfect and I found
it failed frequently. I do not consider Git+&lt;span class="caps"&gt;LFS&lt;/span&gt; to be mature for the thousands of opaque binary files that Unreal uses. I do not consider Git+&lt;span class="caps"&gt;LFS&lt;/span&gt; locking to be mature for medium sized&amp;nbsp;teams.&lt;/p&gt;
&lt;h3 id="gitlfs-doesnt-scale-as-well-as-perforce-and-subversion"&gt;Git+&lt;span class="caps"&gt;LFS&lt;/span&gt; doesn&amp;#8217;t scale as well as Perforce and&amp;nbsp;Subversion.&lt;/h3&gt;
&lt;p&gt;Git stores the whole repository over time locally. This is great because
you can switch branches trivially, experiment more easily and develop powerful workflows. Alas it means every binary
file exists in all it&amp;#8217;s forms over the life of the project locally. Even a medium sized Unreal game will be &lt;span class="caps"&gt;100GB&lt;/span&gt;
of live assets and nanite is making this look small. After a few years for a small team of 10 this can result in a dataset nearing &lt;span class="caps"&gt;1TB&lt;/span&gt; of data. Disk space
is cheap but it&amp;#8217;s all just noise and slows Windows and git&amp;nbsp;down.&lt;/p&gt;
&lt;p&gt;Git&amp;#8217;s primary innovation of it&amp;#8217;s branching strategy and branching is not used by most Unreal devs because locking files is integral to the workflow of Unreal&amp;nbsp;Editor.&lt;/p&gt;
&lt;p&gt;A &lt;span class="caps"&gt;AAA&lt;/span&gt; game will easily have &lt;span class="caps"&gt;1TB&lt;/span&gt; of live assets and a total dataset can easily be &lt;span class="caps"&gt;50TB&lt;/span&gt; in size. For this scale Perforce
really is the only product in town&amp;#8230; but most people will not be working on a game that&amp;nbsp;large.&lt;/p&gt;
&lt;h3 id="perforce"&gt;Perforce&lt;/h3&gt;
&lt;p&gt;This is industry standard. This is a pointless phrase and tells you nothing of whether it meets your needs. The 
games industry is conservative and like all mature industries, full of group&amp;nbsp;think.&lt;/p&gt;
&lt;p&gt;Perforce is stable, secure and scales well. 
If you want to use it, it&amp;#8217;s great. It&amp;#8217;s expensive though. It broadly uses the same algorithms as Subversion to store 
data but it&amp;#8217;s primary advantage is Streams, tight integration in to Unreal Editor and it scales to &lt;span class="caps"&gt;HUGE&lt;/span&gt; depot&amp;nbsp;sizes.&lt;/p&gt;
&lt;p&gt;Unlike GitHub, GitLab or Gitea, Perforce is a stable product over time. You won&amp;#8217;t be upgrading every week with security patches
you won&amp;#8217;t have fancy websites to worry about being hacked, you will basically, every so often, load the admin
interface to check why it&amp;#8217;s starting to crawl and delete users because you&amp;#8217;re running out of seat licenses and
the &lt;span class="caps"&gt;CFO&lt;/span&gt; wonders why your sending $$$ to a company in &lt;span class="caps"&gt;SW&lt;/span&gt;&amp;nbsp;England.&lt;/p&gt;
&lt;h2 id="good-and-bad-of-subversion"&gt;Good and bad of&amp;nbsp;Subversion&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;m just gonna add a summary here because you&amp;#8217;ve already read a&amp;nbsp;lot.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;+ server is simple to setup on Windows, Linux, *&lt;span class="caps"&gt;BSD&lt;/span&gt; or&amp;nbsp;macOS&lt;/li&gt;
&lt;li&gt;+ easy to&amp;nbsp;maintain&lt;/li&gt;
&lt;li&gt;+ works just as well if not better than Perforce with Unreal&amp;nbsp;Editor&lt;/li&gt;
&lt;li&gt;+ is substantially faster than&amp;nbsp;Git.&lt;/li&gt;
&lt;li&gt;+ Is supported by UnrealEd out of the&amp;nbsp;box&lt;/li&gt;
&lt;li&gt;+ Repo size scales better than Git (but not as well as&amp;nbsp;perforce).&lt;/li&gt;
&lt;li&gt;+ Team size scales better than Git (but not as well as&amp;nbsp;perforce).&lt;/li&gt;
&lt;li&gt;+ Simple to backup&amp;#8230; remember to do&amp;nbsp;this!&lt;/li&gt;
&lt;li&gt;+ Free to&amp;nbsp;use.&lt;/li&gt;
&lt;li&gt;+ Highly scriptable, much better than Perforce, same as&amp;nbsp;git&lt;/li&gt;
&lt;li&gt;+ Integrates with Jenkins out of the&amp;nbsp;box&lt;/li&gt;
&lt;li&gt;+ Supports locking by default&amp;#8230; and it works and you can cancel/override&amp;nbsp;locks.&lt;/li&gt;
&lt;li&gt;+ Subversion is extremely mature. It changes slowly letting you get on with you actual job of making a&amp;nbsp;game.&lt;/li&gt;
&lt;li&gt;+ &lt;span class="caps"&gt;BP&lt;/span&gt; &amp;#8220;diffing against last depot&amp;#8221; is fast because the &amp;#8220;depot&amp;#8221; reversion is stored locally (see negative&amp;nbsp;[1])&lt;/li&gt;
&lt;li&gt;- &lt;a href="https://tortoisesvn.net/"&gt;Tortoise Subversion&lt;/a&gt; is the best &amp;#8220;desktop &lt;span class="caps"&gt;UI&lt;/span&gt;&amp;#8221; for Subversion. It&amp;#8217;s worse then P4Win, GitFork, GitExtension, GitHub Desktop. But you&amp;#8217;ll mostly be in Unreal or Rider both of which support Subversion very&amp;nbsp;well.&lt;/li&gt;
&lt;li&gt;- When you checkout an Subversion repository you get two copies of nearly everything (by design this is to make reverts/diffs fast) and this is why for &lt;span class="caps"&gt;AAA&lt;/span&gt; it&amp;#8217;s not good enough. Still better than a version of everything through all time like git-lfs though.&amp;nbsp;[1]&lt;/li&gt;
&lt;li&gt;- You don&amp;#8217;t get all the bells and whistles of bug tracking, &lt;span class="caps"&gt;CI&lt;/span&gt;, Pull requests that you get with GitHub/Lab and for $$$ with&amp;nbsp;Perforce.&lt;/li&gt;
&lt;li&gt;- Perforce streams are a good way to lower bandwidth for remote teams. With Subversion you can (ab)use it&amp;#8217;s &lt;code&gt;externals&lt;/code&gt; property to create something similar but it&amp;#8217;s not as powerful. It does work though. I&amp;#8217;ve used externals to create &amp;#8220;views&amp;#8221; of the repo for design, art and&amp;nbsp;code.&lt;/li&gt;
&lt;li&gt;- Perforce support exists. It&amp;#8217;s not that good but it is there. Subversion support is the&amp;nbsp;internet.&lt;/li&gt;
&lt;li&gt;- Perforce is industry standard and by that I mean people who know nothing about source control will complain you are not using Perforce only to complain just as much if you do use Perforce. Go&amp;nbsp;figure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="setting-up-subversion"&gt;Setting up&amp;nbsp;Subversion&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;This isn&amp;#8217;t a tutorial, there are already lots of those out there for your &lt;span class="caps"&gt;OS&lt;/span&gt; of&amp;nbsp;choice&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A fresh install of any operating systems will do. Install Subversion, Apache and Python 3
on these machines which are all mature well used packages on most operating systems. There are detailed docs
for all platforms on installing Subversion. I&amp;#8217;ll just give my set up here. If you must use docker&amp;#8230; then there
are docker files out&amp;nbsp;there.&lt;/p&gt;
&lt;p&gt;You&amp;#8217;ll need at least two (metal or virtual) machines if you want a live backup (which I recommend). The backup can be a small &lt;span class="caps"&gt;PC&lt;/span&gt; in your home. You don&amp;#8217;t need to give &lt;span class="caps"&gt;AWS&lt;/span&gt;/&lt;span class="caps"&gt;MS&lt;/span&gt; more money. Just make sure you do back shit&amp;nbsp;up!&lt;/p&gt;
&lt;p&gt;Here is my (FreeBSD) apache conf file for&amp;nbsp;svn&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/usr/local/etc/apache24/Include/svn.conf&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;LoadModule&lt;span class="w"&gt; &lt;/span&gt;dav_svn_module&lt;span class="w"&gt;     &lt;/span&gt;libexec/apache24/mod_dav_svn.so
LoadModule&lt;span class="w"&gt; &lt;/span&gt;authz_svn_module&lt;span class="w"&gt;   &lt;/span&gt;libexec/apache24/mod_authz_svn.so

KeepAlive&lt;span class="w"&gt; &lt;/span&gt;on
MaxKeepAliveRequests&lt;span class="w"&gt; &lt;/span&gt;1000
Timeout&lt;span class="w"&gt; &lt;/span&gt;12000
KeepAliveTimeout&lt;span class="w"&gt; &lt;/span&gt;15

&lt;span class="nt"&gt;&amp;lt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dav_svn_module&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
#&lt;span class="w"&gt; &lt;/span&gt;Add&lt;span class="w"&gt; &lt;/span&gt;some&lt;span class="w"&gt; &lt;/span&gt;over&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;wire&lt;span class="w"&gt; &lt;/span&gt;compression
SVNCompressionLevel&lt;span class="w"&gt; &lt;/span&gt;5

#&lt;span class="w"&gt; &lt;/span&gt;cache&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;in&lt;span class="w"&gt; &lt;/span&gt;KB
SVNInMemoryCacheSize&lt;span class="w"&gt; &lt;/span&gt;16384
SVNCacheTextDeltas&lt;span class="w"&gt; &lt;/span&gt;On
SVNCacheFullTexts&lt;span class="w"&gt; &lt;/span&gt;On

&lt;span class="nt"&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;VirtualHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;ServerName&lt;span class="w"&gt; &lt;/span&gt;XXX_YOUR_SERVER_NAME_HERE_XXX

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;Location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;ifModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mime_module&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;RemoveEncoding&lt;span class="w"&gt;  &lt;/span&gt;.gz&lt;span class="w"&gt; &lt;/span&gt;.tgz&lt;span class="w"&gt; &lt;/span&gt;.Z
&lt;span class="w"&gt;            &lt;/span&gt;RemoveType&lt;span class="w"&gt;      &lt;/span&gt;.gz&lt;span class="w"&gt; &lt;/span&gt;.tgz&lt;span class="w"&gt; &lt;/span&gt;.Z
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/ifModule&amp;gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;DAV&lt;span class="w"&gt; &lt;/span&gt;svn
&lt;span class="w"&gt;        &lt;/span&gt;SVNParentPath&lt;span class="w"&gt; &lt;/span&gt;/var/svn/

&lt;span class="w"&gt;        &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;Authentication:&lt;span class="w"&gt; &lt;/span&gt;Digest
&lt;span class="w"&gt;        &lt;/span&gt;AuthName&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;SVN&amp;quot;
&lt;span class="w"&gt;        &lt;/span&gt;AuthType&lt;span class="w"&gt; &lt;/span&gt;Digest
&lt;span class="w"&gt;        &lt;/span&gt;AuthDigestProvider&lt;span class="w"&gt; &lt;/span&gt;file
&lt;span class="w"&gt;        &lt;/span&gt;AuthUserFile&lt;span class="w"&gt; &lt;/span&gt;/usr/local/etc/apache24/svn-auth.htdigest

&lt;span class="w"&gt;        &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;Authorization:&lt;span class="w"&gt; &lt;/span&gt;Authenticated&lt;span class="w"&gt; &lt;/span&gt;users&lt;span class="w"&gt; &lt;/span&gt;only
&lt;span class="w"&gt;        &lt;/span&gt;Require&lt;span class="w"&gt; &lt;/span&gt;valid-user
&lt;span class="w"&gt;        &lt;/span&gt;AuthzSVNAccessFile&lt;span class="w"&gt; &lt;/span&gt;/usr/local/etc/apache24/svn-authzaccess.conf
&lt;span class="w"&gt;        &lt;/span&gt;Satisfy&lt;span class="w"&gt; &lt;/span&gt;Any

&lt;span class="w"&gt;        &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;Allow&lt;span class="w"&gt; &lt;/span&gt;repo&lt;span class="w"&gt; &lt;/span&gt;roots&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;browsed.
&lt;span class="w"&gt;        &lt;/span&gt;SVNListParentPath&lt;span class="w"&gt; &lt;/span&gt;on

&lt;span class="w"&gt;        &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;Do&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;limit&lt;span class="w"&gt; &lt;/span&gt;large&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;requests
&lt;span class="w"&gt;        &lt;/span&gt;LimitXMLRequestBody&lt;span class="w"&gt; &lt;/span&gt;0

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Location&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are some tweakables in here but this is what works well for me. Again, there are lots of tutorials
about setting up&amp;nbsp;apache+svn.&lt;/p&gt;
&lt;h2 id="setting-user-password"&gt;Setting user&amp;nbsp;password&lt;/h2&gt;
&lt;p&gt;Apache will be doing user authentication. The above file tells apache where the
user password database is. This command adds a user and sets their&amp;nbsp;password.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt; htdigest /usr/local/etc/apache24/svn-auth.htdigest &amp;quot;SVN&amp;quot; &amp;lt;USERNAME&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To delete a user, edit the svn-auth-htdigest file and delete the line with the username in&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;If you want groups for finer access control look up svn conf/authz files, you can set groups
of users, set access controls to specific paths, set who can read and who can write&amp;nbsp;etc.&lt;/p&gt;
&lt;h2 id="security"&gt;Security&lt;/h2&gt;
&lt;p&gt;I always run access over &lt;span class="caps"&gt;VPN&lt;/span&gt; software. I use wireguard but use whatever you want. This gives me peace of mind. While apache and subversion are very mature and secure it pays to be&amp;nbsp;careful.&lt;/p&gt;
&lt;p&gt;If your team is on a &lt;span class="caps"&gt;LAN&lt;/span&gt; then you don&amp;#8217;t need a &lt;span class="caps"&gt;VPN&lt;/span&gt; as you can probably trust your
team members&amp;nbsp;(ymmv).&lt;/p&gt;
&lt;h2 id="maintenance-script"&gt;Maintenance&amp;nbsp;script&lt;/h2&gt;
&lt;p&gt;Server shell script to repack/clean repositories overnight. I&amp;#8217;m not actually sure if this is 
needed but it&amp;#8217;s mentioned in the docs so I do it. I went years without doing this
and never had a&amp;nbsp;problem.&lt;/p&gt;
&lt;p&gt;Again this is a FreeBSD csh&amp;nbsp;script.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/csh&lt;/span&gt;

&lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;SVNADMIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin/svnadmin
&lt;span class="nb"&gt;set &lt;/span&gt;&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/var/svn/

&lt;span class="nb"&gt;set dirs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;find &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ROOT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; -type d -depth 1&lt;span class="sb"&gt;`&lt;/span&gt;

&lt;span class="k"&gt;foreach &lt;/span&gt;dir &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dirs&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Cleaning transactions ${dir}&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SVNADMIN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; rmtxns &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SVNADMIN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; lstxns &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Packing ${dir}&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SVNADMIN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; pack &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2 id="backing-up"&gt;Backing&amp;nbsp;up&lt;/h2&gt;
&lt;p&gt;Subversion has a concept of syncing two repositories. The easiest way to backup your live repo is to have another machine, somewhere in the universe, that syncs all commit from the primary repo to the backup repo. I run this script nightly but you can do it every hour if you&amp;nbsp;want.&lt;/p&gt;
&lt;p&gt;Note in 15 years of using Subversion I&amp;#8217;ve had one corruption (due to a disk failure) and I had the repo back online in an a few hours. This was basically the time it took to move the data across the&amp;nbsp;internet.&lt;/p&gt;
&lt;p&gt;There are many good tutorials on setting this&amp;nbsp;up.&lt;/p&gt;
&lt;h2 id="integration-with-other-tools"&gt;Integration with other&amp;nbsp;tools.&lt;/h2&gt;
&lt;p&gt;Subversion has various hooks that get called when things happen. The most useful is the post-commit
hook to trigger Jenkins and to push a message to discord of a&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;In the trunk of each repository I have a folder called &lt;code&gt;.hooks&lt;/code&gt;. When subversion has committed
a file to the repo successfully this hooks/post-commit script is&amp;nbsp;called&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;REPOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;REV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="nv"&gt;CWD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;dirname&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;span class="nv"&gt;PYTHON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin/python3.11

&lt;span class="nv"&gt;jenkins_username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;buildbot
&lt;span class="nv"&gt;jenkins_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;SECRET&amp;gt;

&lt;span class="nv"&gt;discord_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;SECRET&amp;gt;
&lt;span class="nv"&gt;discord_webhookid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;SECRET&amp;gt;

&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:/usr/local/bin

&lt;span class="c1"&gt;# create a temp file for the post-commit.py script&lt;/span&gt;
&lt;span class="nv"&gt;tmpfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;/tmp/post-commit.XXXXXXXX&lt;span class="k"&gt;)&lt;/span&gt;
svnlook&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$CWD&lt;/span&gt;/../&lt;span class="w"&gt; &lt;/span&gt;/trunk/.hooks/post-commit.py&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$tmpfile&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-gt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;No post-commit&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;


&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jenkins_username
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;jenkins_secret
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;discord_secret
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;discord_webhookid
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PATH

&lt;span class="nv"&gt;$PYTHON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$tmpfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$REPOS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$REV&lt;/span&gt;

rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$tmpfile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The script never really changes and stores the secrets I don&amp;#8217;t want in the repository 
(password, tokens&amp;nbsp;etc). &lt;/p&gt;
&lt;p&gt;The script copies a python file from the repo called post-commit.py and runs that. This
allows each repo to have scriptable actions that are easily changed and the changes are
recorded in the&amp;nbsp;repo.&lt;/p&gt;
&lt;h3 id="post-commitpy"&gt;post-commit.py&lt;/h3&gt;
&lt;script src="https://gist.github.com/executionunit/3292d86c3224d8136c696cf66be737ae.js"&gt;&lt;/script&gt;

&lt;p&gt;This file does all the work. It copies a json file from the repository in &lt;code&gt;/trunk/.hooks/post-commit.json&lt;/code&gt; and uses data in that to decide what actions to do depending on what files/paths&amp;nbsp;changed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;If you&amp;#8217;re going to use this you&amp;#8217;ll need to install some python&amp;nbsp;packages&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="post-commitjson"&gt;post-commit.json&lt;/h3&gt;
&lt;script src="https://gist.github.com/executionunit/8fef79a1227fa5e1d975129678827c4b.js"&gt;&lt;/script&gt;

&lt;p&gt;This is the file contains configuration info for jobs that will be run if certain conditions are&amp;nbsp;met.&lt;/p&gt;
&lt;p&gt;Hope this helps&amp;nbsp;someone.&lt;/p&gt;
&lt;h3 id="changes"&gt;Changes:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;240827 - added video on git+lfs not being&amp;nbsp;great.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class="caps"&gt;EOL&lt;/span&gt;&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="Unreal"></category><category term="Subversion"></category></entry><entry><title>MSVC Print All Predefined #Defines</title><link href="https://www.executionunit.com/blog/2022/09/24/msvc-print-all-predefined-defines/" rel="alternate"></link><published>2022-09-24T00:00:00+01:00</published><updated>2022-09-24T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2022-09-24:/blog/2022/09/24/msvc-print-all-predefined-defines/</id><summary type="html">&lt;p&gt;Sometimes you really need to know what defines your compiler has on by&amp;nbsp;default.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Sometimes you really need to know what defines your compiler has on by default. I had no idea how
to do this with Visual Studio so I dug in. Here is how to do&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Open up a &lt;span class="caps"&gt;VS&lt;/span&gt; command prompt, pick the appropriate prompt x86, x64&amp;nbsp;etc.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/uploads/blog/vs_cmd_prompt.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;enter the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; echo int main(){} &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; test.cpp
&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; cl.exe /PD /Zc:preprocessor test.cpp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You should see output similar to the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;
&lt;span class="normal"&gt;56&lt;/span&gt;
&lt;span class="normal"&gt;57&lt;/span&gt;
&lt;span class="normal"&gt;58&lt;/span&gt;
&lt;span class="normal"&gt;59&lt;/span&gt;
&lt;span class="normal"&gt;60&lt;/span&gt;
&lt;span class="normal"&gt;61&lt;/span&gt;
&lt;span class="normal"&gt;62&lt;/span&gt;
&lt;span class="normal"&gt;63&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cpp&lt;/span&gt;
&lt;span class="cp"&gt;#define _CPPRTTI 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_ref_qualifiers 200710L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_init_captures 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define __STDCPP_DEFAULT_NEW_ALIGNMENT__ 8u&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_rtti 199711L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_decltype_auto 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSC_EXTENSIONS 1&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSVC_LANG 201402L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_binary_literals 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_constexpr 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSC_BUILD 0&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_attributes 200809L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_inheriting_constructors 200802L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_generic_lambdas 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_variable_templates 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_nsdmi 200809L&lt;/span&gt;
&lt;span class="cp"&gt;#define _NATIVE_WCHAR_T_DEFINED 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __BOOL_DEFINED 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_sized_deallocation 201309L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_threadsafe_static_init 200806L&lt;/span&gt;
&lt;span class="cp"&gt;#define _HAS_CHAR16_T_LANGUAGE_SUPPORT 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_initializer_lists 200806L&lt;/span&gt;
&lt;span class="cp"&gt;#define _IS_ASSIGNABLE_NOCHECK_SUPPORTED 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_static_assert 200410L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_return_type_deduction 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_enumerator_attributes 201411L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_decltype 200707L&lt;/span&gt;
&lt;span class="cp"&gt;#define _M_IX86_FP 2&lt;/span&gt;
&lt;span class="cp"&gt;#define _CONSTEXPR_CHAR_TRAITS_SUPPORTED 1&lt;/span&gt;
&lt;span class="cp"&gt;#define _MT 1&lt;/span&gt;
&lt;span class="cp"&gt;#define _WCHAR_T_DEFINED 1&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSVC_WARNING_LEVEL 1L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_alias_templates 200704L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cplusplus 199711L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_lambdas 200907L&lt;/span&gt;
&lt;span class="cp"&gt;#define __STDC_HOSTED__ 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_user_defined_literals 200809L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_rvalue_references 200610L&lt;/span&gt;
&lt;span class="cp"&gt;#define _NATIVE_NULLPTR_SUPPORTED 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_namespace_attributes 201411L&lt;/span&gt;
&lt;span class="cp"&gt;#define __STDCPP_THREADS__ 1&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSC_FULL_VER 193331629&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSC_VER 1933&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSVC_TRADITIONAL 0&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_range_based_for 200907L&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSVC_CONSTEXPR_ATTRIBUTE 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_raw_strings 200710L&lt;/span&gt;
&lt;span class="cp"&gt;#define _M_IX86 600&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_unicode_literals 200710L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_unicode_characters 200704L&lt;/span&gt;
&lt;span class="cp"&gt;#define _MSVC_EXECUTION_CHARACTER_SET 1252&lt;/span&gt;
&lt;span class="cp"&gt;#define _INTEGRAL_MAX_BITS 64&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_aggregate_nsdmi 201304L&lt;/span&gt;
&lt;span class="cp"&gt;#define _WIN32 1&lt;/span&gt;
&lt;span class="cp"&gt;#define _CRT_USE_BUILTIN_OFFSETOF 1&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_variadic_templates 200704L&lt;/span&gt;
&lt;span class="cp"&gt;#define __cpp_delegating_constructors 200604L&lt;/span&gt;
&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Incremental&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Linker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;14.33.31629.0&lt;/span&gt;
&lt;span class="n"&gt;Copyright&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Corporation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;All&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rights&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;reserved&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I turned this in to a simple&amp;nbsp;batchfile&lt;/p&gt;
&lt;script src="https://gist.github.com/executionunit/b19adb679bdfe26b67179def116b754b.js"&gt;&lt;/script&gt;

&lt;p&gt;Hope this&amp;nbsp;helps.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;EOL&lt;/span&gt;.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="Unreal"></category><category term="C++"></category></entry><entry><title>Unreal: Am I On The Server</title><link href="https://www.executionunit.com/blog/2022/09/24/unreal-am-i-on-the-server/" rel="alternate"></link><published>2022-09-24T00:00:00+01:00</published><updated>2022-09-24T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2022-09-24:/blog/2022/09/24/unreal-am-i-on-the-server/</id><summary type="html">&lt;p&gt;I&amp;#8217;ve been working on an Unreal game for the past few months. One of the things that
the whole team has found very frustrating is knowing if the code we are writing is
running on the server or the&amp;nbsp;client.&lt;/p&gt;
&lt;p&gt;Lots of code only needs to run on one …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve been working on an Unreal game for the past few months. One of the things that
the whole team has found very frustrating is knowing if the code we are writing is
running on the server or the&amp;nbsp;client.&lt;/p&gt;
&lt;p&gt;Lots of code only needs to run on one or the other and some code needs to run on both.
Unreal has a powerful and slightly confusing networking model combined with numerous ways to run
the game from within the&amp;nbsp;editor.&lt;/p&gt;
&lt;p&gt;To help me understand the different modes I created the following table. I wrote a small bit
of code in my GameMode class to extract some values. I added a break point just after this code
so that I could record the&amp;nbsp;values.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;UWorld&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;World&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GetWorld&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;ENetMode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NetMode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GetNetMode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;ENetRole&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SystemRole&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GetLocalRole&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bHasAuthority&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HasAuthority&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GameMode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;World&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetAuthGameMode&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;PlayMode&lt;/code&gt; is the mode you select in the editor (in the Play button drop&amp;nbsp;down).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;#&lt;/code&gt; is the number of players selected in&amp;nbsp;editor&lt;/p&gt;
&lt;p&gt;&lt;code&gt;BP&lt;/code&gt; is the number of times my break point is hit. So for two players I would expect to hit it twice
(note that this isn&amp;#8217;t true in one&amp;nbsp;case).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Has Game Mode&lt;/code&gt; technically the game mode only ever exists in the&amp;nbsp;server.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Play Mode&lt;/th&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;&lt;span class="caps"&gt;BP&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;Net Mode&lt;/th&gt;
&lt;th&gt;System Role&lt;/th&gt;
&lt;th style="text-align: center;"&gt;Has Game Mode&lt;/th&gt;
&lt;th style="text-align: center;"&gt;Has Authority&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;StandAlone&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NM_StandAlone&lt;/td&gt;
&lt;td&gt;Role_Authority&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StandAlone&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NM_StandAlone&lt;/td&gt;
&lt;td&gt;Role_Authority&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;NM_StandAlone&lt;/td&gt;
&lt;td&gt;Role_Authority&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Listen Server&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NM_ListenServer&lt;/td&gt;
&lt;td&gt;Role_Authority&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Listen Server&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NM_ListenServer&lt;/td&gt;
&lt;td&gt;Role_Authority&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;NM_Client&lt;/td&gt;
&lt;td&gt;Role_SimulatedProxy&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NM_DedicatedServer&lt;/td&gt;
&lt;td&gt;Role_Authority&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;NM_Client&lt;/td&gt;
&lt;td&gt;Role_SimulatedProxy&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;NM_DedicatedServer&lt;/td&gt;
&lt;td&gt;Role_Authority&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;td style="text-align: center;"&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;NM_Client&lt;/td&gt;
&lt;td&gt;Role_SimulatedProxy&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;NM_Client&lt;/td&gt;
&lt;td&gt;Role_SimulatedProxy&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;td style="text-align: center;"&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It all makes sense to me apart from in StandAlone mode. In all other scenarios &lt;code&gt;NetMode&lt;/code&gt; and &lt;code&gt;SystemRole&lt;/code&gt; have
reasonable values. You can easily say &amp;#8220;this code is running on the server&amp;#8221; when &lt;code&gt;NetMode == NM_ListenServer&lt;/code&gt; or 
&lt;code&gt;NetMode == NM_DedicatedServer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So what is going on in &lt;strong&gt;Stand Alone&lt;/strong&gt; mode? In standalone mode everything is running inside one process,
the same process the editor is in. So The code is both the server and the client. This makes some
things easier to debug and other things just plain confusing. I think this is the scenario for a split
screen game, so it&amp;#8217;s important your code works in this mode as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;As a side note &lt;a href="https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool"&gt;Visual Studio has a plugin&lt;/a&gt; to enable child process debugging. With this plugin you can
launch the editor from &lt;span class="caps"&gt;VS&lt;/span&gt;, play the game and launch child clients and the debugger will attach to them
and allow you to set break points and view memory, very&amp;nbsp;useful.&lt;/p&gt;
&lt;p&gt;Hope this&amp;nbsp;helps.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;EOL&lt;/span&gt;.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="Unreal"></category></entry><entry><title>OpnSense Wiregaurd VPN Road warrior setup.</title><link href="https://www.executionunit.com/blog/2022/07/22/opnsense-wiregaurd-vpn-road-warrior-setup/" rel="alternate"></link><published>2022-07-22T00:00:00+01:00</published><updated>2022-07-22T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2022-07-22:/blog/2022/07/22/opnsense-wiregaurd-vpn-road-warrior-setup/</id><summary type="html">&lt;p&gt;How I set up Wireguard &lt;span class="caps"&gt;VPN&lt;/span&gt; in OpnSense asa road&amp;nbsp;warrior&lt;/p&gt;</summary><content type="html">&lt;div class="toc"&gt;&lt;span class="toctitle"&gt;Table of contents:&lt;/span&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#enable-wireguard-on-opnsense"&gt;Enable Wireguard on&amp;nbsp;OpnSense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-a-local-wireguard-instanceconfiguration"&gt;Create a local wireguard&amp;nbsp;instance/configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#create-a-client-end-point"&gt;Create a client end&amp;nbsp;point&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#add-opnsense-fireguard-rule"&gt;Add OpnSense Fireguard&amp;nbsp;rule&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#client-configuration"&gt;Client&amp;nbsp;Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#what-is-missing"&gt;What is&amp;nbsp;missing?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;I found getting &lt;a href="https://www.wireguard.com/"&gt;WireGuard&lt;/a&gt; to work on &lt;a href="https://opnsense.org/"&gt;OpnSense&lt;/a&gt;
a &amp;#8220;little tricky&amp;#8221; to say the least (but far easier than&amp;nbsp;OpenVPN).&lt;/p&gt;
&lt;p&gt;The setup I wanted is the classic Road Warrior setup. While away from my office I need my laptop to have
access to the office &lt;span class="caps"&gt;LAN&lt;/span&gt;, so I can remote desktop to my work &lt;span class="caps"&gt;PC&lt;/span&gt; and I need all my mobile phone data (iOS)
to be routed securely via the&amp;nbsp;office.&lt;/p&gt;
&lt;p&gt;I started with the &lt;a href="https://docs.opnsense.org/manual/how-tos/wireguard-client.html"&gt;official docs for a Road Warrior Setup&lt;/a&gt;.
This didn&amp;#8217;t work out of the box for me. So I&amp;#8217;m detailing my setup just incase it is useful for&amp;nbsp;others.&lt;/p&gt;
&lt;h3 id="enable-wireguard-on-opnsense"&gt;Enable Wireguard on&amp;nbsp;OpnSense&lt;/h3&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/uploads/blog/wireguard/opnsense1.jpg" alt="Enable WireGaurd"/&gt;&lt;/p&gt;
&lt;p&gt;Note: you will need to install the plugin&amp;nbsp;first!&lt;/p&gt;
&lt;h3 id="create-a-local-wireguard-instanceconfiguration"&gt;Create a local wireguard&amp;nbsp;instance/configuration&lt;/h3&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/uploads/blog/wireguard/opnsense2.jpg" alt="WireGuard Configuration"/&gt;&lt;/p&gt;
&lt;p&gt;The public and private key can be generated for you. &lt;strong&gt;Remember to keep the private key private!&lt;/strong&gt;. Set a high listen port (51820 or&amp;nbsp;higher).&lt;/p&gt;
&lt;p&gt;I decided to go with the private &lt;span class="caps"&gt;IP&lt;/span&gt; range 10.10.10.x for my &lt;span class="caps"&gt;VPN&lt;/span&gt;. So the server (tunnel address) is on 10.10.10.1 and
all clients will be on 10.10.10.2, 10.10.10.3,&amp;nbsp;&amp;#8230;&lt;/p&gt;
&lt;h3 id="create-a-client-end-point"&gt;Create a client end&amp;nbsp;point&lt;/h3&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/uploads/blog/wireguard/endpoint1.jpg" alt="WireGuard Configuration"/&gt;&lt;/p&gt;
&lt;p&gt;Once you&amp;#8217;ve created an end point remember to enable it in the Peers options in the local&amp;nbsp;configuration.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/uploads/blog/wireguard/opnsense3.jpg" alt="Peers Configuration"/&gt;&lt;/p&gt;
&lt;h3 id="add-opnsense-fireguard-rule"&gt;Add OpnSense Fireguard&amp;nbsp;rule&lt;/h3&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/uploads/blog/wireguard/opnsense4.jpg" alt="Firewall"/&gt;&lt;/p&gt;
&lt;p&gt;Gotta let those packets in through the &lt;span class="caps"&gt;WAN&lt;/span&gt;. Make sure that the &lt;strong&gt;port&lt;/strong&gt; is the same as the one you set in the WireGuard&amp;nbsp;configuration.&lt;/p&gt;
&lt;p&gt;I think WireGuard created rules for me allowing packets to go from the WireGuard interface to any other group.
For example from WireGuard (10.10.10.x) to &lt;span class="caps"&gt;LAN&lt;/span&gt;&amp;nbsp;(192.168.1.x).&lt;/p&gt;
&lt;h3 id="client-configuration"&gt;Client&amp;nbsp;Configuration&lt;/h3&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/uploads/blog/wireguard/pc-wg.jpg" alt="PC Configuration"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;note: endpoint is the &lt;span class="caps"&gt;IP&lt;/span&gt;:&lt;span class="caps"&gt;PORT&lt;/span&gt; pair of the WireGuard&amp;nbsp;router.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.wireguard.com/install/"&gt;I installed the official Windows client&lt;/a&gt;.
Most of the values in here are just copies of the ones from OpnSense. Crucially you will need to set the private
key that you generated on the server in here. I would show you the editable configuration (by clicking the edit button)
but when I did that WireGuard stopped responding and now after restarting it the configuration has been deleted! I
mostly followed &lt;a href="https://www.makeuseof.com/how-to-set-up-wireguard-windows/"&gt;this&lt;/a&gt; tutorial to get Windows set&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;The bit in the client configuration that was &lt;span class="caps"&gt;NOT&lt;/span&gt; intuitive for me was the Allowed IPs. The documentation seemed to
imply that setting &lt;code&gt;0.0.0.0/24&lt;/code&gt; allowed the client to route to any network. This didn&amp;#8217;t work for me at all, and I
had to explicitly allow &lt;code&gt;10.10.10.0/24&lt;/code&gt; for access to the &lt;span class="caps"&gt;DNS&lt;/span&gt; server in this subnet and &lt;code&gt;192.168.1.0/24&lt;/code&gt; to allow
access to the &lt;span class="caps"&gt;LAN&lt;/span&gt; &lt;strong&gt;as well as&lt;/strong&gt; &lt;code&gt;0.0.0.0/0&lt;/code&gt; which allowed my clients to access networks outside my &lt;span class="caps"&gt;LAN&lt;/span&gt; but still
via the &lt;span class="caps"&gt;VPN&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The settings for iOS were similar. I installed the
&lt;a href="https://apps.apple.com/us/app/wireguard/id1441195209"&gt;official WireGuard app from the App Store&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="what-is-missing"&gt;What is&amp;nbsp;missing?&lt;/h3&gt;
&lt;p&gt;For me, the only thing that is missing is some form of two-factor authentication. This isn&amp;#8217;t a deal-breaker as
you need to log in to my laptop, and you need my face to unlock my phone. However, I feel it would be good especially
for my laptop for some form of added authentication to take place before connecting to my &lt;span class="caps"&gt;VPN&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Hope this helps someone&amp;nbsp;else.&lt;/p&gt;
&lt;p&gt;dazza.&lt;/p&gt;</content><category term="freebsd"></category><category term="FreeBSD"></category></entry><entry><title>Adding “Fork Me on Github” to Pelican Templates</title><link href="https://www.executionunit.com/blog/2020/04/24/adding-fork-me-on-github-to-pelican-templates/" rel="alternate"></link><published>2020-04-24T00:00:00+01:00</published><updated>2020-04-24T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2020-04-24:/blog/2020/04/24/adding-fork-me-on-github-to-pelican-templates/</id><summary type="html">&lt;p&gt;I just wrote a blog about a project I uploaded to GitHub and I wanted to
have a &amp;#8220;Fork Me On GitHub ribbon&amp;#8221; in the top right of the page. This is the
cool thing to do nowadays after&amp;nbsp;all.&lt;/p&gt;
&lt;p&gt;I write my blog using a static website generator called …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I just wrote a blog about a project I uploaded to GitHub and I wanted to
have a &amp;#8220;Fork Me On GitHub ribbon&amp;#8221; in the top right of the page. This is the
cool thing to do nowadays after&amp;nbsp;all.&lt;/p&gt;
&lt;p&gt;I write my blog using a static website generator called &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt;. One of the advantages of Pelican is that
the templates used to generate the static site are easily modifiable. Here
is what I&amp;nbsp;did.&lt;/p&gt;
&lt;p&gt;Firstly I found someone who had done the dirty work of creating a &lt;span class="caps"&gt;CSS&lt;/span&gt;
&lt;a href="https://simonwhitaker.github.io/github-fork-ribbon-css/"&gt;ribbon&lt;/a&gt;,
Thank you Simon. For Simon&amp;#8217;s ribbon to appear I needed to add one &lt;span class="caps"&gt;CSS&lt;/span&gt;
file and an anchor to any page with a GitHub link in&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Adding metadata to articles in Pelican is very easy. For any article
that needed a GitHub ribbon I add some metadata named &lt;code&gt;githuburl&lt;/code&gt;. Here
is the meta data for my&amp;nbsp;article:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CSGJS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;CPP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GitHub&lt;/span&gt;
&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20200424&lt;/span&gt;
&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GameDev&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="n"&gt;Authors&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dazza&lt;/span&gt;
&lt;span class="n"&gt;githuburl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;://&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;com&lt;/span&gt;&lt;span class="sr"&gt;/executionunit/&lt;/span&gt;&lt;span class="n"&gt;csgjs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cpp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So now when processing an article and generating &lt;span class="caps"&gt;HTML&lt;/span&gt; the article object
will have a member called&amp;nbsp;githuburl.&lt;/p&gt;
&lt;p&gt;The blogposts are rendered using the &lt;code&gt;article.html&lt;/code&gt; template. I&amp;nbsp;added&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;extracss&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="x"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;article.githuburl&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="x"&gt;        &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css&amp;quot; /&amp;gt;&lt;/span&gt;
&lt;span class="x"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;to the top and at the&amp;nbsp;bottom.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;endbody&lt;/span&gt;&lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;article.githuburl&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github-fork-ribbon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;article.githuburl&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;data-ribbon=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Fork me on GitHub&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Fork me on GitHub&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Fork&lt;span class="w"&gt; &lt;/span&gt;me&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;GitHub&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This code creates two new blocks and if &lt;code&gt;article.githuburl&lt;/code&gt; has a value
the &lt;code&gt;extracss&lt;/code&gt; block will contain the &lt;span class="caps"&gt;CSS&lt;/span&gt; &lt;code&gt;link&lt;/code&gt; and the &lt;code&gt;endbody&lt;/code&gt; block
will contain the link to the GitHub&amp;nbsp;page.&lt;/p&gt;
&lt;p&gt;To make these blocks rendering in to the output &lt;span class="caps"&gt;HTML&lt;/span&gt; I need to tell the
template engine where to put them. So I modified &lt;code&gt;base.html&lt;/code&gt; which all
templates inherit&amp;nbsp;from.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;...
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;extracss&lt;/span&gt; &lt;span class="cp"&gt;%}{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;...
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cp"&gt;{%&lt;/span&gt;&lt;span class="k"&gt;block&lt;/span&gt; &lt;span class="nv"&gt;endbody&lt;/span&gt; &lt;span class="cp"&gt;%}{%&lt;/span&gt; &lt;span class="k"&gt;endblock&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After that I rebuilt my site and now I can have a little GitHub ribbon on any
page just by adding some meta data to an article. Pretty&amp;nbsp;cool.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.executionunit.com/blog/2020/04/24/csgjs-cpp-on-github/"&gt;You can see the article here&lt;/a&gt; complete with
a lovely GitHub&amp;nbsp;ribbon.&lt;/p&gt;
&lt;p&gt;I hope that makes&amp;nbsp;sense.&lt;/p&gt;
&lt;p&gt;dazza.&lt;/p&gt;</content><category term="misc"></category><category term="Python"></category></entry><entry><title>CSGJS-CPP on GitHub</title><link href="https://www.executionunit.com/blog/2020/04/24/csgjs-cpp-on-github/" rel="alternate"></link><published>2020-04-24T00:00:00+01:00</published><updated>2020-04-24T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2020-04-24:/blog/2020/04/24/csgjs-cpp-on-github/</id><summary type="html">&lt;p&gt;I spent some time playing around with &lt;a href="https://github.com/evanw/csg.js/"&gt;&lt;span class="caps"&gt;CSGJS&lt;/span&gt;&lt;/a&gt; over the weekend. It&amp;#8217;s a great library. I thought it might be interesting to port it to&amp;nbsp;C++.&lt;/p&gt;
&lt;p&gt;After quite a lot of googling I found that someone had already done most of the hard work &lt;a href="https://github.com/dabroz/csgjs-cpp"&gt;here&lt;/a&gt; which was nice and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I spent some time playing around with &lt;a href="https://github.com/evanw/csg.js/"&gt;&lt;span class="caps"&gt;CSGJS&lt;/span&gt;&lt;/a&gt; over the weekend. It&amp;#8217;s a great library. I thought it might be interesting to port it to&amp;nbsp;C++.&lt;/p&gt;
&lt;p&gt;After quite a lot of googling I found that someone had already done most of the hard work &lt;a href="https://github.com/dabroz/csgjs-cpp"&gt;here&lt;/a&gt; which was nice and they had kept the &lt;span class="caps"&gt;MIT&lt;/span&gt; license which was even&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;I decided I&amp;#8217;d take their work and see if I could improve it a little and learn how it&amp;nbsp;worked.&lt;/p&gt;
&lt;p&gt;The fundamental algorithm used is to take two sets of convex polygons that make up a 3D model, create separate &lt;a href="https://en.wikipedia.org/wiki/Binary_space_partitioning"&gt;&lt;span class="caps"&gt;BSP&lt;/span&gt; trees&lt;/a&gt; and then perform union, subtract or difference algorithms upon the target &lt;span class="caps"&gt;BSP&lt;/span&gt; tree. The algorithm is actually very nice and well documented here &lt;a href="https://pdfs.semanticscholar.org/eeb5/014f86750c54a87f214b03246799e970d114.pdf"&gt;Constructive Solid Geometry Using &lt;span class="caps"&gt;BSP&lt;/span&gt; Tree - Christian Segura1, Taylor Stine2, Jackie Yang&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The code I took worked pretty well but I managed to optimize making it about 40% faster and removed the memory&amp;nbsp;leaks.&lt;/p&gt;
&lt;p&gt;Here are some examples of the&amp;nbsp;output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A gourd with a cylinder&amp;nbsp;subtracted&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/gamedev_csglib/gourd-cylinder00.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The same gourd with the cylinder added&amp;nbsp;(union)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/gamedev_csglib/gourdpluscylinder02.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cube with a sphere union and cylinder subtracted along x, y and z&amp;nbsp;axis&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/gamedev_csglib/multiops01.png" /&gt;&lt;/p&gt;
&lt;p&gt;The good thing about the algorithm is that it&amp;#8217;s recursive nature and simple testable stages make it pretty easy to implement and test. The downside is that the creation of &lt;span class="caps"&gt;BSP&lt;/span&gt; trees both at the initial &amp;#8220;list of polygons to &lt;span class="caps"&gt;BSP&lt;/span&gt;&amp;#8221; stage and the processing stage cause a lot of allocations making this unsuitable for real time&amp;nbsp;operations.&lt;/p&gt;
&lt;p&gt;Anyway, all my changes and test harness are available on &lt;a href="https://github.com/executionunit/csgjs-cpp"&gt;git hub&lt;/a&gt; for people to play&amp;nbsp;with.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category></entry><entry><title>Smith and Winston - Update #11 - Halloween</title><link href="https://www.executionunit.com/blog/2019/10/28/smith-and-winston-update-11-halloween/" rel="alternate"></link><published>2019-10-28T00:00:00+00:00</published><updated>2019-10-28T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-10-28:/blog/2019/10/28/smith-and-winston-update-11-halloween/</id><summary type="html">&lt;p&gt;New update for Smith and Winston with Halloween helmets and 10%&amp;nbsp;off.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/SnW_twitter_10.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s our first sale! Halloween isn&amp;#8217;t really a British thing but you&amp;#8217;ve got to go with the&amp;nbsp;flow.&lt;/p&gt;
&lt;p&gt;So if you&amp;#8217;re looking for a bargain this All Hallows&amp;#8217; Eve look no further than Smith and&amp;nbsp;Winston.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve added some spooky helmets for you to play the game with as well! Everyone gets them for free. Just look in your Collectables menu and set your&amp;nbsp;head!&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/halloween_gif_4_adjusted.gif" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/halloween_gif_adjusted.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Have fun exploring and&amp;nbsp;destroying.&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="SmithAndWinston"></category><category term="SmithAndWinston"></category></entry><entry><title>Develop: Brighton 2019 Indie Showcase</title><link href="https://www.executionunit.com/blog/2019/06/18/develop-brighton-2019-indie-showcase/" rel="alternate"></link><published>2019-06-18T00:00:00+01:00</published><updated>2019-06-18T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-06-18:/blog/2019/06/18/develop-brighton-2019-indie-showcase/</id><summary type="html">&lt;p&gt;Smith and Winston has been selected as one of 10 games to be showcased at the Develop conference this&amp;nbsp;year!&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.developconference.com/whats-on/indie-showcase"&gt;
    &lt;img alt="Head over heels for Coop" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/developlogo.jpg" /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We are pretty chuffed to announce that Smith and Winston has been selected for the &lt;a href="https://www.developconference.com/whats-on/indie-showcase"&gt;Indie Game Showcase&lt;/a&gt; at Develop: Brighton 2019 here in the &lt;span class="caps"&gt;UK&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Develop is an industry event where developers from all over Europe get together and talk shop. We&amp;#8217;re very surprised and quite elated that Smith and Winston is one of the 10 games that has been selected by an expert panel. We didn&amp;#8217;t even have to bribe them with&amp;nbsp;cake!&lt;/p&gt;
&lt;p&gt;With all ten games being of such a high standard it looks like it&amp;#8217;s gonna be a tough&amp;nbsp;competition.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Head over heels for Coop" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/headheels.gif" /&gt;&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;</content><category term="SmithAndWinston"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #10 - Power Cubes, Shippy, New Levels, More Debris and much more!</title><link href="https://www.executionunit.com/blog/2019/05/23/smith-and-winston-update-10-power-cubes-shippy-new-levels-more-debris-and-much-more/" rel="alternate"></link><published>2019-05-23T00:00:00+01:00</published><updated>2019-05-23T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-05-23:/blog/2019/05/23/smith-and-winston-update-10-power-cubes-shippy-new-levels-more-debris-and-much-more/</id><summary type="html">&lt;p&gt;In this update to Smith and Winston we&amp;#8217;ve added Power Cubes, Shippy, New Levels, More Debris and much&amp;nbsp;more!&lt;/p&gt;</summary><content type="html">&lt;p&gt;Update #10 is up on &lt;a href="https://store.steampowered.com/app/942250/Smith_and_Winston/"&gt;Steam&lt;/a&gt; and &lt;a href="https://executionunit.itch.io/smith-and-winston"&gt;itch.io&lt;/a&gt; &lt;span class="caps"&gt;NOW&lt;/span&gt;! Don&amp;#8217;t delay, buy it or wish list it&amp;#8230; what&amp;#8217;s the worst that could&amp;nbsp;happen!&lt;/p&gt;
&lt;h2 id="new-levels-to-explore"&gt;New levels to&amp;nbsp;explore&lt;/h2&gt;
&lt;h3 id="spynall-tapp"&gt;Spynall&amp;nbsp;Tapp&lt;/h3&gt;
&lt;p&gt;Where the demons dwell if you can find the secret door at&amp;nbsp;least.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Spynall Tapp Level in Smith and Winston" class="img-responsive img-rounded" src="https://www.executionunit.com/static/media/snwblog/spynalltapp.jpg" /&gt;&lt;/p&gt;
&lt;h3 id="asteroid"&gt;Asteroid&lt;/h3&gt;
&lt;p&gt;You&amp;#8217;ve made it to the surface of the Asteroid. The space ship that the &lt;span class="caps"&gt;VOID&lt;/span&gt; used to gather the monoliths to unleash his power&amp;#8230; it&amp;#8217;s a bit weird on the giant&amp;nbsp;cube.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Asteroid Level in Smith and Winston" class="img-responsive img-rounded" src="https://www.executionunit.com/static/media/snwblog/asteroid.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;These are the final two levels before you enter the Asteroid to face the &lt;span class="caps"&gt;VOID&lt;/span&gt;&amp;nbsp;itself.&lt;/p&gt;
&lt;h2 id="escape-from-the-teacher"&gt;Escape from the&amp;nbsp;teacher&lt;/h2&gt;
&lt;p&gt;Listen, we all know that you hate training levels. But we also know that some people need them. So we&amp;#8217;ve added a get out quick door at the beginning. So if you are super l337 hard core haX0r twin stick aficionado then you don&amp;#8217;t need to sit through&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Quick exit from training level" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/leave_training.gif" /&gt;&lt;/p&gt;
&lt;h2 id="its-certain-flowers-that-give-you-coins"&gt;It&amp;#8217;s certain flowers that give you&amp;nbsp;coins.&lt;/h2&gt;
&lt;p&gt;We got an interesting bug report that sometime you picked up a power cube but it didn&amp;#8217;t appear in the &lt;span class="caps"&gt;HUD&lt;/span&gt;. After some digging we realised that it wasn&amp;#8217;t clear that some flowers give you a coin. So now when you get a power cube an icon appears to let you know it&amp;#8217;s a power cube you&amp;#8217;ve collected and not a&amp;nbsp;coin.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Certain flowers give you coins!" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/flowercoins.gif" /&gt;&lt;/p&gt;
&lt;h2 id="power-cubes"&gt;Power&amp;nbsp;Cubes&lt;/h2&gt;
&lt;p&gt;Speaking of power cubes. You collect them to repair shippy, well at least that&amp;#8217;s what she tells you at the beginning of the game. Well now they are needed to power the spinning portal doors. After feedback from &lt;span class="caps"&gt;EGX&lt;/span&gt; we realised that people were just powering through the levels and not taking the time to smell the roses and explore a little. There is a lot to find in all the levels so this is a little hint to chill a bit, destroy a bit more and dig for some &lt;span class="caps"&gt;POWER&lt;/span&gt;!&lt;/p&gt;
&lt;p&gt;The number of power cubes needed is written at the top of the door because  the aliens that inhabit this shattered ring world are all highly organised and probably have a spreadsheet about these sorts of&amp;nbsp;things.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Power Cubes to get through portals" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/powercubes.gif" /&gt;&lt;/p&gt;
&lt;h2 id="sarcastic-shippy"&gt;Sarcastic&amp;nbsp;Shippy&lt;/h2&gt;
&lt;p&gt;When you jumped to a new level Shippy told you some useful information about how many enemies you&amp;#8217;d killed, how many power cubes you got and all that stuff. Well that was far too nice of Shippy so now she tells you sometimes useful information and sometimes sarcastic&amp;nbsp;information.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Good old sarcastic shippy." class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/sarcasticshippyhelp.gif" /&gt;&lt;/p&gt;
&lt;h2 id="bug-fixes-and-tweaks"&gt;Bug Fixes and&amp;nbsp;tweaks.&lt;/h2&gt;
&lt;h3 id="screen-shake-shenanigans"&gt;Screen &lt;span class="caps"&gt;SHAKE&lt;/span&gt;&amp;nbsp;Shenanigans!&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Screen shake is worked out for each co-op player independently so now, just as you were making that difficult boost across a gap, your coop partner can&amp;#8217;t throw a grenade making the whole screen&amp;nbsp;shake.&lt;/li&gt;
&lt;li&gt;If the screen was shaking because, say, a large block was moving, and you threw a grenade&amp;#8230; well all hell broke loose and the screen shook like a wet dog. That&amp;#8217;s fixed&amp;nbsp;now.&lt;/li&gt;
&lt;li&gt;If you&amp;#8217;ve turned off the screen shake then maybe give it another&amp;nbsp;go.&lt;/li&gt;
&lt;li&gt;Better physics on low end&amp;nbsp;machines&lt;/li&gt;
&lt;li&gt;Physics uses more cores if you&amp;#8217;ve got&amp;nbsp;them&lt;/li&gt;
&lt;li&gt;Up debris in options &amp;gt; game &amp;gt;&amp;nbsp;debris&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Increase the number of voxel debris!" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/numvoxels.gif" /&gt;&lt;/p&gt;
&lt;h3 id="faster-loading-and-rendering"&gt;Faster loading and&amp;nbsp;rendering&lt;/h3&gt;
&lt;p&gt;We&amp;#8217;ve sped up the loading of levels a tiny bit by being a bit more clever&amp;#8230; or less dumb. We no longer build the same model thousands of times per level and just do it once. Thank you for recognising my&amp;nbsp;genius.&lt;/p&gt;
&lt;p&gt;Have fun exploring and&amp;nbsp;destroying.&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="SmithAndWinston"></category><category term="SmithAndWinston"></category></entry><entry><title>Notes on vr development</title><link href="https://www.executionunit.com/blog/2019/05/10/notes-on-vr-development/" rel="alternate"></link><published>2019-05-10T00:00:00+01:00</published><updated>2019-05-10T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-05-10:/blog/2019/05/10/notes-on-vr-development/</id><summary type="html"></summary><content type="html">&lt;p&gt;Prompted by &lt;a href="https://www.reddit.com/r/gamedev/comments/bmnleb/how_is_developing_for_vr_different_than_a/"&gt;a question&lt;/a&gt; on reddit&amp;#8217;s gamedev subreddit here is a slightly more fleshed out answer&amp;nbsp;to&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How is developing for &lt;span class="caps"&gt;VR&lt;/span&gt; different than a standard 3D dev&amp;nbsp;cycle?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In 01/2018 we worked on a &lt;span class="caps"&gt;VR&lt;/span&gt; prototype of &lt;a href="http://www.smithandwinston.com"&gt;Smith and Winston&lt;/a&gt;, ultimately we abandoned it because we couldn&amp;#8217;t attract enough investment to take it forward. Here is what we learned, hopefully this is useful to anyone else embarking on a &lt;span class="caps"&gt;VR&lt;/span&gt; project even though this was learned over a year&amp;nbsp;ago.&lt;/p&gt;
&lt;h2 id="interaction"&gt;Interaction&lt;/h2&gt;
&lt;p&gt;One of the first things you&amp;#8217;ll experience in &lt;span class="caps"&gt;VR&lt;/span&gt; is that some types of interaction that are rewarding in a 3D or 2D game are so different that they are completely useless or make you&amp;nbsp;vomit.&lt;/p&gt;
&lt;p&gt;Things that are annoying like &amp;#8220;Press triangle to continue&amp;#8221; are a &lt;span class="caps"&gt;PITA&lt;/span&gt; in the real world and if you can&amp;#8217;t see the controller it&amp;#8217;s impossible to remember where triangle is anyway. The solution of placing the controller in the scene, something we did for Smith and Winston demo, doesn&amp;#8217;t work in all games. Astrobot does this really well by making the controller an integral part of the players&amp;nbsp;experience.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive img-rounded" src="https://www.executionunit.com/static/media/uploads/blog/gamedev_firstexprience_vr_ds4.jpg" alt="Smith and Winston putting the controller in the scene."&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Putting the controller in the scene helps but not&amp;nbsp;always&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The sheer act of looking around in a 3D game is interesting but it can be completely absorbing in a &lt;span class="caps"&gt;VR&lt;/span&gt; game. Even beyond the trivial first contact with &lt;span class="caps"&gt;VR&lt;/span&gt; the act of being in a game is intensely rewarding to the&amp;nbsp;player.&lt;/p&gt;
&lt;p&gt;So if you bring a traditional game, like we did with Smith and Winston, you quickly find a lot of what you&amp;#8217;ve learned, implemented and become accustomed to is no longer&amp;nbsp;useful.&lt;/p&gt;
&lt;h2 id="sound-design"&gt;Sound&amp;nbsp;Design&lt;/h2&gt;
&lt;p&gt;Sound design is the ugly step child in game development. Everyone knows it&amp;#8217;s there but no one pays enough attention to it. In &lt;span class="caps"&gt;VR&lt;/span&gt; the minimum requirements are much much higher. I&amp;#8217;d go as far as to say potentially two to four times more costly for an indie. For the &lt;span class="caps"&gt;AAA&lt;/span&gt; guys, they are already doing full surround sound 7.1 Dolby mega &lt;span class="caps"&gt;THX&lt;/span&gt; tastic stuff that people play out of their crappy &lt;span class="caps"&gt;PC&lt;/span&gt; speakers. For them, the audience may actually hear their lovely work. For indies, you need to step up your&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;In &lt;span class="caps"&gt;VR&lt;/span&gt;, because the players head is &lt;span class="caps"&gt;IN&lt;/span&gt; the game (and thus their ears are in the game) and because nearly all &lt;span class="caps"&gt;VR&lt;/span&gt; is played with headphones, the potential for sound design is much greater but also what is needed is much greater. The player can pinpoint exactly where the sound is coming from relative to them and they will look at the sound&amp;nbsp;source.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive img-rounded" src="https://www.executionunit.com/static/media/uploads/blog/gamedev_firstexprience_vr_chalk.jpg" alt="Smith and Winston Chalk and Flowers Secret Level"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;this image is from the 3D (non vr) version of the&amp;nbsp;game&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In Smith and Winston we had a very low pace puzzle level as a break from the destruction. The sound design for this level is a very light wind, the occasional Cicada chirp and a single bird call (that can play from five or so different locations). That is all that is needed. The player gets it, it&amp;#8217;s&amp;nbsp;restful.&lt;/p&gt;
&lt;p&gt;However in &lt;span class="caps"&gt;VR&lt;/span&gt; the bird call was annoying as you can never see the bird despite being able to locate the invisible sound source pretty well. We&amp;#8217;re all used to not being able to locate the Cicada sound but we expect to be able to see the&amp;nbsp;bird.&lt;/p&gt;
&lt;p&gt;There is so much potential for immersive sound design in &lt;span class="caps"&gt;VR&lt;/span&gt; but there is also so much that can be subtly wrong that disconnects the player from the&amp;nbsp;scene.&lt;/p&gt;
&lt;h2 id="textures-will-all-need-work"&gt;Textures will all need&amp;nbsp;work&lt;/h2&gt;
&lt;p&gt;The actual displays for each eye are very low resolution and the image you send to the headset is very distorted. This tends to exaggerate any slight movement of pixels and noise within textures. The &amp;#8220;small voxel&amp;#8221; art style in Smith and Winston naturally creates a very high frequency image and when distorted the middle distance shimmered and looked terrible. We toned all of our colours down to compensate for this. It&amp;#8217;s basically was not possible to take all of the levels we&amp;#8217;d already designed and just explore them in &lt;span class="caps"&gt;VR&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The level of detail in the scene dramatically affects how the brain reacts to motion. So games like Rez with limited detail can get away with extreme speed/direction change where as doom can make you spew in 30 seconds. It takes a lot of time to find the sweet spot for your game and art&amp;nbsp;style.&lt;/p&gt;
&lt;h2 id="implicit-design"&gt;Implicit&amp;nbsp;design.&lt;/h2&gt;
&lt;p&gt;There are very many things about playing a game that you don&amp;#8217;t need to explicitly tell players. Everyone knows how the analog controllers work for example. In &lt;span class="caps"&gt;VR&lt;/span&gt; those tropes haven&amp;#8217;t been established yet. As time goes by this will be fixed and stand out titles like Astrobot are setting standards for people to follow. We&amp;#8217;re not there yet&amp;nbsp;though.&lt;/p&gt;
&lt;h2 id="captivated"&gt;Captivated&lt;/h2&gt;
&lt;p&gt;In games like Astrobot, Moss and in our demo players are totally captivated by tiny life forms that they can bend over and look at. It&amp;#8217;s a deeply rewarding and weirdly emotional experience for players and it can change your game completely. When the robots in Astrobot look at you it is a very intense experience that cannot be replicated in 3D (nor in movies I would&amp;nbsp;add).&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive img-rounded" src="https://www.executionunit.com/static/media/uploads/blog/gamedev_firstexprience_vr_look.jpg" alt="Smith and Winston looking in a hole"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I couldn&amp;#8217;t find a picture of looking at Smith or Winston but here is a pick up the player&amp;nbsp;uncovered&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="time-challenges"&gt;Time&amp;nbsp;challenges&lt;/h2&gt;
&lt;p&gt;The tweak/test cycle is a &lt;span class="caps"&gt;LOT&lt;/span&gt; longer. It takes time to put the headset on/off and you need to rest your eyes/brain a lot more for &lt;span class="caps"&gt;VR&lt;/span&gt; work. It&amp;#8217;s easy to work too long and get&amp;nbsp;car-sick.&lt;/p&gt;
&lt;h2 id="budgeting"&gt;Budgeting&lt;/h2&gt;
&lt;p&gt;A lot of the recent indie/small studio boom has been enabled by the off the shelf engines. This has dramatically lowered costs and risk. In &lt;span class="caps"&gt;VR&lt;/span&gt; those gains are partially lost. The increased sound design and slower design/tweak/test cycle increase costs and risk. This new risk/cost profile has to be balanced with the smaller market that &lt;span class="caps"&gt;VR&lt;/span&gt; currently offers. Again, over time this will hopefully change as &lt;span class="caps"&gt;VR&lt;/span&gt; grows. A lot of publishers are not willing to take on the increased risks at the moment so the actual designs they will consider are more&amp;nbsp;limited.&lt;/p&gt;
&lt;p&gt;Anyway, hope this helps someone who is researching doing a &lt;span class="caps"&gt;VR&lt;/span&gt;&amp;nbsp;game.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category></entry><entry><title>Smith and Winston - Update #9 - Save the Day</title><link href="https://www.executionunit.com/blog/2019/04/18/smith-and-winston-update-9-save-the-day/" rel="alternate"></link><published>2019-04-18T00:00:00+01:00</published><updated>2019-04-18T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-04-18:/blog/2019/04/18/smith-and-winston-update-9-save-the-day/</id><summary type="html">&lt;p&gt;Small update with Coop Saves, Buddy mode, debris tweaks and more sound&amp;nbsp;design&lt;/p&gt;</summary><content type="html">&lt;h2 id="save-the-coop"&gt;Save the&amp;nbsp;coop&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;ve turned on save games for coop. So now you can officially continue a coop game you&amp;#8217;ve been playing with your&amp;nbsp;buddy.&lt;/p&gt;
&lt;h2 id="coop-rebirth"&gt;Coop&amp;nbsp;rebirth&lt;/h2&gt;
&lt;p&gt;If one of the coop player runs out of lives they will be given a free life with a full shield if you can get to the next level. We&amp;#8217;re prototyping an in-level recovery mechanism where a pick up can recover the lost player. We&amp;#8217;re not sure if the pickup should come from killing, destruction or just add it to the extra life pickup. Any&amp;nbsp;ideas?&lt;/p&gt;
&lt;p&gt;&lt;img alt="Coop Settings" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/coopsettings.gif" /&gt;&lt;/p&gt;
&lt;h2 id="buddy-mode"&gt;Buddy&amp;nbsp;Mode&lt;/h2&gt;
&lt;p&gt;We think this is a big one. In buddy mode player 2 can never be killed and if they fall off of the level they get respawned. We wanted a way to play Smith and Winston with our young kids. Hopefully you&amp;#8217;ll find it useful. It&amp;#8217;s part of our design mantra of always making the player feel&amp;nbsp;powerful.&lt;/p&gt;
&lt;p&gt;There are some really interesting tactics that you can use in buddy mode with your kids or less-gamer-like friends and it&amp;#8217;s fun and that&amp;#8217;s all that really matters in&amp;nbsp;life.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Buddy Mode" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/buddy.gif" /&gt;&lt;/p&gt;
&lt;h2 id="oh-coop-partner-wherefore-art-thou"&gt;Oh coop partner, wherefore art&amp;nbsp;thou!&lt;/h2&gt;
&lt;p&gt;You can turn on a little icon that appears when your coop partner goes offscreen. Yeah the levels can get quite confusing after blowing them to pieces and spinning around for a few minutes&amp;nbsp;:)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Coop Marker" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/whereareyoumarker.gif" /&gt;&lt;/p&gt;
&lt;h2 id="language-update"&gt;Language&amp;nbsp;update&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;ve updated all the German, French and Spanish strings in the game with google-translated strings that match the English. They got out of sync with the &lt;span class="caps"&gt;EGX&lt;/span&gt; Rezzed build.&amp;nbsp;Sorry.&lt;/p&gt;
&lt;h2 id="no-more-clever-adjust-the-slider"&gt;No more clever, adjust the&amp;nbsp;slider&lt;/h2&gt;
&lt;p&gt;We tried to be clever and add a dynamic debris load balancing system and it didn&amp;#8217;t work. The code tried to monitor how long the &lt;span class="caps"&gt;CPU&lt;/span&gt; took to calculate all the debris physics and adjust the amount of debris on screen in a super clever way. Well it turns out it was bloody rubbish! So now there is a slider in options &amp;gt; game that you can slide up or down to increase and decrease the amound of debris. It&amp;#8217;s stupid, but it&amp;nbsp;works.&lt;/p&gt;
&lt;p&gt;&lt;img alt="More Debris" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/moredebris.gif" /&gt;&lt;/p&gt;
&lt;h2 id="shippy"&gt;Shippy&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;ve added some more sarcastic shippy comments through out the levels because she&amp;#8217;s funny and we like adding sarcastic messages when we get a few&amp;nbsp;minutes.&lt;/p&gt;
&lt;p&gt;Have fun exploring and&amp;nbsp;destroying.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="SmithAndWinston"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #8 - Cooperation for all</title><link href="https://www.executionunit.com/blog/2019/04/10/smith-and-winston-update-8-cooperation-for-all/" rel="alternate"></link><published>2019-04-10T00:00:00+01:00</published><updated>2019-04-10T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-04-10:/blog/2019/04/10/smith-and-winston-update-8-cooperation-for-all/</id><summary type="html">&lt;p&gt;This update includes a whole host of fixes, coop mode and better&amp;nbsp;explosions!&lt;/p&gt;</summary><content type="html">&lt;h2 id="shattering"&gt;Shattering&lt;/h2&gt;
&lt;p&gt;For a long time we&amp;#8217;ve had the world blowing up in to tiny voxels. This has been very satisfying for everyone. We&amp;#8217;ve made it even more satisfying now by creating big chunks of floor and walls from the world when you blow it&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Chunky debris coming off a building" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/debris.gif" /&gt;&lt;/p&gt;
&lt;h2 id="tree-collapse"&gt;Tree&amp;nbsp;Collapse&lt;/h2&gt;
&lt;p&gt;Cutting the bottom out of a tree is one of the first things that players do. When it  doesn&amp;#8217;t fall a lot of players feel cheated. So now the tree will fall down shattering in to bits in the process. This is oh.. so&amp;#8230; good&amp;nbsp;:)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Chopping down trees" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/deforest.gif" /&gt;&lt;/p&gt;
&lt;h2 id="head-over-heels-for-coop"&gt;Head over Heels for&amp;nbsp;Coop.&lt;/h2&gt;
&lt;p&gt;We recently showed Smith and Winston at &lt;span class="caps"&gt;EGX&lt;/span&gt; Rezzed in London. Coop mode went down a complete storm. &amp;#8220;Best Game of the Show&amp;#8221;, &amp;#8220;So satisfying&amp;#8221; were just two of the many comments we got from all different types of gamers and we&amp;#8217;re still beaming from hearing all the kind&amp;nbsp;words.&lt;/p&gt;
&lt;p&gt;Coop mode isn&amp;#8217;t complete and there are still a few issues but it&amp;#8217;s so much fun we want everyone to join in with a friend and blow some stuff&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;One notable ommision is that we haven&amp;#8217;t got save games working and when a player dies there is no way to revive them just yet but fixes for those are coming&amp;nbsp;soon.&lt;/p&gt;
&lt;p&gt;Dig&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Head over heels for Coop" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/headheels.gif" /&gt;&lt;/p&gt;
&lt;h2 id="better-debris"&gt;Better&amp;nbsp;Debris&lt;/h2&gt;
&lt;p&gt;One of the challenges with Smith and Winston is managing all the tiny cubes that fly around. They are relatively expensive to draw (for what they are) and they are very expensive to do the collision for but oh they are so&amp;nbsp;satisfying.&lt;/p&gt;
&lt;p&gt;So in this update we&amp;#8217;ve added a more flexible system where if they are getting too expensive we remove them from the scene more quickly keeping the framerate up for all players and allowing players with monster machines to get even more&amp;nbsp;debris!&lt;/p&gt;
&lt;p&gt;This is especially useful in coop where people seem to spend most of their time mining out the floor from under their &amp;#8216;coop partner&amp;#8217;&amp;nbsp;:)&lt;/p&gt;
&lt;h2 id="mining-freeze"&gt;Mining&amp;nbsp;freeze&lt;/h2&gt;
&lt;p&gt;At the &lt;span class="caps"&gt;EGX&lt;/span&gt; rezzed show we learned that a lot of users were just using the mining laser to shoot everything, the world and the enemies. This is cool but when someone said &amp;#8220;I don&amp;#8217;t think you should give the player a shotgun from the beginning!&amp;#8221; we realised that we&amp;#8217;d got the mining laser all&amp;nbsp;wrong.&lt;/p&gt;
&lt;p&gt;So for mining the laser hasn&amp;#8217;t changed at all but now it freezes enemies it hits for a second or so giving the player time to change weapon. Give it a go and see what you&amp;nbsp;think.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Mining laser freezes enemies" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/freezer.gif" /&gt;&lt;/p&gt;
&lt;h2 id="quicker-level-restores"&gt;Quicker level&amp;nbsp;restores&lt;/h2&gt;
&lt;p&gt;With all this new destruction we started to notice that when the player died and we have to revert the level back to it&amp;#8217;s original state it was taking too long. This has been even more optimized now so it doesn&amp;#8217;t get in the way of your&amp;nbsp;fun.&lt;/p&gt;
&lt;h2 id="new-title-page-and-new-intro-movie"&gt;New title page and new intro&amp;nbsp;movie&lt;/h2&gt;
&lt;p&gt;No one likes a long boring intro movie but we&amp;#8217;ve made one just to annoy you even more. Trust me it&amp;#8217;s very short, gives you an insight in to Shippy and why she&amp;#8217;s a little mad and hopefully as we finish up the single player mode you&amp;#8217;ll enjoy her more as a character. We&amp;#8217;re working really hard to making her a richer and more rewarding part of the&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;We changed the title page just because it so cool to see Shippy in&amp;nbsp;space!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Shippy in space!" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/shippyspace.gif" /&gt;&lt;/p&gt;
&lt;h2 id="thanks-to-all-our-supporters"&gt;Thanks to all our&amp;nbsp;supporters&lt;/h2&gt;
&lt;p&gt;Lastly but definitely not leastly we&amp;#8217;d like to say thanks to all that have bought the game and supported us. We are just two guys making a game. It&amp;#8217;s completely self funded, we don&amp;#8217;t have a wealthy backer or publisher and sometimes we need to take on contract work to pay the bills. It&amp;#8217;s really frustrating but that&amp;#8217;s life. Once again, thanks for your patience and&amp;nbsp;kindness.&lt;/p&gt;
&lt;h2 id="tweaks"&gt;Tweaks&lt;/h2&gt;
&lt;p&gt;A lot of small things that players have asked&amp;nbsp;for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Disable &lt;span class="caps"&gt;ALT&lt;/span&gt;-F4 from killing the&amp;nbsp;game.&lt;/li&gt;
&lt;li&gt;Better controller detection and actions when unplugged/plugged&amp;nbsp;in&lt;/li&gt;
&lt;li&gt;Correct controller names in the &lt;span class="caps"&gt;HUD&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Enemy shots are more controlled, sometimes they fired at weird angles which&amp;nbsp;sucked&lt;/li&gt;
&lt;li&gt;Turn on/off Depth of Field (video&amp;nbsp;menu)&lt;/li&gt;
&lt;li&gt;Turn on/off Shadows (video&amp;nbsp;menu)&lt;/li&gt;
&lt;li&gt;Turn on/off Bloom (video&amp;nbsp;menu)&lt;/li&gt;
&lt;li&gt;Enable/Disable screen saver kicking in (video&amp;nbsp;menu)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks for reading all this, I&amp;#8217;d forgotten we&amp;#8217;d done half of this stuff. The next update hopefully won&amp;#8217;t take so long to get&amp;nbsp;out.&lt;/p&gt;
&lt;p&gt;Have fun exploring and&amp;nbsp;destroying.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="SmithAndWinston"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Play Smith and Winston CoOp at Rezzed 2019</title><link href="https://www.executionunit.com/blog/2019/03/30/smith-and-winston-play-smith-and-winston-coop-at-rezzed-2019/" rel="alternate"></link><published>2019-03-30T00:00:00+00:00</published><updated>2019-03-30T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-03-30:/blog/2019/03/30/smith-and-winston-play-smith-and-winston-coop-at-rezzed-2019/</id><summary type="html">&lt;p&gt;See you&amp;nbsp;there!&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you&amp;#8217;re coming along to &lt;a href="https://www.egx.net/rezzed"&gt;Rezzed 2019&lt;/a&gt; then stop by our booth and give &lt;a href="https://www.egx.net/rezzed/news/smith-and-winston-will-be-playable-at-egx-rezzed"&gt;Smith and Winston a play&lt;/a&gt; and chat to us. Both Charlie and I will be there in our exclusive Smith and Winston tshirts so we won&amp;#8217;t be hard to&amp;nbsp;miss.&lt;/p&gt;
&lt;h2 id="exclusive-coop"&gt;Exclusive&amp;nbsp;Coop&lt;/h2&gt;
&lt;p&gt;Coop is still a bit buggy but we&amp;#8217;re enabling it for this special event. As we&amp;#8217;ll be there we&amp;#8217;ll be able to tell you what&amp;#8217;s gone wrong and apologise&amp;nbsp;:)&lt;/p&gt;
&lt;h2 id="exclusive-free-voxel"&gt;Exclusive Free&amp;nbsp;Voxel&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;re giving away exclusive voxels that have travelled from the far side of the asteroid. In our dimension they appear to be flattened but can be folded and glued back in to &amp;#8220;three&amp;#8221; dimensions for us to view&amp;nbsp;;)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Smith and Winston TShirt" class="img-responsive img-rounded" src="https://www.executionunit.com/static/media/snwblog/rezzed_voxel.jpg" /&gt;&lt;/p&gt;
&lt;h2 id="boob-shot"&gt;Boob&amp;nbsp;shot!&lt;/h2&gt;
&lt;p&gt;Charlie and I will be wearing these exlusive tshirts so we are easy to find. We&amp;#8217;re pretty happy how they turned out in the end. Our names are across our bums as our names and big like our&amp;nbsp;bums.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Smith and Winston TShirt" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/snw_tee1.jpg" /&gt;
&lt;img alt="Smith and Winston TShirt" class="img-rounded" src="https://www.executionunit.com/static/media/snwblog/snw_tee2.jpg" /&gt;&lt;/p&gt;
&lt;h2 id="a-preview-of-our-stand"&gt;A preview of our&amp;nbsp;stand&lt;/h2&gt;
&lt;p&gt;The booth will also have a massive Smith and Winston logo over it as well so&amp;#8230; yeah you won&amp;#8217;t be able to miss&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Smith and Winston Stand artwork" class="img-responsive img-rounded" src="https://www.executionunit.com/static/media/snwblog/rezzed_stand.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Hope to see you there. There are &lt;a href="https://www.egx.net/rezzed/2019/show-floor"&gt;lots of indies and mainstream games&lt;/a&gt; to play at Rezzed&amp;#8230; but the indies are the&amp;nbsp;best!&lt;/p&gt;</content><category term="SmithAndWinston"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #6 - New Levels, Shield is Live and a Rejig.</title><link href="https://www.executionunit.com/blog/2019/03/06/smith-and-winston-update-6-new-levels-shield-is-live-and-a-rejig/" rel="alternate"></link><published>2019-03-06T00:00:00+00:00</published><updated>2019-03-06T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-03-06:/blog/2019/03/06/smith-and-winston-update-6-new-levels-shield-is-live-and-a-rejig/</id><summary type="html"></summary><content type="html">&lt;h2 id="story-and-arcade-merged"&gt;Story and Arcade&amp;nbsp;Merged&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;ve been following along you&amp;#8217;ll know that originally there were two game modes: Story and Arcade. With the introduction of the shield (see below) and thus the removal of one shot death these two modes seems a waste of time. So they are merged. The downside of this is that everyone&amp;#8217;s saves games are now invalid so, unfortunately, everyone has been kicked back to boot camp and has to start the mission again. The good news is that the mission is much clearer, much more balanced and starts a lot easier because of the&amp;nbsp;shield.&lt;/p&gt;
&lt;h2 id="introductory-offer"&gt;Introductory&amp;nbsp;Offer&lt;/h2&gt;
&lt;p&gt;Lets be honest no one really &lt;em&gt;likes&lt;/em&gt; a cut scene but they are sometimes necessary. We found that people were asking questions&amp;nbsp;like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who are Smith and&amp;nbsp;Winston?&lt;/li&gt;
&lt;li&gt;Am I playing as Smith or&amp;nbsp;Winston?&lt;/li&gt;
&lt;li&gt;Why is shippy such an&amp;nbsp;asshat?&lt;/li&gt;
&lt;li&gt;Is shippy the&amp;nbsp;ship?&lt;/li&gt;
&lt;li&gt;How many potatoes are there is each&amp;nbsp;voxel?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So when you start a new game you get to see a little 30 second intro sequence which helps to set the scene a&amp;nbsp;little.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/intro.gif" /&gt;&lt;/p&gt;
&lt;h2 id="training"&gt;Training&lt;/h2&gt;
&lt;p&gt;The cut scene plops you in to a little training area now where you can learn the controls. We&amp;#8217;ve removed most of the introduction Shippy Beacons from the start of the game now. A lot of players just ignored them and Shippy&amp;#8217;s voice was just too&amp;nbsp;annoying&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/holo_cake.gif" /&gt;&lt;/p&gt;
&lt;h2 id="calm-down-shippy"&gt;Calm down&amp;nbsp;Shippy!&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;ve re-synthesized Shippy so she&amp;#8217;s &lt;span class="caps"&gt;FAR&lt;/span&gt; less annoying to the players ears, especially when wearing headphones. So if you&amp;#8217;ve turned down the shippy volume&amp;#8230; you may want to turn it back up for a&amp;nbsp;bit.&lt;/p&gt;
&lt;h2 id="shiela-sha-poo-pee-shields"&gt;Shiela Sha-poo-pee&amp;nbsp;Shields&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/shield_1.gif" /&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#8217;ve added a shield. This means you can take three hits before losing a life. This makes a &lt;strong&gt;huge&lt;/strong&gt; difference to the game. It&amp;#8217;s amazing. We said we&amp;#8217;d never do it but in the end, the players were correct, the game is better with a&amp;nbsp;shield.&lt;/p&gt;
&lt;h2 id="bossing-the-boss-around"&gt;Bossing the Boss&amp;nbsp;around&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/chopperreveal.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Based on the feedback we got about the Chopper Boss we&amp;#8217;ve moved him to be the first boss that you see. It&amp;#8217;s a better boss, it plays better than bunker boss and this gives us a chance to revisit the Bunker Boss and make him&amp;nbsp;better.&lt;/p&gt;
&lt;h2 id="new-levels"&gt;New&amp;nbsp;Levels&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;ve added three new levels to the game&amp;#8230; each with distinct eeriness, distinct enemies and one of them is based on my personal addiction to Paprika Pringles.. but it&amp;#8217;s probably not clear&amp;nbsp;which.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/2_4.gif" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/5_1.gif" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/5_2.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;#8217;s it for now. We&amp;#8217;re going to get a build ready for &lt;a href="https://www.egx.net/rezzed"&gt;&lt;span class="caps"&gt;EGX&lt;/span&gt; Rezzed in London&lt;/a&gt; 4th-6th of April, 2019. If you&amp;#8217;re around be sure to drop by and say&amp;nbsp;hi.&lt;/p&gt;
&lt;p&gt;Have fun exploring and&amp;nbsp;destroying.&lt;/p&gt;
&lt;p&gt;be seeing&amp;nbsp;you&lt;/p&gt;
&lt;p&gt;dazza.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #5 - Holodeck Lessons</title><link href="https://www.executionunit.com/blog/2019/02/22/smith-and-winston-update-5-holodeck-lessons/" rel="alternate"></link><published>2019-02-22T00:00:00+00:00</published><updated>2019-02-22T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-02-22:/blog/2019/02/22/smith-and-winston-update-5-holodeck-lessons/</id><summary type="html">&lt;p&gt;Another quick update with some bug fixes and a new &lt;span class="caps"&gt;BETA&lt;/span&gt; area for your&amp;nbsp;feedback.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Another quick update with some bug fixes and a new &lt;span class="caps"&gt;BETA&lt;/span&gt; area for your&amp;nbsp;feedback.&lt;/p&gt;
&lt;h2 id="hollow-holo"&gt;Hollow&amp;nbsp;Holo&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/holo_intro.gif" /&gt;&lt;/p&gt;
&lt;p&gt;We hear you and agree we&amp;#8217;re really not happy with the way we use Shippy to teach the player how to play Smith and Winston. It&amp;#8217;s boring and annoying. Training areas in games are always hard tbh so we&amp;#8217;re having another go at&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;As part of a brand new intro sequence the player will be sent, by shippy, to a holodeck training area to learn the buttons and get a feel for controlling Smith and Winston before getting stuck&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/holo_beta.gif" /&gt;&lt;/p&gt;
&lt;p&gt;The shippy text is all provisional and untranslated and we&amp;#8217;ve not added Shippy&amp;#8217;s patented rudeness or voice&amp;nbsp;yet&lt;/p&gt;
&lt;p&gt;What do you think? Is it a better way to introduce the game? Please give feed back in the discussion area on &lt;a href="https://steamcommunity.com//app/942250/"&gt;Steam&lt;/a&gt; or &lt;a href="https://executionunit.itch.io/smith-and-winston/community"&gt;itch.io&lt;/a&gt;. More feedback on the Chopper boss is very much appreciated as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/holo_cake.gif" /&gt;&lt;/p&gt;
&lt;p&gt;After this the player will see a little cut scene explaining how the ship crashes and then they are straight in to playing the &amp;#8220;second&amp;#8221; level &amp;#8220;Sunshine and&amp;nbsp;Showers&amp;#8221;&lt;/p&gt;
&lt;h2 id="bug-fixes"&gt;Bug&amp;nbsp;Fixes&lt;/h2&gt;
&lt;h3 id="toilet-sound"&gt;Toilet&amp;nbsp;Sound&lt;/h3&gt;
&lt;p&gt;If you happened to die in a bit of the game with reverb turned on (echoy sound effects etc.) then you were stuck playing the rest of the game like you were in a toilet. Should be fixed&amp;nbsp;now.&lt;/p&gt;
&lt;h3 id="white-so-white"&gt;White&amp;#8230;. so&amp;nbsp;white&lt;/h3&gt;
&lt;p&gt;Some textures didn&amp;#8217;t render correctly in OpenGL on any platform. This was because we were blending two texture together one of which didn&amp;#8217;t exist&amp;#8230; yeah, that&amp;#8217;s fixed now as well&amp;#8230;&amp;nbsp;oops.&lt;/p&gt;
&lt;h2 id="less-chatter-more-batter"&gt;Less chatter, more&amp;nbsp;batter&lt;/h2&gt;
&lt;p&gt;That&amp;#8217;s it, have a great weekend, Explore and Destroy and if you&amp;#8217;ve got a bit of spare time jump in the discussion area of Steam or itch and tell us what you think of the holodeck, chopper boss or anything else about the&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;be seeing&amp;nbsp;you&lt;/p&gt;
&lt;p&gt;dazza.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #4</title><link href="https://www.executionunit.com/blog/2019/02/17/smith-and-winston-update-4/" rel="alternate"></link><published>2019-02-17T00:00:00+00:00</published><updated>2019-02-17T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-02-17:/blog/2019/02/17/smith-and-winston-update-4/</id><summary type="html">&lt;p&gt;We&amp;#8217;ve released a new update to Smith and Wintston! This is mainly a metric ton of tweaks to the first half of the game to make it more balanced and more fun to play. Thanks to everyone that gave us feedback and helped make the game even&amp;nbsp;better.&lt;/p&gt;</summary><content type="html">&lt;p&gt;We&amp;#8217;ve released a new update to Smith and Wintston! This is mainly a metric ton of tweaks to the first half of the game to make it more balanced and more fun to play. Thanks to everyone that gave us feedback and helped make the game even&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/chopperreveal.gif" /&gt;&lt;/p&gt;
&lt;h2 id="features"&gt;Features:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Added in the Chopper boss. This is the middle boss in the game. He’s pretty epic (testable via the new &lt;span class="caps"&gt;BETA&lt;/span&gt; &lt;span class="caps"&gt;TEST&lt;/span&gt;&amp;nbsp;menu)&lt;/li&gt;
&lt;li&gt;Added a &lt;span class="caps"&gt;BETA&lt;/span&gt; &lt;span class="caps"&gt;TEST&lt;/span&gt; menu so player can test specific features of the game and give us feedback without destroying their Arcade Save games. We’ll be adding things to this menu and asking for feedback a lot we&amp;nbsp;think.&lt;/li&gt;
&lt;li&gt;Added a button for twitter and facebook in the title&amp;nbsp;screen&lt;/li&gt;
&lt;li&gt;Tweaking/Balancing of lives and ammo based on player feedback and streamer&amp;nbsp;videos&lt;/li&gt;
&lt;li&gt;Added disabled story and coop buttons to the main menu so players know they will be there activated at some point&amp;nbsp;:)&lt;/li&gt;
&lt;li&gt;After the player dies in a level specific enemies don’t restore so it becomes ‘slightly’ easier to finish the level. The cost to the player is that they will get a slightly lower score because there are less enemies to&amp;nbsp;kill.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="beta-test"&gt;Beta&amp;nbsp;Test&lt;/h2&gt;
&lt;p&gt;You can jump straight to the Chopper Boss from the new Beta Test menu option. You can test the boss and give us feedback without affecting your Arcade Save game. We&amp;#8217;d love to hear from all players&amp;nbsp;ːsteamhappyː&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/beta_chopper.gif" /&gt;&lt;/p&gt;
&lt;h2 id="engine-changes"&gt;Engine&amp;nbsp;Changes:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Upgraded &lt;span class="caps"&gt;BGFX&lt;/span&gt; rendering code. At least 10% faster on all&amp;nbsp;platforms.&lt;/li&gt;
&lt;li&gt;Added Metal rendering engine for macOS (8x faster than&amp;nbsp;OpenGL)&lt;/li&gt;
&lt;li&gt;Added OpenGL rendering engine for&amp;nbsp;Windows&lt;/li&gt;
&lt;li&gt;macOS and Windows can select the rendering engine to use in Options &amp;gt;&amp;nbsp;Video&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/pickrenderer.gif" /&gt;&lt;/p&gt;
&lt;h2 id="bug-fixes"&gt;Bug&amp;nbsp;Fixes:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fix for some of the trophies not being&amp;nbsp;present&lt;/li&gt;
&lt;li&gt;Skip cutscene text is now correct for controller, &lt;span class="caps"&gt;KB&lt;/span&gt;/Mouse&amp;nbsp;users.&lt;/li&gt;
&lt;li&gt;Ping Game Boy helmet renamed to the correct Pink Game&amp;nbsp;Boi&lt;/li&gt;
&lt;li&gt;Chopper based enemies can now be hit by&amp;nbsp;grenades&lt;/li&gt;
&lt;li&gt;Mining Laser now shoots from closer to the player so that when right up against the wall it actually hits it. This makes running through the caves and mines a lot&amp;nbsp;easier.&lt;/li&gt;
&lt;li&gt;In some levels the player plows through snow or mud, after they died this stopped working, this is&amp;nbsp;fixed.&lt;/li&gt;
&lt;li&gt;Some GameObject (enemies, pickups etc) were not restoring after player&amp;nbsp;death&lt;/li&gt;
&lt;li&gt;long german and spanish phrases should now in to text&amp;nbsp;boxes&lt;/li&gt;
&lt;li&gt;custom in game cursors appear in front of the shippy&amp;nbsp;text.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once again,  thanks to everyone that&amp;#8217;s played the game and given us bug reports and feedbacl. It&amp;#8217;s really means the world to us so jump in to the forum and tell us what you&amp;nbsp;think!&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #3 Patch 2</title><link href="https://www.executionunit.com/blog/2019/01/22/smith-and-winston-update-3-patch-2/" rel="alternate"></link><published>2019-01-22T00:00:00+00:00</published><updated>2019-01-22T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-01-22:/blog/2019/01/22/smith-and-winston-update-3-patch-2/</id><summary type="html">&lt;p&gt;More fixes to the update 3&amp;nbsp;release.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today we released a &lt;span class="caps"&gt;32MB&lt;/span&gt; patch to Smith and Winston on &lt;a href="https://executionunit.itch.io/smith-and-winston"&gt;itch.io&lt;/a&gt; and &lt;a href="https://store.steampowered.com/app/942250/Smith_and_Winston"&gt;Steam&lt;/a&gt; fixing a few small issues, adding a few little things and tweaking the game&amp;nbsp;play.&lt;/p&gt;
&lt;h3 id="new-features"&gt;New&amp;nbsp;Features:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Camera shake can be adjusted in Options &amp;gt; Game &amp;gt; Camera&amp;nbsp;Shake&lt;/li&gt;
&lt;li&gt;Controller rumble can be adjusted in Options &amp;gt; Game &amp;gt;&amp;nbsp;Rumble&lt;/li&gt;
&lt;li&gt;Added three custom mouse cursors for &lt;span class="caps"&gt;KB&lt;/span&gt;/Mouse players, see Options &amp;gt; Controls &amp;gt;&amp;nbsp;Mouse.&lt;/li&gt;
&lt;li&gt;Added a languages menu on Option where you can select the temporary translations for Spanish, German and French or the default&amp;nbsp;English.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tweaks-to-the-game"&gt;Tweaks to the&amp;nbsp;game:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Added a glow to in game switches to make them a bit more&amp;nbsp;obvious.&lt;/li&gt;
&lt;li&gt;Added a flashing light to Shippy beacons so you can ignore them even more&amp;nbsp;:)&lt;/li&gt;
&lt;li&gt;Lava wasps now get killed by the exploding Lava&amp;nbsp;eggs.&lt;/li&gt;
&lt;li&gt;Spiders can be killed with&amp;nbsp;grenades.&lt;/li&gt;
&lt;li&gt;Dashing makes you invulnerable to explosions as well as bullets (while you are blue). So you can dash through&amp;nbsp;spiders.&lt;/li&gt;
&lt;li&gt;Some more sound design done in the Swamp of the&amp;nbsp;Reanimated.&lt;/li&gt;
&lt;li&gt;Added in more collectable helmets ( they have all now been placed in the game though some of them are on levels not yet&amp;nbsp;released).&lt;/li&gt;
&lt;li&gt;Balanced pick up and weapon distribution e.g all main levels should have at least 2 lives in&amp;nbsp;them.&lt;/li&gt;
&lt;li&gt;Added some more air pick ups, the number of these dropped off quite quickly as you progressed through the levels, there should now be a few more to test your&amp;nbsp;dexterity.&lt;/li&gt;
&lt;li&gt;Small voxel changes to the levels, e.g. fixing voxels that the player was getting caught up&amp;nbsp;on.&lt;/li&gt;
&lt;li&gt;Fixed lighting issues in Swamp of the Reanimated. Happened when the player went back through some of the&amp;nbsp;portals.&lt;/li&gt;
&lt;li&gt;Made some of the hidden portals a little easier to&amp;nbsp;spot.&lt;/li&gt;
&lt;li&gt;Labyrinth secret level is now a lot more forgiving and a wrong portal returns you to the same part of the level rather than the previous bit. Also the portal to the level exit has been differentiated from the other&amp;nbsp;ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bug-fixes"&gt;Bug&amp;nbsp;Fixes:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;more robust loading of corrupt save&amp;nbsp;games.&lt;/li&gt;
&lt;li&gt;no longer hide the cursor when playing with a Controller. This leads to annoying issues for users when like to use the mouse to tweak options with the mouse but play the game with a&amp;nbsp;Controller.&lt;/li&gt;
&lt;li&gt;When using the menus, pressing back selects the menu you&amp;#8217;ve just come from to make menu navigation more&amp;nbsp;clear.&lt;/li&gt;
&lt;li&gt;Menu sliders now scale better for small resolutions&amp;nbsp;(1024x768).&lt;/li&gt;
&lt;li&gt;When setting a controller action to use the &amp;#8216;B&amp;#8217;/Circle button (which is also menu back) set the option but do not go back to the previous&amp;nbsp;menu.&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;KB&lt;/span&gt;/Mouse shooting is now more accurate, the players gun now faces the mouse position not the&amp;nbsp;player.&lt;/li&gt;
&lt;li&gt;Fix for &lt;span class="caps"&gt;PSX&lt;/span&gt; controller Circle not appearing in Shippy dialog&amp;nbsp;boxes&lt;/li&gt;
&lt;li&gt;Linux, using a non-English locale no longer stops levels loading and doesn&amp;#8217;t create corrupt userprefs files (thanks Stephan)&amp;nbsp;*&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="known-issues"&gt;Known&amp;nbsp;Issues:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;long German and Spanish phrases don&amp;#8217;t fit in to text&amp;nbsp;boxes.&lt;/li&gt;
&lt;li&gt;custom in game cursors appear behind the shippy&amp;nbsp;text.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy Exploring and&amp;nbsp;Destroying&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/face_icons_dazza.jpg" /&gt;&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="SmithAndWinston"></category></entry><entry><title>itch.io Desktop App on Fedora 29</title><link href="https://www.executionunit.com/blog/2019/01/19/itchio-desktop-app-on-fedora-29/" rel="alternate"></link><published>2019-01-19T00:00:00+00:00</published><updated>2019-01-19T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-01-19:/blog/2019/01/19/itchio-desktop-app-on-fedora-29/</id><summary type="html">&lt;p&gt;I just tried to get the itch.io desktop app running on a fresh &lt;span class="caps"&gt;VM&lt;/span&gt; of Fedora 29. I used the &lt;code&gt;Fedora-Workstation-x86-64-29-1.2.iso&lt;/code&gt; and then ran an update to get a few&amp;nbsp;patches.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img style="float:left; margin: 1em;" src="/static/media/icons/itch.png"&gt;&lt;/p&gt;
&lt;p&gt;I just tried to get the itch.io desktop app running on a fresh &lt;span class="caps"&gt;VM&lt;/span&gt; of Fedora 29. I used the &lt;code&gt;Fedora-Workstation-x86-64-29-1.2.iso&lt;/code&gt; and then ran an update to get a few&amp;nbsp;patches.&lt;/p&gt;
&lt;p&gt;Unfortunately when I downloaded the excellent itch.io app from &lt;a href="https://itch.io/app"&gt;itch.io&lt;/a&gt; and installed&amp;nbsp;it&lt;/p&gt;
&lt;div class="clearfix"&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;+x&lt;span class="w"&gt; &lt;/span&gt;~/Download/itch-setup&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/Download/itch-setup
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;it then just refused to run&amp;#8230; as in nothing&amp;nbsp;happened.&lt;/p&gt;
&lt;p&gt;Digging a little further itch installs itself in&amp;nbsp;to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;.itch/app-24.5.0/itch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;: the version number is likely to change as itch updates it&amp;#8217;s app very&amp;nbsp;regularly.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;running from the command line it became clear what was&amp;nbsp;wrong:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;.itch/app-25.4.0/itch:&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;loading&lt;span class="w"&gt; &lt;/span&gt;shared&lt;span class="w"&gt; &lt;/span&gt;libraries:&lt;span class="w"&gt; &lt;/span&gt;libXss.so.1:&lt;span class="w"&gt; &lt;/span&gt;cannot&lt;span class="w"&gt; &lt;/span&gt;open&lt;span class="w"&gt; &lt;/span&gt;shared&lt;span class="w"&gt; &lt;/span&gt;object&lt;span class="w"&gt; &lt;/span&gt;file:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;such&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;directory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So libXss is missing, should be easy to install, I wonder what it is? X Screen Saver&amp;#8230; oh, &lt;span class="caps"&gt;OK&lt;/span&gt;!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;yum&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;Xss
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;fixes the issue and now you can download and run &lt;a href="http://www.smithandwinston.com"&gt;Smith and&amp;nbsp;Winston&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope that helps someone out&amp;nbsp;there!&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/face_icons_dazza.jpg" /&gt;&lt;/p&gt;</content><category term="misc"></category><category term="Linux"></category></entry><entry><title>Smith and Winston - Update #3 Patch 1</title><link href="https://www.executionunit.com/blog/2019/01/14/smith-and-winston-update-3-patch-1/" rel="alternate"></link><published>2019-01-14T00:00:00+00:00</published><updated>2019-01-14T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-01-14:/blog/2019/01/14/smith-and-winston-update-3-patch-1/</id><summary type="html">&lt;p&gt;Bunch of small fixes after feed back from&amp;nbsp;players.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today we released a 4.&lt;span class="caps"&gt;3MB&lt;/span&gt; patch to Smith and Winston on &lt;a href="https://executionunit.itch.io/smith-and-winston"&gt;itch.io&lt;/a&gt; and &lt;a href="https://store.steampowered.com/app/942250/Smith_and_Winston"&gt;Steam&lt;/a&gt; fixing a few small issues that have been reported by players and one we noticed in a Twitch&amp;nbsp;steam.&lt;/p&gt;
&lt;h3 id="hot-low-end-action"&gt;Hot low end&amp;nbsp;action&lt;/h3&gt;
&lt;p&gt;On lower end machines players are having to turn down the amount of debris. &lt;strong&gt;&lt;span class="caps"&gt;THIS&lt;/span&gt; &lt;span class="caps"&gt;IS&lt;/span&gt; &lt;span class="caps"&gt;NOT&lt;/span&gt; &lt;span class="caps"&gt;ACCEPTABLE&lt;/span&gt;&lt;/strong&gt;. So we&amp;#8217;ve tweaked the physics a bit to get some more juice from your &lt;span class="caps"&gt;CPU&lt;/span&gt; and get some more debris on screen at 60&amp;nbsp;fps.&lt;/p&gt;
&lt;h3 id="keeping-your-head"&gt;Keeping your&amp;nbsp;head!&lt;/h3&gt;
&lt;p&gt;Because we are idiots we didn&amp;#8217;t think about heads properly. So if you collected one of the hidden Collectable heads in the game you could never switch back to a standard Smith or Winston head. Well now you&amp;nbsp;can.&lt;/p&gt;
&lt;h3 id="more-text-or-space-for-it"&gt;More text&amp;#8230; or space for&amp;nbsp;it&lt;/h3&gt;
&lt;p&gt;Some of the shippy text when you&amp;#8217;re at the crash site didn&amp;#8217;t fit in the little shippy box. We know no one is going to read this text but we really want you to be able to ignore all of it properly, in it&amp;#8217;s entirety with&amp;nbsp;aplomb.&lt;/p&gt;
&lt;h3 id="no-dead-flying"&gt;No dead&amp;nbsp;flying!&lt;/h3&gt;
&lt;p&gt;When you were lying flat on your back, shot, wondering why you even started exploring this cursed ring world of &lt;span class="caps"&gt;DOOM&lt;/span&gt; you could press the boost button and fly up. This wasn&amp;#8217;t very useful to you and in many ways it was quite funny but &lt;span class="caps"&gt;NO&lt;/span&gt;&amp;#8230; &lt;span class="caps"&gt;STOP&lt;/span&gt; &lt;span class="caps"&gt;IT&lt;/span&gt;&amp;#8230;. you&amp;#8217;re dead&amp;nbsp;;)&lt;/p&gt;
&lt;h3 id="no-more-equality"&gt;No more&amp;nbsp;equality&lt;/h3&gt;
&lt;p&gt;If you pressed the equals key (&amp;#8216;=&amp;#8217;) you seemed to randomly warp around the level&amp;#8230; even to places that you can&amp;#8217;t get to normally. We use this debug feature to quickly test new areas of the level and you were never supposed to have such powers because we just can&amp;#8217;t trust any of you naughty people can we? Look out for this feature accidentally being re-enabled because &amp;#8220;we are idiots&amp;#8221;&amp;nbsp;;).&lt;/p&gt;
&lt;h3 id="no-more-home"&gt;No more &lt;span class="caps"&gt;HOME&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Another oversight was that pressing the &lt;span class="caps"&gt;HOME&lt;/span&gt; key brought up a very useful debug window with loads of wibbly buttons and sliders and gizmos and yeah, we&amp;#8217;re idiots, that&amp;#8217;s not for you. Even I don&amp;#8217;t know what most of those buttons&amp;nbsp;did.&lt;/p&gt;
&lt;h3 id="glyphs"&gt;Glyphs?&lt;/h3&gt;
&lt;p&gt;A glyph is a fancy word for one of the letters in a font. We cleaned up the glyphs that represent the controller buttons for &lt;span class="caps"&gt;PSX&lt;/span&gt; and XBox controllers so they are less&amp;#8230;&amp;nbsp;poopy.&lt;/p&gt;
&lt;p&gt;Happy Exploring and&amp;nbsp;Destroying&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/face_icons_dazza.jpg" /&gt;&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="SmithAndWinston"></category></entry><entry><title>GameMite review Smith and Winston Early Access</title><link href="https://www.executionunit.com/blog/2019/01/12/gamemite-review-smith-and-winston-early-access/" rel="alternate"></link><published>2019-01-12T00:00:00+00:00</published><updated>2019-01-12T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-01-12:/blog/2019/01/12/gamemite-review-smith-and-winston-early-access/</id><summary type="html">&lt;p&gt;The lovely people over at &lt;a href="http://www.gamemite.com"&gt;GameMite&lt;/a&gt; have &lt;a href="https://www.gamemite.com/article/682/smith-and-winston-enters-early-access-for-linux-and-windows/"&gt;reviewed Smith and Winston&lt;/a&gt;. I particlularly liked the ending where they&amp;nbsp;say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Anyone who loves a good, exciting twin stick shooter should find a lot to enjoy&amp;nbsp;here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great to see people covering the game and getting it&amp;#8217;s weird mix of metroidly …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The lovely people over at &lt;a href="http://www.gamemite.com"&gt;GameMite&lt;/a&gt; have &lt;a href="https://www.gamemite.com/article/682/smith-and-winston-enters-early-access-for-linux-and-windows/"&gt;reviewed Smith and Winston&lt;/a&gt;. I particlularly liked the ending where they&amp;nbsp;say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Anyone who loves a good, exciting twin stick shooter should find a lot to enjoy&amp;nbsp;here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great to see people covering the game and getting it&amp;#8217;s weird mix of metroidly looking aroundy&amp;nbsp;shootyness.&lt;/p&gt;
&lt;p&gt;be seeing&amp;nbsp;you,&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/face_icons_dazza.jpg" /&gt;&lt;/p&gt;</content><category term="snw"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Steam Early Access</title><link href="https://www.executionunit.com/blog/2019/01/09/smith-and-winston-steam-early-access/" rel="alternate"></link><published>2019-01-09T00:00:00+00:00</published><updated>2019-01-09T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-01-09:/blog/2019/01/09/smith-and-winston-steam-early-access/</id><summary type="html">&lt;p&gt;We are really pleased to finally be able to say that &lt;a href="https://store.steampowered.com/app/942250/Smith_and_Winston/"&gt;Smith and Winston is on Steam&lt;/a&gt;. We really enjoyed &lt;a href="https://executionunit.itch.io/smith-and-winston"&gt;releasing on itch.io first&lt;/a&gt; and we think that the smaller community helped us prepare for the much larger and faster moving Steam&amp;nbsp;community.&lt;/p&gt;
&lt;p&gt;As well as releasing on Early …&lt;/p&gt;</summary><content type="html">&lt;p&gt;We are really pleased to finally be able to say that &lt;a href="https://store.steampowered.com/app/942250/Smith_and_Winston/"&gt;Smith and Winston is on Steam&lt;/a&gt;. We really enjoyed &lt;a href="https://executionunit.itch.io/smith-and-winston"&gt;releasing on itch.io first&lt;/a&gt; and we think that the smaller community helped us prepare for the much larger and faster moving Steam&amp;nbsp;community.&lt;/p&gt;
&lt;p&gt;As well as releasing on Early Access we are starting to ramp up press activity so people know about the game. We&amp;#8217;ve opened up the &lt;a href="/snw_presskit.html"&gt;Smith and Winston Press Kit&lt;/a&gt; page to everyone. There are loads of lovely images, gifs and a few movies in there as well. Feel free to use them to talk about the&amp;nbsp;game.&lt;/p&gt;
&lt;h2 id="new-gameplay-trailer"&gt;New gameplay&amp;nbsp;trailer&lt;/h2&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/_UZsUh4glUI" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;h2 id="plans-for-itch"&gt;Plans for&amp;nbsp;itch&lt;/h2&gt;
&lt;p&gt;Just because we&amp;#8217;re on Steam we don&amp;#8217;t plan on dropping support for itch.io. Itch.io is a great site for indies and we plan to support it. We&amp;#8217;ll be updating itch with the same code as Steam (excluding things like Steam achievements and cloud saves for obvious&amp;nbsp;reasons).&lt;/p&gt;
&lt;p&gt;If you bought the game on itch.io in the past few months you can get a free Steam key via your Purchases section in your itch.io account. Your save game should just work as well so you can fire up your Steam copy and carry on from where you left off. At some point we&amp;#8217;ll move to Steam Cloud saves though and your save games will no longer be the same between itch.io and Steam&amp;nbsp;versions.&lt;/p&gt;
&lt;h2 id="plans-for-steam"&gt;Plans for&amp;nbsp;Steam&lt;/h2&gt;
&lt;p&gt;On Steam we plan to add a lot more achievements, cloud saves, leader boards and more controller&amp;nbsp;support.&lt;/p&gt;
&lt;h2 id="plans-for-the-game"&gt;Plans for the&amp;nbsp;game&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;ve got a long list of things to add to the game&amp;nbsp;including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;13/25 levels are not ready for the public yet (too buggy or incomplete) and are being worked on as we&amp;nbsp;speak.&lt;/li&gt;
&lt;li&gt;2/3 bosses have not been completed&amp;nbsp;yet.&lt;/li&gt;
&lt;li&gt;Split screen two player coop mode isn&amp;#8217;t enabled as it&amp;#8217;s too buggy and the levels need&amp;nbsp;balancing.&lt;/li&gt;
&lt;li&gt;Story Mode isn&amp;#8217;t enabled as the save games don&amp;#8217;t reliably work&amp;nbsp;yet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So there are things to come for itch.io and Steam&amp;nbsp;users.&lt;/p&gt;
&lt;p&gt;Have a great new year and we hope you enjoy Exploring and&amp;nbsp;Destroying.&lt;/p&gt;
&lt;p&gt;be seeing&amp;nbsp;you,&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/face_icons_dazza.jpg" /&gt;&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="SmithAndWinston"></category></entry><entry><title>How I support Windows, Mac and Linux</title><link href="https://www.executionunit.com/blog/2019/01/02/how-i-support-windows-mac-and-linux/" rel="alternate"></link><published>2019-01-02T00:00:00+00:00</published><updated>2019-01-02T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-01-02:/blog/2019/01/02/how-i-support-windows-mac-and-linux/</id><summary type="html">&lt;p class="bg-danger"&gt;
    10th Jan 2019 12:03 &lt;span class="caps"&gt;GMT&lt;/span&gt; - I just wanted to write a positive article that might help others. So please don&amp;#8217;t use this post as a stick to beat others. It&amp;#8217;s a complex issue of dev experience, team size and frankly money. We&amp;#8217;re all just trying to …&lt;/p&gt;</summary><content type="html">&lt;p class="bg-danger"&gt;
    10th Jan 2019 12:03 &lt;span class="caps"&gt;GMT&lt;/span&gt; - I just wanted to write a positive article that might help others. So please don&amp;#8217;t use this post as a stick to beat others. It&amp;#8217;s a complex issue of dev experience, team size and frankly money. We&amp;#8217;re all just trying to make great games -&amp;nbsp;dazza.
&lt;/p&gt;

&lt;p&gt;So as usual there is some controversy about supporting Linux (and macOS for that matter) if you&amp;#8217;re a game dev. I am a game dev and our current game &lt;a href="http://www.smithandwinston.com"&gt;Smith and Winston&lt;/a&gt; support Windows, Linux and macOS. So how do I as a lone coder in a team of two support three platforms and is it all easy and&amp;nbsp;free?&lt;/p&gt;
&lt;h2 id="how"&gt;How?&lt;/h2&gt;
&lt;h3 id="custom-code"&gt;Custom&amp;nbsp;Code&lt;/h3&gt;
&lt;p&gt;Firstly we use a custom engine and this makes it harder but also better. Here is a blog about &lt;a href="https://www.executionunit.com/blog/2017/07/14/in-defence-of-writing-your-own-engine/"&gt;how I assemble the engine&lt;/a&gt;. I&amp;#8217;m sure it is a lot &amp;#8216;easier&amp;#8217; to just use Unity, Unreal, Godot or any of the other engines out there. The easy path is not necessarily the most fun or rewarding path to travel&amp;nbsp;though.&lt;/p&gt;
&lt;p&gt;The upside of custom code is that I basically build upon the best for me, my game and my customers. &lt;a href="https://www.libsdl.org/"&gt;libSDL2&lt;/a&gt; is fantastic and takes 90% of the pain away from platform support. &lt;a href="https://github.com/bkaradzic/bgfx"&gt;&lt;span class="caps"&gt;BGFX&lt;/span&gt;&lt;/a&gt; is an amazing library for rendering, &lt;a href="https://twitter.com/bkaradzic"&gt;written by someone&lt;/a&gt; who clearly knows about cross platform support and is dedicated to producing quality&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;Custom code gives me the maximum chance of being able to debug a platform specific issue. Not only is the source code available but because I integrated it I know how it works. I hate the idea that I would have to say to a customer that &amp;#8220;I can&amp;#8217;t fix that issue because there is a bug in Unity/Unreal that I can&amp;#8217;t fix and will never really know when it&amp;#8217;s going to be fixed&amp;#8221;. This is a matter of professional due diligence. Of course there are hidden corners of all the libraries I use so I can&amp;#8217;t guarantee anything but I at least have a fighting&amp;nbsp;chance.&lt;/p&gt;
&lt;p&gt;From day one I intended to support multiple platforms. I didn&amp;#8217;t code for all of them from day one but I knew that where ever I touched the &lt;span class="caps"&gt;OS&lt;/span&gt; I was going to need to think about platform differences. Common areas are files, file paths, rendering, threading, sound, date and time and localisation. You just need to think about it. If you didn&amp;#8217;t compile it then you may need to wrap it in a cross platform &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;h3 id="machines-and-vms"&gt;Machines and&amp;nbsp;VMs&lt;/h3&gt;
&lt;p&gt;I dedicate hardware to building and testing macOS, Windows and&amp;nbsp;Linux.&lt;/p&gt;
&lt;p&gt;I have a machine dedicated to building the engine and game datasets on all platforms in all configurations all the time. It has many VMs running. It just sits there waiting for new code to be added and the opportunity to make me look stupid. It emails me with build errors and warnings. I hate that machine. Here are the configurations it&amp;nbsp;builds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows&lt;/li&gt;
&lt;li&gt;Windows +&amp;nbsp;Oculus&lt;/li&gt;
&lt;li&gt;Windows +&amp;nbsp;Steam&lt;/li&gt;
&lt;li&gt;Windows + Steam +&amp;nbsp;Oculus&lt;/li&gt;
&lt;li&gt;Linux&lt;/li&gt;
&lt;li&gt;Linux +&amp;nbsp;Steam&lt;/li&gt;
&lt;li&gt;macOS&lt;/li&gt;
&lt;li&gt;macOS +&amp;nbsp;Steam&lt;/li&gt;
&lt;li&gt;FreeBSD&lt;/li&gt;
&lt;li&gt;(consoles I can&amp;#8217;t talk&amp;nbsp;about)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;all of them in debug, release and profiling configurations. So that&amp;#8217;s 27 targets I can talk about. While it&amp;#8217;s only really four platforms each of the sub-platforms offer opportunities for me to break things. If you make finding these faults easy and fast then you&amp;#8217;re much more likely to fix them early and&amp;nbsp;quickly.&lt;/p&gt;
&lt;p&gt;This means I am totally relaxed about macOS and Linux as platforms. There are no surprises for me when it comes to testing and deployment. I use a custom python build system that constantly loops through (checkout, cmake/premake/GENie, build, report). It&amp;#8217;s only a few thousand lines of code but it&amp;#8217;s saved me many hours by catching code that breaks a platform I am not working&amp;nbsp;on.&lt;/p&gt;
&lt;p&gt;I also rotate my primary development platform spending time in Windows, macOS and Linux. This means I know the platforms and tools&amp;nbsp;well.&lt;/p&gt;
&lt;h3 id="im-old"&gt;I&amp;#8217;m&amp;nbsp;old&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;ve been writing games and engines for 30+ years so none of this is new, I have a lot of experience. But you only get the experience by doing it and not making&amp;nbsp;excuses.&lt;/p&gt;
&lt;h3 id="separation-of-game-and-engine-logic"&gt;Separation of game and engine&amp;nbsp;logic&lt;/h3&gt;
&lt;p&gt;Our engine uses Lua for game logic and C++ for the runtime code. This separation means we can focus our testing depending on what has changed between releases. Mostly the engine stays the same so we can focus on testing the actual elements of the game and the few bug fixes the engine&amp;nbsp;gets.&lt;/p&gt;
&lt;h2 id="why"&gt;Why?&lt;/h2&gt;
&lt;h3 id="moral-argument"&gt;Moral&amp;nbsp;Argument&lt;/h3&gt;
&lt;p&gt;There are a lot of good things to say about Microsoft. Monopolies are not good for anyone though. While you can&amp;#8217;t break a monopoly on your own you can play your small part. Microsoft is an infinitely better company now than they were 10 years ago because they&amp;#8217;ve had a few bloody noses. Let&amp;#8217;s hope someone does the same to Google and Facebook pretty soon. So by supporting the minor platforms you are making the major platform&amp;nbsp;better.&lt;/p&gt;
&lt;h3 id="quality-argument"&gt;Quality&amp;nbsp;Argument&lt;/h3&gt;
&lt;p&gt;By forcing the game through different compilers (Visual C++, Clang and &lt;span class="caps"&gt;GCC&lt;/span&gt;) you find different code bugs (leave the warnings on max). By forcing the runtime to use different memory allocators, threading libraries and rendering technologies you find different runtime bugs. This makes your code way more stable on every platform. Even if you never deploy your code to a non windows platform just running it on Linux or macOS will expose crashes instantly that rarely appear on Windows. So delivering a quality product on the dominant platform is easier if your support the minor platforms as&amp;nbsp;well.&lt;/p&gt;
&lt;h3 id="porting-argument"&gt;Porting&amp;nbsp;argument&lt;/h3&gt;
&lt;p&gt;Starting with Windows, Linux and macOS makes porting to XBox One, &lt;span class="caps"&gt;PS4&lt;/span&gt; and Switch a &lt;span class="caps"&gt;LOT&lt;/span&gt; easier. There will be a clear separation between common and platform specific. Maybe you&amp;#8217;ll never port to those platforms but if you do you&amp;#8217;ll be&amp;nbsp;ready.&lt;/p&gt;
&lt;h2 id="is-it-free"&gt;Is it&amp;nbsp;free?&lt;/h2&gt;
&lt;p&gt;Hell no. But if it were free it probably wouldn&amp;#8217;t be worth doing. Machines take time to maintain, they cost money to run and purchase. Certainly macOS is an expensive platform to buy in to with it&amp;#8217;s low end machines being expensive and &lt;em&gt;very&lt;/em&gt; low&amp;nbsp;end. &lt;/p&gt;
&lt;p&gt;Over time there is a cost as well. With the transition from &lt;span class="caps"&gt;DX11&lt;/span&gt; to &lt;span class="caps"&gt;DX12&lt;/span&gt; and OpenGL to Vulkan I need to manage that. Unity and Unreal will &amp;#8216;hopefully&amp;#8217; make  this completely transparent to their users (but I doubt it). macOS moves pretty slowly but it routinely drops features where as Windows has only recently dropped some &lt;span class="caps"&gt;DOS&lt;/span&gt; features! This needs to be factored in to the long term maintenance costs of an engine and&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;Do you make your money back? It&amp;#8217;s hard to say definitely which could mean no. Linux and macOS sales are low so the direct rewards are also low. However this needs to be weighed up against the increase in quality of the engine. For Smith and Winston right now I don&amp;#8217;t think it&amp;#8217;s been worth it financially (but it will probably make it&amp;#8217;s money back on Launch), but mentally (peace of mind), morally and quality wise it&amp;#8217;s been more than worth&amp;nbsp;it.&lt;/p&gt;
&lt;h2 id="fanboy"&gt;Fanboy!&lt;/h2&gt;
&lt;p&gt;I am &lt;strong&gt;not&lt;/strong&gt; a Linux fan boy. In fact I use FreeBSD, recommend FreeBSD and am a total FreeBSD fan boy. I&amp;#8217;ll probably never ship a game on FreeBSD because that&amp;#8217;s just not what it is for. Linux is however a desktop &lt;span class="caps"&gt;OS&lt;/span&gt; and a pretty good one so I see no reason not to support&amp;nbsp;it.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;People will tell you it&amp;#8217;s not worth supporting the minor desktop OSes. My argument is that by doing it you will create a better quality product on the major OSes saving you money in testing and bug fixing for the majority of your users. I have nothing other than 25 years of commercial experience making games to back up this statement so feel free to ignore&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Happy new year and good luck in what ever you decide to&amp;nbsp;do.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #3</title><link href="https://www.executionunit.com/blog/2019/01/02/smith-and-winston-update-3/" rel="alternate"></link><published>2019-01-02T00:00:00+00:00</published><updated>2019-01-02T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2019-01-02:/blog/2019/01/02/smith-and-winston-update-3/</id><summary type="html">&lt;p&gt;Today we released the third update to Smith and Winston (only two more to go before it&amp;#8217;s finished!). I&amp;#8217;ll cover the new levels, bugfixes, tweaks and the future development in this&amp;nbsp;post.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today we released the third update to Smith and Winston (only two more to go before it&amp;#8217;s finished!). I&amp;#8217;ll cover the new levels, bugfixes, tweaks and the future development in this&amp;nbsp;post.&lt;/p&gt;
&lt;h2 id="new-levels"&gt;New&amp;nbsp;Levels&lt;/h2&gt;
&lt;p&gt;There are three new levels in this release. First &lt;em&gt;The Sky Ways&lt;/em&gt;. This level is a crazy mix of combat and puzzle. There is a clue in this picture if you ever make it this far :) Don&amp;#8217;t worry, there isn&amp;#8217;t any combat on these thin walkways&amp;#8230; I don&amp;#8217; think ;)
&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_3_1.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hanging Rock&lt;/em&gt;. Back in the forest zone of this weird ring world. Things are looking even more broken then before&amp;#8230; spider crab things are everywhere! Watch your back.
&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_3_2.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Abandoned&lt;/em&gt; This is a weird place. A mixture of army base and shipping port. Hidden portals, dark passageways and eerie poorly placed street&amp;nbsp;lights.&lt;/p&gt;
&lt;h2 id="tweaks"&gt;Tweaks&lt;/h2&gt;
&lt;p&gt;Weirdly we didn&amp;#8217;t get everything right in the game up til now so we&amp;#8217;ve made some tweaks after feedback from&amp;nbsp;players:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed fly forever ceiling bug - turns out that if you were in a cave with an invisible ceiling you could fly forever and basically scoot across all the lava and enemies that we deliberately put in the way to make the game hard. Very naughty of you so we&amp;#8217;ve fixed&amp;nbsp;that!&lt;/li&gt;
&lt;li&gt;We tweaked the elite enemies so they aren&amp;#8217;t &lt;span class="caps"&gt;SO&lt;/span&gt; hard to kill. They basically had really high health and soaked up way too many&amp;nbsp;bullets.&lt;/li&gt;
&lt;li&gt;Reworked the bunker boss as it was too hard and actually became a bit tedious. We don&amp;#8217;t want that so we&amp;#8217;ve removed a stage, slowed down the enemy spawning and reduced his health a&amp;nbsp;little.&lt;/li&gt;
&lt;li&gt;Added sound effects to doors and lifts in the early&amp;nbsp;levels.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bug-fixes"&gt;Bug&amp;nbsp;Fixes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;In Deep Down Again we reduced the fog a little as the enemies were too hard to&amp;nbsp;see.&lt;/li&gt;
&lt;li&gt;Fixed Proximity mines sometimes reappearing after death but&amp;nbsp;invisible.&lt;/li&gt;
&lt;li&gt;Fixed Proximity mines camera shake so it doesn&amp;#8217;t feel like you&amp;#8217;re going to&amp;nbsp;spew.&lt;/li&gt;
&lt;li&gt;Fix for the player flying/hovering forever. If you flew up and as you were about to reach the floor you dashes and the next frame there was a certain type of voxel you would fly/hover forever until&amp;nbsp;death.&lt;/li&gt;
&lt;li&gt;Fix a bug were rebuilding level collision/models occurred multiple times because dazza is an idiot. (helps low end machines a&amp;nbsp;lot)&lt;/li&gt;
&lt;li&gt;Removed some annoying debug prints that slowed down windows builds a&amp;nbsp;bit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="future-development"&gt;Future&amp;nbsp;Development&lt;/h2&gt;
&lt;p&gt;In general development is going really well. The engine is basically stable now across Windows, Linux and macOS. Crashes are pretty rare which is always a good thing. This leaves more time for dazza to concentrate on game play, bosses and polishing a few things here and there.  The levels are on track for release which is great. We were both ill over the xmas period so we&amp;#8217;re running a few weeks behind schedule for polish and sound which is very annoying. Nothing we can do about that&amp;nbsp;though.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re really struggling getting all the sound design done for the levels unfortunately and we&amp;#8217;re a good four weeks behind on&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;Steam is so nearly ready to go. The game is approved by Steam and we&amp;#8217;re ready to go in to Early Access. We&amp;#8217;re just getting together a decent press kit so that hopefully we can get some press coverage for the game. I&amp;#8217;ll just reiterate, if you&amp;#8217;ve bought the game on itch.io you are entitled to a Steam key if you want one (we get asked this a lot :) ). We&amp;#8217;ll keep you updated on the status of Steam. Hopefully you&amp;#8217;ll know because of all the press: billboards, sky writing, logo on the moon, maybe a mention from some streamer I&amp;#8217;ve never heard of&amp;#8230; or just an email from us&amp;nbsp;:)&lt;/p&gt;
&lt;p&gt;Anyway, thanks for reading this far, the two of us are really thankful for all your feedback, kind words and patience while we try and make Smith and Winston as good as&amp;nbsp;possible.&lt;/p&gt;
&lt;p&gt;Have a great new year and keep on exploring and&amp;nbsp;destroying.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #2</title><link href="https://www.executionunit.com/blog/2018/12/05/smith-and-winston-update-2/" rel="alternate"></link><published>2018-12-05T00:00:00+00:00</published><updated>2018-12-05T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2018-12-05:/blog/2018/12/05/smith-and-winston-update-2/</id><summary type="html">&lt;p&gt;Earlier than promised (by only a day) we&amp;#8217;ve released the second update to Smith and Winston. Of course we&amp;#8217;re really excited to hear what you guys think of the new levels including another secret level! Can you find&amp;nbsp;it?&lt;/p&gt;
&lt;p&gt;Get lost in the ancient underground temples but watch …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Earlier than promised (by only a day) we&amp;#8217;ve released the second update to Smith and Winston. Of course we&amp;#8217;re really excited to hear what you guys think of the new levels including another secret level! Can you find&amp;nbsp;it?&lt;/p&gt;
&lt;p&gt;Get lost in the ancient underground temples but watch out for the killer space slugs. They take a lot of hits to kill.
&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_2_3.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Get up high and survey the landscape, jumping to the left of me, enemies to the right and here I am stuck in the middle with&amp;#8230; is that a weapon power up down there!
&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_2_1.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;When you&amp;#8217;ve spent the evening shooting, plundering and exploring why not take a trip to the Chalk and Flowers level. The sun is setting, the birds are chirping and the blossoms are blossoming. There&amp;#8217;s loot to be plundered here but it&amp;#8217;s not where you expect.
&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_2_2.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Of course this release comes with a hosts of bug fixes including a lovely crash bug that we&amp;#8217;ve been hunting for a few years, an &lt;span class="caps"&gt;AI&lt;/span&gt; bug where they just jumped off the world for no reason and a sound bug where enemies would explode forever deafening everyone for one hundred miles. Thanks to everyone who reported bugs and gave feedback on here, Reddit and&amp;nbsp;Steam.&lt;/p&gt;
&lt;p&gt;If you don&amp;#8217;t feel like buying the game then follow us on itch for more update, &lt;a href="https://store.steampowered.com/app/942250/Smith_and_Winston/"&gt;Wishlist Smith and Winston on Steam&lt;/a&gt; or just check back here for info. There will be more news about steam soon. If you buy on here, we&amp;#8217;ll give you a Steam key when the game releases on&amp;nbsp;Steam.&lt;/p&gt;
&lt;p&gt;Explore and&amp;nbsp;Destroy.&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - Update #1</title><link href="https://www.executionunit.com/blog/2018/11/02/smith-and-winston-update-1/" rel="alternate"></link><published>2018-11-02T00:00:00+00:00</published><updated>2018-11-02T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2018-11-02:/blog/2018/11/02/smith-and-winston-update-1/</id><summary type="html">&lt;p&gt;We are amazingly happy to release Update #1 to everyone! It&amp;#8217;s been two weeks of hard work, over 50 bug fixes, three new levels and a metric tonne of tweaking and balancing. Thanks for all the feedback from the initial release. Smith and Winston is now &lt;span class="caps"&gt;EVEN&lt;/span&gt;&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;So …&lt;/p&gt;</summary><content type="html">&lt;p&gt;We are amazingly happy to release Update #1 to everyone! It&amp;#8217;s been two weeks of hard work, over 50 bug fixes, three new levels and a metric tonne of tweaking and balancing. Thanks for all the feedback from the initial release. Smith and Winston is now &lt;span class="caps"&gt;EVEN&lt;/span&gt;&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;So what is in the&amp;nbsp;update?&lt;/p&gt;
&lt;h2 id="bunker-boss"&gt;Bunker&amp;nbsp;Boss&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_1_bunkerboss.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;You meet this guy right at the end of this update. He&amp;#8217;s a recurring enemy, he lives in a bunker that belches out fumes and he protects himself with enemy spawners and massive cannons. Do you think you&amp;#8217;ve got what it takes to beat&amp;nbsp;him?&lt;/p&gt;
&lt;h2 id="swamp-of-the-reanimated"&gt;Swamp of the&amp;nbsp;Reanimated&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_1_swamp.jpg" /&gt;
So who would have though that near a damp, dinghy womble infested swamp there would a maze of lava caverns hiding a few secrets? Games designers, that&amp;#8217;s who. Everyone loves a lava section and if you don&amp;#8217;t&amp;#8230; well you might not even find&amp;nbsp;it.&lt;/p&gt;
&lt;h2 id="candy"&gt;Candy&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_1_maze.jpg" /&gt;
It&amp;#8217;s not all dark and dingy in the shattered ring world future of dooooom. Candy is so colourful it might make you sick&amp;#8230; after Halloween I think we can all relate to that&amp;#8230; even us brits who have inexplicably started to dress as ghouls for one day of the&amp;nbsp;year!&lt;/p&gt;
&lt;p&gt;Why oh why is Smithy sitting in that strange hole&amp;nbsp;though&amp;#8230;&lt;/p&gt;
&lt;h2 id="maze"&gt;Maze&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_1_maze.jpg" /&gt;
Leave  the dark and enter the light after the maze. This place must have been  lovely before&amp;#8230; well before it all went&amp;nbsp;wrong.&lt;/p&gt;
&lt;h2 id="collectable-helmets"&gt;Collectable&amp;nbsp;Helmets&lt;/h2&gt;
&lt;p&gt;&lt;img class="img-responsive" src="https://www.executionunit.com/static/media/snwblog/snw_1_heads.png" /&gt;&lt;/p&gt;
&lt;h2 id="thats-it-till-the-next-update"&gt;That&amp;#8217;s it till the next&amp;nbsp;update&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;re, of course, very proud of what we&amp;#8217;re releasing to all you lucky people today. To be honest though it&amp;#8217;s so much better for all the feedback you&amp;#8217;ve given us. From tweaking the controls to huge holes in the level design you&amp;#8217;ve been fantastic partners in the making of Smith and&amp;nbsp;Winston.&lt;/p&gt;
&lt;p&gt;The next update is scheduled for the 6th of December, more levels, more destruction and more&amp;nbsp;fun.&lt;/p&gt;
&lt;p&gt;Thanks&amp;#8230; now go forth&amp;#8230; &lt;span class="caps"&gt;EXPLORE&lt;/span&gt; &lt;span class="caps"&gt;AND&lt;/span&gt; &lt;span class="caps"&gt;DESTROY&lt;/span&gt;&lt;/p&gt;
&lt;iframe src="https://store.steampowered.com/widget/942250/" frameborder="0" width="646" height="190"&gt;&lt;/iframe&gt;

&lt;iframe src="https://itch.io/embed/209288" width="646" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston - First Access</title><link href="https://www.executionunit.com/blog/2018/10/12/smith-and-winston-first-access/" rel="alternate"></link><published>2018-10-12T00:00:00+01:00</published><updated>2018-10-12T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2018-10-12:/blog/2018/10/12/smith-and-winston-first-access/</id><summary type="html">&lt;p&gt;Well it&amp;#8217;s been a long long four years and Smith and Winston isn&amp;#8217;t done yet but it is a major milestone for us. We&amp;#8217;re opening the game up for&amp;nbsp;first-access.&lt;/p&gt;
&lt;p&gt;Why not just wait and release it? Well when you&amp;#8217;ve worked on something for so long …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Well it&amp;#8217;s been a long long four years and Smith and Winston isn&amp;#8217;t done yet but it is a major milestone for us. We&amp;#8217;re opening the game up for&amp;nbsp;first-access.&lt;/p&gt;
&lt;p&gt;Why not just wait and release it? Well when you&amp;#8217;ve worked on something for so long there comes a time when you just need to hear what other people think. Charlie and I love playing the game but what do &lt;span class="caps"&gt;YOU&lt;/span&gt;&amp;nbsp;think?&lt;/p&gt;
&lt;p&gt;Why did we go with itch.io? We&amp;#8217;re a two person team. One coder and one artist. To be frank if we launch on steam we&amp;#8217;re terrified that we&amp;#8217;ll be mobbed with bugs and complaints. Itch just seems a little bit more human and a little more kind&amp;#8230; if that makes sense. Sure we&amp;#8217;ll release on Steam later but for us itch.io seems like the right place to&amp;nbsp;be.&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/rgKcU1byc70" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Together, Chalie and I have over fourty years of game development experience. We&amp;#8217;re not spring chickens by any means but we&amp;#8217;re committed to releasing Smith and Winston and making it the best game we&amp;nbsp;can.&lt;/p&gt;
&lt;p&gt;Here are some images of Smith and Winston over the&amp;nbsp;years:&lt;/p&gt;
&lt;p&gt;&lt;img alt="First Prototype in Unity" src="https://www.executionunit.com/static/media/snwblog/snw_fa_unity.jpg" title="First Prototype in Unity"&gt;&lt;/p&gt;
&lt;p&gt;We originally prototyped an Ikari Warrior game in Unity in 2015. It was terrible but we enjoyed the Ikari Warrior&amp;nbsp;elements.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Early prototype in Custom Engine" src="https://www.executionunit.com/static/media/snwblog/snw_fa_bridge.jpg" title="Early prototype in Custom Engine"&gt;&lt;/p&gt;
&lt;p&gt;For some reason we decided that we&amp;#8217;d prototype a voxel version of the game, this is an early prototype in Unity or maybe Unreal engine. It looks good but both Unreal and Unity were a bit too slow for the size of voxels we wanted (they were slow at collision mesh update basically). I&amp;#8217;d written many engines over the year so I set about making my own &amp;#8220;quick&amp;#8221;&amp;nbsp;engine.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Early prototype of Combat" src="https://www.executionunit.com/static/media/snwblog/snw_fa_combat.gif" title="Early prototype of Combat"&gt;&lt;/p&gt;
&lt;p&gt;Again from 2015 maybe 16, we&amp;#8217;ve got basic combat, the camera can&amp;#8217;t rotate but it already looks &lt;span class="caps"&gt;REALLY&lt;/span&gt; good (if I say so&amp;nbsp;myself).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cracking" src="https://www.executionunit.com/static/media/snwblog/snw_fa_cracking.gif" title="Cracking"&gt;&lt;/p&gt;
&lt;p&gt;Another six months and we&amp;#8217;ve polished the lighting and the cracking that grenades can cause in the voxel&amp;nbsp;landscape.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Caves" src="https://www.executionunit.com/static/media/snwblog/snw_fa_caves.gif" title="Caves"&gt;&lt;/p&gt;
&lt;p&gt;Here, about a year ago (give or take) the voxel version, code and design really start to hit their stride. Now it&amp;#8217;s amazing to play and it&amp;#8217;s starting to get&amp;nbsp;challenging.&lt;/p&gt;
&lt;p&gt;All these pictures are on our imgur account so you can see how we got here: &lt;a href="https://executionunit.imgur.com/"&gt;Imgur&lt;/a&gt;&lt;/p&gt;
&lt;iframe src="https://itch.io/embed/209288" width="552" height="167" frameborder="0"&gt;&lt;/iframe&gt;</content><category term="snw"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston mentioned in Kotaku UK - We’re sexy!</title><link href="https://www.executionunit.com/blog/2018/01/14/smith-and-winston-mentioned-in-kotaku-uk-were-sexy/" rel="alternate"></link><published>2018-01-14T00:00:00+00:00</published><updated>2018-01-14T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2018-01-14:/blog/2018/01/14/smith-and-winston-mentioned-in-kotaku-uk-were-sexy/</id><summary type="html">&lt;p&gt;We&amp;#8217;re not that great at promoting Smith and Winston. It&amp;#8217;s not finished yet, so we&amp;#8217;re very busy, but we also know that we need to get as many people to see the game before it&amp;#8217;s done so they know it exists. So we are very grateful …&lt;/p&gt;</summary><content type="html">&lt;p&gt;We&amp;#8217;re not that great at promoting Smith and Winston. It&amp;#8217;s not finished yet, so we&amp;#8217;re very busy, but we also know that we need to get as many people to see the game before it&amp;#8217;s done so they know it exists. So we are very grateful to Kotaku and &lt;a href="https://twitter.com/LaurakBuzz"&gt;Laura Kate Dale&lt;/a&gt; for including is on a &lt;a href="http://www.kotaku.co.uk/2018/01/12/games-of-2018-british-games"&gt;big list of British Games coming out in 2018&lt;/a&gt;&amp;#8230; wahooo. There are some great games on the list as well as ours so why not have a wonder through the future of british&amp;nbsp;games.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.kotaku.co.uk/2018/01/12/games-of-2018-british-games"&gt;
    &lt;img alt="Big List of Games" src="/static/media/uploads/blog/snw/kotaku2018.jpg"&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hopefully we can get the game done &lt;span class="caps"&gt;ASAP&lt;/span&gt; and get some feed back from real humans. Not just our exhausted dev team of me and Charlie&amp;nbsp;;)&lt;/p&gt;</content><category term="snw"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>New Year, new HUD</title><link href="https://www.executionunit.com/blog/2018/01/10/new-year-new-hud/" rel="alternate"></link><published>2018-01-10T00:00:00+00:00</published><updated>2018-01-10T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2018-01-10:/blog/2018/01/10/new-year-new-hud/</id><summary type="html">&lt;p&gt;One of the elements we&amp;#8217;ve iterated on the most in Smith and Winston has been the &lt;span class="caps"&gt;HUD&lt;/span&gt;. It really is hard to convey all the information in a quick and timely manner to the player. This is especially true for a game with as fast action as Smith and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;One of the elements we&amp;#8217;ve iterated on the most in Smith and Winston has been the &lt;span class="caps"&gt;HUD&lt;/span&gt;. It really is hard to convey all the information in a quick and timely manner to the player. This is especially true for a game with as fast action as Smith and Winston. Here is out latest&amp;nbsp;revision.&lt;/p&gt;
&lt;p&gt;&lt;img alt="In the Light" src="/static/media/uploads/blog/snw/HUD_01.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Designing it so that it worked in both light and dark scenarios was also a&amp;nbsp;challenge.&lt;/p&gt;
&lt;p&gt;&lt;img alt="In the Dark" src="/static/media/uploads/blog/snw/HUD_03.jpg"&gt;&lt;/p&gt;
&lt;p&gt;It really feel like it&amp;#8217;s starting to come together now though so that&amp;#8217;s&amp;nbsp;good.&lt;/p&gt;</content><category term="snw"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Installing MacOS 9.2 on my Power Mac G4 (Sawtooth)</title><link href="https://www.executionunit.com/blog/2018/01/07/installing-macos-92-on-my-power-mac-g4-sawtooth/" rel="alternate"></link><published>2018-01-07T00:00:00+00:00</published><updated>2018-01-07T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2018-01-07:/blog/2018/01/07/installing-macos-92-on-my-power-mac-g4-sawtooth/</id><summary type="html">&lt;p&gt;For reasons that are obscure even to me, I felt the desire to unarchive some old &lt;span class="caps"&gt;DAT&lt;/span&gt; tapes that have been sitting around my house for the last 20 years. They were backed up with &lt;a href="https://www.retrospect.com/"&gt;Retrospect backup&lt;/a&gt; about 20 years ago on an old &lt;a href="https://everymac.com/systems/apple/powermac/specs/powermac_7100_80.html"&gt;PowerMac 7100/80&lt;/a&gt; when I worked …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For reasons that are obscure even to me, I felt the desire to unarchive some old &lt;span class="caps"&gt;DAT&lt;/span&gt; tapes that have been sitting around my house for the last 20 years. They were backed up with &lt;a href="https://www.retrospect.com/"&gt;Retrospect backup&lt;/a&gt; about 20 years ago on an old &lt;a href="https://everymac.com/systems/apple/powermac/specs/powermac_7100_80.html"&gt;PowerMac 7100/80&lt;/a&gt; when I worked at a company called The Multimedia Corporation (now&amp;nbsp;defunct).&lt;/p&gt;
&lt;p&gt;I looked at the &lt;span class="caps"&gt;DDS2&lt;/span&gt; tapes on FreeBSD and it said they were blank (using tar) but I couldn&amp;#8217;t be sure that Retrospect wasn&amp;#8217;t writing to the tape in a non standard way. So I could either look at the tape as a raw character device and maybe get some data from it or install &lt;span class="caps"&gt;OS9&lt;/span&gt; and Retrospect on my old G4 and restore the tapes. The latter should be easier! Plus the thought of actually reverse engineering the Restrospect tape format (which is as far as I know completely undocumented) was a bit daunting. &lt;em&gt;Especially if there was an easy out&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Installing &lt;span class="caps"&gt;OS&lt;/span&gt; 9 on to my G4 was a total &lt;span class="caps"&gt;PITA&lt;/span&gt; because of duff ISOs and a lot of duff information around. The &lt;span class="caps"&gt;ISO&lt;/span&gt; I found that did work for me was from &lt;a href="https://winworldpc.com/download/3dc3a37f-6518-c39a-11c3-a4e284a2c3a5"&gt;WinWorld&lt;/a&gt;. It&amp;#8217;s MacOS 9.2.1 and definitely supports that Sawtooth G4. I did a complete Universal install (you need to select custom install in the Mac &lt;span class="caps"&gt;OS&lt;/span&gt; installer). This does mean it boots a little more slowly but at least it works and you can move the drive to another &lt;span class="caps"&gt;OS9&lt;/span&gt;+ compatible computer and&amp;nbsp;boot.&lt;/p&gt;
&lt;p&gt;Before stumbling upon the WinWorld ISOs I tried many &lt;a href="http://www.roxio.com/enu/products/toast/titanium/"&gt;Toast&lt;/a&gt; files and it took me a long time to learn that you can&amp;#8217;t burn them in &lt;span class="caps"&gt;OSX&lt;/span&gt; and have them boot on old world Macs. I also learned that you can&amp;#8217;t turn them in to ISOs, burn them and have them boot in old world Macs. Many CDs lost their lives in the pursuit of this knowledge. I also learned that the netboot image floating around the internet boots but is unstable on my G4! I got to the point where I started to suspect my old G4 had a hardware fault. Despite it running flawlessly in &lt;span class="caps"&gt;OSX&lt;/span&gt; 10.4 is qould rarely run for more than 5 minutes in &lt;span class="caps"&gt;OS9&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Once MacOS was successfully installed I jumped through many hoops of &lt;span class="caps"&gt;SCSI&lt;/span&gt;&amp;lt;-&amp;gt;&lt;span class="caps"&gt;SCSI&lt;/span&gt; connectivity and adapter to connect my &lt;span class="caps"&gt;DDS3&lt;/span&gt; drive to my G4. I downloaded an old copy of &lt;a href="http://macintoshgarden.org/apps/retrospect-51"&gt;Retrospect&lt;/a&gt; and&amp;#8230; yep, you guessed it&amp;#8230; &lt;em&gt;the tapes were blank&lt;/em&gt;. Either I had blanked them, or I never backed up to these tapes or the tapes are dead and Retrospect is reporting them as blank (this seems unlikely to me). So anyway, lesson learned, just watch &lt;span class="caps"&gt;TV&lt;/span&gt; over christmas and don&amp;#8217;t have plans! I know I have at least another 5 tapes somewhere in the house so I&amp;#8217;ve left the setup ready to go if I ever stumble upon the&amp;nbsp;tapes.&lt;/p&gt;
&lt;p&gt;Here is an action shot, sometime around 3am on Christmas Day with my FreeBSD machine open so I can run a &lt;span class="caps"&gt;SCSI&lt;/span&gt; cable to the internals of the Mac. Another partial&amp;nbsp;success!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cables on xmas day" src="https://www.executionunit.com/static/media/uploads/blog/g4_macos.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Interesting to me is that my G4 has an accelerator in it. I totally forgot that I bought this. It takes it from 450MHz to 1.4GHz&amp;#8230; yes giga! It was one of the factors that I thought could be causing the various &lt;span class="caps"&gt;OS9&lt;/span&gt; installs to crash. Along with swapping out the &lt;span class="caps"&gt;HD&lt;/span&gt;, Memory, all &lt;span class="caps"&gt;PCI&lt;/span&gt; cards, &lt;span class="caps"&gt;CD&lt;/span&gt;-&lt;span class="caps"&gt;ROM&lt;/span&gt; and the &lt;span class="caps"&gt;AGP&lt;/span&gt; card. I had a lot of trouble finding the spec sheet on Other World Computings website so it&amp;#8217;s &lt;a href="https://www.executionunit.com/static/media/uploads/blog/Processor_OWCME41330L2D.pdf"&gt;here&lt;/a&gt; but the original from &lt;span class="caps"&gt;OWC&lt;/span&gt; is &lt;a href="https://eshop.macsales.com/Tech/manuals/mercuryextreme/OWCME41330L2D.pdf"&gt;here&lt;/a&gt; (for&amp;nbsp;now).&lt;/p&gt;
&lt;p&gt;Hope this helps poor soul who wants to use their&amp;nbsp;G4.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;As an aside I discovered on Boxing day that my G5 no longer turns on and just clicks when the on button is pressed. I have no idea where to start diagnosing that. A future blog post I&amp;nbsp;guess&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;</content><category term="misc"></category><category term="Hardware"></category></entry><entry><title>Mounting USB sticks autmatically in FreeBSD</title><link href="https://www.executionunit.com/blog/2018/01/01/freebsd-automount-usb-sticks/" rel="alternate"></link><published>2018-01-01T10:20:00+00:00</published><updated>2018-01-01T10:20:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2018-01-01:/blog/2018/01/01/freebsd-automount-usb-sticks/</id><summary type="html">&lt;p&gt;Getting &lt;span class="caps"&gt;USB&lt;/span&gt; devices to automount in FreeBSD is harder and more complex that it needs to be. All the parts are there but what makes it hard is that it&amp;#8217;s changed over the years so you can get yourself in a right pickle. Here is what I did to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Getting &lt;span class="caps"&gt;USB&lt;/span&gt; devices to automount in FreeBSD is harder and more complex that it needs to be. All the parts are there but what makes it hard is that it&amp;#8217;s changed over the years so you can get yourself in a right pickle. Here is what I did to get it working with &lt;code&gt;FreeBSD 11.1-RELASE&lt;/code&gt;. If you follow the handbook you end up with &lt;span class="caps"&gt;USB&lt;/span&gt; sticks that mount but are readonly and can&amp;#8217;t be unmounted by a non-root&amp;nbsp;user.&lt;/p&gt;
&lt;p&gt;Firstly follow &lt;a href="https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/usb-disks.html"&gt;FreeBSD Handbook section on &lt;span class="caps"&gt;USB&lt;/span&gt;&lt;/a&gt; sections &lt;code&gt;17.4.1&lt;/code&gt; and &lt;code&gt;17.4.2&lt;/code&gt; &lt;strong&gt;&lt;span class="caps"&gt;BUT&lt;/span&gt; &lt;span class="caps"&gt;DO&lt;/span&gt; &lt;span class="caps"&gt;NOT&lt;/span&gt;&lt;/strong&gt; uncomment&amp;nbsp;the&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/media&lt;span class="w"&gt; &lt;/span&gt;-media&lt;span class="w"&gt; &lt;/span&gt;-nosuid
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;line in &lt;code&gt;/etc/auto_master&lt;/code&gt; and &lt;strong&gt;&lt;span class="caps"&gt;DO&lt;/span&gt; &lt;span class="caps"&gt;NOT&lt;/span&gt;&lt;/strong&gt; uncomment the lines in devd.conf (or move them above the comment as the file&amp;nbsp;says). &lt;/p&gt;
&lt;p&gt;Next install &lt;a href="https://www.freshports.org/sysutils/automount/"&gt;Freshports/automount&lt;/a&gt; from ports or&amp;nbsp;pkg.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pkg&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;automount
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Automount is going to be called by devfs when a &lt;span class="caps"&gt;USB&lt;/span&gt; device is detected on insertion. The installer installs the devd additions in to &lt;code&gt;/usr/local/etc/devd/automount_devd.conf&lt;/code&gt; for you (which is why you don&amp;#8217;t need to do it&amp;nbsp;yourself).&lt;/p&gt;
&lt;p&gt;Automount itself needs to be configured. So &lt;code&gt;cp /usr/local/etc/automount.conf.sample /usr/local/etc/automount.conf&lt;/code&gt; and then open it in your favourite&amp;nbsp;editor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;USERUMOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YES
&lt;span class="nv"&gt;ATIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO
&lt;span class="nv"&gt;REMOVEDIRS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YES
&lt;span class="nv"&gt;FM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;thunar&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;USERNAME&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;ENCODING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pl_PL.ISO8859-2
&lt;span class="nv"&gt;CODEPAGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cp852
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I changed &lt;code&gt;USER&lt;/code&gt; to my username and &lt;code&gt;FM&lt;/code&gt; to launch &lt;code&gt;thunar&lt;/code&gt; when a &lt;span class="caps"&gt;USB&lt;/span&gt; is inserted. In a multi user system this isn&amp;#8217;t ideal as there is only one user. My only thought on this is to create a user called &lt;code&gt;USBThumb&lt;/code&gt; that can&amp;#8217;t login and add all users to the &lt;code&gt;USBThumb&lt;/code&gt; group. I&amp;#8217;ve not done this but you can see where I am going with&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Anyway, this should get you going. Hope it helps&amp;nbsp;someone.&lt;/p&gt;</content><category term="freebsd"></category><category term="FreeBSD"></category></entry><entry><title>Merry XMas and a happy new year</title><link href="https://www.executionunit.com/blog/2017/12/25/merry-xmas-and-a-happy-new-year/" rel="alternate"></link><published>2017-12-25T00:00:00+00:00</published><updated>2017-12-25T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2017-12-25:/blog/2017/12/25/merry-xmas-and-a-happy-new-year/</id><summary type="html">&lt;p&gt;We took one of the secret levels from &lt;a href="http://www.smithandwinston.com"&gt;Smith and Winston&lt;/a&gt; and played with it for a few days to make a Christmas style level. We&amp;#8217;ll probably hide this level somewhere in the game, maybe it will only appear on Christmas&amp;nbsp;day?&lt;/p&gt;
&lt;p&gt;Anyway, we hope everyone has a really …&lt;/p&gt;</summary><content type="html">&lt;p&gt;We took one of the secret levels from &lt;a href="http://www.smithandwinston.com"&gt;Smith and Winston&lt;/a&gt; and played with it for a few days to make a Christmas style level. We&amp;#8217;ll probably hide this level somewhere in the game, maybe it will only appear on Christmas&amp;nbsp;day?&lt;/p&gt;
&lt;p&gt;Anyway, we hope everyone has a really happy&amp;nbsp;break.&lt;/p&gt;
&lt;div style="position:relative;height:0;padding-bottom:56.25%"&gt;&lt;iframe src="https://www.youtube.com/embed/YxKkM05jZv0?ecver=2" width="640" height="360" frameborder="0" gesture="media" allow="encrypted-media" style="position:absolute;width:100%;height:100%;left:0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Connecting to a m0n0wall box over serial</title><link href="https://www.executionunit.com/blog/2017/08/20/connecting-to-a-m0n0wall-box-over-serial/" rel="alternate"></link><published>2017-08-20T00:00:00+01:00</published><updated>2017-08-20T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2017-08-20:/blog/2017/08/20/connecting-to-a-m0n0wall-box-over-serial/</id><summary type="html">&lt;p&gt;I dug up my old &lt;a href="http://m0n0.ch"&gt;m0n0wall&lt;/a&gt; box today and wanted to see what was on it. It&amp;#8217;s an old &lt;a href="http://www.pcengines.ch/wrap.htm"&gt;&lt;span class="caps"&gt;WRAP&lt;/span&gt; embedded system from &lt;span class="caps"&gt;PC&lt;/span&gt; Engines&lt;/a&gt;. It doesn&amp;#8217;t have any video out.  I didn&amp;#8217;t want to connect it to my network as it&amp;#8217;s likely to have the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I dug up my old &lt;a href="http://m0n0.ch"&gt;m0n0wall&lt;/a&gt; box today and wanted to see what was on it. It&amp;#8217;s an old &lt;a href="http://www.pcengines.ch/wrap.htm"&gt;&lt;span class="caps"&gt;WRAP&lt;/span&gt; embedded system from &lt;span class="caps"&gt;PC&lt;/span&gt; Engines&lt;/a&gt;. It doesn&amp;#8217;t have any video out.  I didn&amp;#8217;t want to connect it to my network as it&amp;#8217;s likely to have the ipaddress 192.168.1.1 and that would cause conflicts with my pfSense&amp;nbsp;box.&lt;/p&gt;
&lt;p&gt;So I connected up a serial cable, connected to the box&amp;nbsp;using&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cu&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;/dev/cuaU0&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;38400&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The docs say that the speed should be &lt;code&gt;115200&lt;/code&gt; but I found that didn&amp;#8217;t work (even after resetting the box back to factory&amp;nbsp;defaults).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is really just a blog post for me. In a few years I will stumble across this box again and need to know how to connect to it&amp;nbsp;:)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Incase anyone stumbles across this on google looking for a FreeBSD compatible &lt;span class="caps"&gt;USB&lt;/span&gt; to serial. I used a &lt;span class="caps"&gt;USB&lt;/span&gt; to Serial cable that I had lying around. I worked fine with FreeBSD 11. The cable appeared&amp;nbsp;as &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Prolific&lt;span class="w"&gt; &lt;/span&gt;Technology&lt;span class="w"&gt; &lt;/span&gt;Inc.&lt;span class="w"&gt; &lt;/span&gt;USB-Serial&lt;span class="w"&gt; &lt;/span&gt;Controller&lt;span class="w"&gt; &lt;/span&gt;D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;in dmesg you see&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ugen0.2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Prolific&lt;span class="w"&gt; &lt;/span&gt;Technology&lt;span class="w"&gt; &lt;/span&gt;Inc.&lt;span class="w"&gt; &lt;/span&gt;USB-Serial&lt;span class="w"&gt; &lt;/span&gt;Controller&lt;span class="w"&gt; &lt;/span&gt;D&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;usbus0
uplcom0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;uhub4
uplcom0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Prolific&lt;span class="w"&gt; &lt;/span&gt;Technology&lt;span class="w"&gt; &lt;/span&gt;Inc.&lt;span class="w"&gt; &lt;/span&gt;USB-Serial&lt;span class="w"&gt; &lt;/span&gt;Controller&lt;span class="w"&gt; &lt;/span&gt;D,&lt;span class="w"&gt; &lt;/span&gt;class&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;/0,&lt;span class="w"&gt; &lt;/span&gt;rev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.10/4.00,&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;usbus0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For reference here is the serial output of the &lt;span class="caps"&gt;WRAP&lt;/span&gt; box as it boots. This box used to be a lovely firewall but m0n0wall&amp;#8217;s retirement and it&amp;#8217;s slow processor forced an upgrade to a more powerful&amp;nbsp;box.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;
&lt;span class="normal"&gt;56&lt;/span&gt;
&lt;span class="normal"&gt;57&lt;/span&gt;
&lt;span class="normal"&gt;58&lt;/span&gt;
&lt;span class="normal"&gt;59&lt;/span&gt;
&lt;span class="normal"&gt;60&lt;/span&gt;
&lt;span class="normal"&gt;61&lt;/span&gt;
&lt;span class="normal"&gt;62&lt;/span&gt;
&lt;span class="normal"&gt;63&lt;/span&gt;
&lt;span class="normal"&gt;64&lt;/span&gt;
&lt;span class="normal"&gt;65&lt;/span&gt;
&lt;span class="normal"&gt;66&lt;/span&gt;
&lt;span class="normal"&gt;67&lt;/span&gt;
&lt;span class="normal"&gt;68&lt;/span&gt;
&lt;span class="normal"&gt;69&lt;/span&gt;
&lt;span class="normal"&gt;70&lt;/span&gt;
&lt;span class="normal"&gt;71&lt;/span&gt;
&lt;span class="normal"&gt;72&lt;/span&gt;
&lt;span class="normal"&gt;73&lt;/span&gt;
&lt;span class="normal"&gt;74&lt;/span&gt;
&lt;span class="normal"&gt;75&lt;/span&gt;
&lt;span class="normal"&gt;76&lt;/span&gt;
&lt;span class="normal"&gt;77&lt;/span&gt;
&lt;span class="normal"&gt;78&lt;/span&gt;
&lt;span class="normal"&gt;79&lt;/span&gt;
&lt;span class="normal"&gt;80&lt;/span&gt;
&lt;span class="normal"&gt;81&lt;/span&gt;
&lt;span class="normal"&gt;82&lt;/span&gt;
&lt;span class="normal"&gt;83&lt;/span&gt;
&lt;span class="normal"&gt;84&lt;/span&gt;
&lt;span class="normal"&gt;85&lt;/span&gt;
&lt;span class="normal"&gt;86&lt;/span&gt;
&lt;span class="normal"&gt;87&lt;/span&gt;
&lt;span class="normal"&gt;88&lt;/span&gt;
&lt;span class="normal"&gt;89&lt;/span&gt;
&lt;span class="normal"&gt;90&lt;/span&gt;
&lt;span class="normal"&gt;91&lt;/span&gt;
&lt;span class="normal"&gt;92&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;PC&lt;span class="w"&gt; &lt;/span&gt;Engines&lt;span class="w"&gt; &lt;/span&gt;WRAP.1C/1D/1E&lt;span class="w"&gt; &lt;/span&gt;v1.11
&lt;span class="m"&gt;640&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;KB&lt;span class="w"&gt; &lt;/span&gt;Base&lt;span class="w"&gt; &lt;/span&gt;Memory
&lt;span class="m"&gt;130048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;KB&lt;span class="w"&gt; &lt;/span&gt;Extended&lt;span class="w"&gt; &lt;/span&gt;Memory

01F0&lt;span class="w"&gt; &lt;/span&gt;Master&lt;span class="w"&gt; &lt;/span&gt;848A&lt;span class="w"&gt; &lt;/span&gt;Flash&lt;span class="w"&gt; &lt;/span&gt;Card&lt;span class="w"&gt;                              &lt;/span&gt;
Phys&lt;span class="w"&gt; &lt;/span&gt;C/H/S&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;984&lt;/span&gt;/16/8&lt;span class="w"&gt; &lt;/span&gt;Log&lt;span class="w"&gt; &lt;/span&gt;C/H/S&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;984&lt;/span&gt;/16/8
Consoles:&lt;span class="w"&gt; &lt;/span&gt;internal&lt;span class="w"&gt; &lt;/span&gt;video/keyboard&lt;span class="w"&gt;  &lt;/span&gt;
BIOS&lt;span class="w"&gt; &lt;/span&gt;drive&lt;span class="w"&gt; &lt;/span&gt;C:&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;disk0
BIOS&lt;span class="w"&gt; &lt;/span&gt;640kB/130048kB&lt;span class="w"&gt; &lt;/span&gt;available&lt;span class="w"&gt; &lt;/span&gt;memory

FreeBSD/i386&lt;span class="w"&gt; &lt;/span&gt;bootstrap&lt;span class="w"&gt; &lt;/span&gt;loader,&lt;span class="w"&gt; &lt;/span&gt;Revision&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.1
&lt;span class="o"&gt;(&lt;/span&gt;root@mb64.neon1.net,&lt;span class="w"&gt; &lt;/span&gt;Thu&lt;span class="w"&gt; &lt;/span&gt;Jul&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;23&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;:56:49&lt;span class="w"&gt; &lt;/span&gt;CEST&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2009&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
/kernel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x368050&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x3d474+0x22ef4&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;syms&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;0x4+0x47050+0x4+0x5acc6&lt;span class="o"&gt;]&lt;/span&gt;
Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1992&lt;/span&gt;-2008&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;FreeBSD&lt;span class="w"&gt; &lt;/span&gt;Project.
Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1979&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1980&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1983&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1986&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1988&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1989&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1991&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1992&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1993&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1994&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;Regents&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;University&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;California.&lt;span class="w"&gt; &lt;/span&gt;All&lt;span class="w"&gt; &lt;/span&gt;rights&lt;span class="w"&gt; &lt;/span&gt;reserved.
FreeBSD&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;registered&lt;span class="w"&gt; &lt;/span&gt;trademark&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;FreeBSD&lt;span class="w"&gt; &lt;/span&gt;Foundation.
FreeBSD&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.4-RELEASE-p5&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0: Sun Jan  9 22:24:57 CET 2011&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;root@mb64.neon1.net:/usr/src/sys/i386/compile/M0N0WALL_EMBEDDED
Timecounter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;i8254&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1193182&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
CPU:&lt;span class="w"&gt; &lt;/span&gt;Geode&lt;span class="o"&gt;(&lt;/span&gt;TM&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Integrated&lt;span class="w"&gt; &lt;/span&gt;Processor&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;National&lt;span class="w"&gt; &lt;/span&gt;Semi&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;266&lt;/span&gt;.65-MHz&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;586&lt;/span&gt;-class&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Geode by NSC&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;0x540&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Stepping&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x808131&amp;lt;FPU,TSC,MSR,CX8,CMOV,MMX&amp;gt;
real&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;134217728&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MB&lt;span class="o"&gt;)&lt;/span&gt;
avail&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;105136128&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MB&lt;span class="o"&gt;)&lt;/span&gt;
wlan:&lt;span class="w"&gt; &lt;/span&gt;mac&lt;span class="w"&gt; &lt;/span&gt;acl&lt;span class="w"&gt; &lt;/span&gt;policy&lt;span class="w"&gt; &lt;/span&gt;registered
ath_hal:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.9.20.3&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;AR5210,&lt;span class="w"&gt; &lt;/span&gt;AR5211,&lt;span class="w"&gt; &lt;/span&gt;AR5212,&lt;span class="w"&gt; &lt;/span&gt;RF5111,&lt;span class="w"&gt; &lt;/span&gt;RF5112,&lt;span class="w"&gt; &lt;/span&gt;RF2413,&lt;span class="w"&gt; &lt;/span&gt;RF5413&lt;span class="o"&gt;)&lt;/span&gt;
cpu0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;motherboard
pcib0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Host&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;PCI&lt;span class="w"&gt; &lt;/span&gt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;pcibus&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;motherboard
pci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;PCI&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pcib0
ath0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Atheros&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5212&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0x80000000-0x8000ffff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
ath0:&lt;span class="w"&gt; &lt;/span&gt;Ethernet&lt;span class="w"&gt; &lt;/span&gt;address:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;:1b:b1:02:bf:0e
ath0:&lt;span class="w"&gt; &lt;/span&gt;mac&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;phy&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;radio&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.6
sis0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;NatSemi&lt;span class="w"&gt; &lt;/span&gt;DP8381&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;56&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;/100BaseTX&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x1000-0x10ff&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0x80040000-0x80040fff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
sis0:&lt;span class="w"&gt; &lt;/span&gt;Silicon&lt;span class="w"&gt; &lt;/span&gt;Revision:&lt;span class="w"&gt; &lt;/span&gt;DP83816A
miibus0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;MII&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;sis0
nsphyter0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;DP83815&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;/100&lt;span class="w"&gt; &lt;/span&gt;media&lt;span class="w"&gt; &lt;/span&gt;interface&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;miibus0
nsphyter0:&lt;span class="w"&gt;  &lt;/span&gt;10baseT,&lt;span class="w"&gt; &lt;/span&gt;10baseT-FDX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX-FDX,&lt;span class="w"&gt; &lt;/span&gt;auto
sis0:&lt;span class="w"&gt; &lt;/span&gt;Ethernet&lt;span class="w"&gt; &lt;/span&gt;address:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;:0d:b9:03:f1:74
sis1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;NatSemi&lt;span class="w"&gt; &lt;/span&gt;DP8381&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;56&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;/100BaseTX&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x1400-0x14ff&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0x80080000-0x80080fff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
sis1:&lt;span class="w"&gt; &lt;/span&gt;Silicon&lt;span class="w"&gt; &lt;/span&gt;Revision:&lt;span class="w"&gt; &lt;/span&gt;DP83816A
miibus1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;MII&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;sis1
nsphyter1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;DP83815&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;/100&lt;span class="w"&gt; &lt;/span&gt;media&lt;span class="w"&gt; &lt;/span&gt;interface&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;miibus1
nsphyter1:&lt;span class="w"&gt;  &lt;/span&gt;10baseT,&lt;span class="w"&gt; &lt;/span&gt;10baseT-FDX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX-FDX,&lt;span class="w"&gt; &lt;/span&gt;auto
sis1:&lt;span class="w"&gt; &lt;/span&gt;Ethernet&lt;span class="w"&gt; &lt;/span&gt;address:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;:0d:b9:03:f1:75
sis2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;NatSemi&lt;span class="w"&gt; &lt;/span&gt;DP8381&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;56&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;/100BaseTX&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x1800-0x18ff&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0x800c0000-0x800c0fff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
sis2:&lt;span class="w"&gt; &lt;/span&gt;Silicon&lt;span class="w"&gt; &lt;/span&gt;Revision:&lt;span class="w"&gt; &lt;/span&gt;DP83816A
miibus2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;MII&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;sis2
nsphyter2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;DP83815&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;/100&lt;span class="w"&gt; &lt;/span&gt;media&lt;span class="w"&gt; &lt;/span&gt;interface&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;miibus2
nsphyter2:&lt;span class="w"&gt;  &lt;/span&gt;10baseT,&lt;span class="w"&gt; &lt;/span&gt;10baseT-FDX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX-FDX,&lt;span class="w"&gt; &lt;/span&gt;auto
sis2:&lt;span class="w"&gt; &lt;/span&gt;Ethernet&lt;span class="w"&gt; &lt;/span&gt;address:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;:0d:b9:03:f1:76
Geode&lt;span class="w"&gt; &lt;/span&gt;PC&lt;span class="w"&gt; &lt;/span&gt;Engines&lt;span class="w"&gt; &lt;/span&gt;WRAP.1C/1D/1E&lt;span class="w"&gt; &lt;/span&gt;v1.tinyBIOS&lt;span class="w"&gt; &lt;/span&gt;V1.4a&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;C&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="m"&gt;1997&lt;/span&gt;-2005
isab0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;PCI-ISA&lt;span class="w"&gt; &lt;/span&gt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0xf400-0xf43f,0xf600-0xf63f&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
isa0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ISA&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isab0
pci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;driver&lt;span class="w"&gt; &lt;/span&gt;attached&lt;span class="o"&gt;)&lt;/span&gt;
atapci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;National&lt;span class="w"&gt; &lt;/span&gt;Geode&lt;span class="w"&gt; &lt;/span&gt;SC1100&lt;span class="w"&gt; &lt;/span&gt;ATA33&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x1f0-0x1f7,0x3f6,0x170-0x177,0x376,0xfc00-0xfc0f&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
ata0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATA&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;atapci0
ata1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATA&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;atapci0
pci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;multimedia,&lt;span class="w"&gt; &lt;/span&gt;audio&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;driver&lt;span class="w"&gt; &lt;/span&gt;attached&lt;span class="o"&gt;)&lt;/span&gt;
Timecounter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Geode&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;27000000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;
pci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.5&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;driver&lt;span class="w"&gt; &lt;/span&gt;attached&lt;span class="o"&gt;)&lt;/span&gt;
pmtimer0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
orm0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ISA&lt;span class="w"&gt; &lt;/span&gt;Option&lt;span class="w"&gt; &lt;/span&gt;ROM&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;iomem&lt;span class="w"&gt; &lt;/span&gt;0xe0000-0xe7fff&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
sio0&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x3f8-0x3ff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flags&lt;span class="w"&gt; &lt;/span&gt;0x10&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
sio0:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;16550A,&lt;span class="w"&gt; &lt;/span&gt;console
sio1:&lt;span class="w"&gt; &lt;/span&gt;configured&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bitmap&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;probed&lt;span class="w"&gt; &lt;/span&gt;irqs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
sio1:&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;may&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;enabled
RTC&lt;span class="w"&gt; &lt;/span&gt;BIOS&lt;span class="w"&gt; &lt;/span&gt;diagnostic&lt;span class="w"&gt; &lt;/span&gt;error&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&amp;lt;clock_battery&amp;gt;
Timecounters&lt;span class="w"&gt; &lt;/span&gt;tick&lt;span class="w"&gt; &lt;/span&gt;every&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.000&lt;span class="w"&gt; &lt;/span&gt;msec
Fast&lt;span class="w"&gt; &lt;/span&gt;IPsec:&lt;span class="w"&gt; &lt;/span&gt;Initialized&lt;span class="w"&gt; &lt;/span&gt;Security&lt;span class="w"&gt; &lt;/span&gt;Association&lt;span class="w"&gt; &lt;/span&gt;Processing.
IP&lt;span class="w"&gt; &lt;/span&gt;Filter:&lt;span class="w"&gt; &lt;/span&gt;v4.1.33&lt;span class="w"&gt; &lt;/span&gt;initialized.&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;block&lt;span class="w"&gt; &lt;/span&gt;all,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Logging&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;enabled
md0:&lt;span class="w"&gt; &lt;/span&gt;Preloaded&lt;span class="w"&gt; &lt;/span&gt;image&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;/mfsroot&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16777216&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bytes&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;0xc086b0e8
ad0:&lt;span class="w"&gt; &lt;/span&gt;FAILURE&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;SETFEATURES&lt;span class="w"&gt; &lt;/span&gt;SET&lt;span class="w"&gt; &lt;/span&gt;TRANSFER&lt;span class="w"&gt; &lt;/span&gt;MODE&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;51&lt;/span&gt;&amp;lt;READY,DSC,ERROR&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&amp;lt;ABORTED&amp;gt;
ad0:&lt;span class="w"&gt; &lt;/span&gt;61MB&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Flash&lt;span class="w"&gt; &lt;/span&gt;Card&lt;span class="w"&gt; &lt;/span&gt;2N2-1205&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;ata0-master&lt;span class="w"&gt; &lt;/span&gt;BIOSPIO
Trying&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;ufs:/dev/md0
kern.coredump:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
Found&lt;span class="w"&gt; &lt;/span&gt;configuration&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ad0.
sis0:&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;state&lt;span class="w"&gt; &lt;/span&gt;changed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;DOWN
sis1:&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;state&lt;span class="w"&gt; &lt;/span&gt;changed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;DOWN
sis2:&lt;span class="w"&gt; &lt;/span&gt;link&lt;span class="w"&gt; &lt;/span&gt;state&lt;span class="w"&gt; &lt;/span&gt;changed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;DOWN
Initializing&lt;span class="w"&gt; &lt;/span&gt;timezone...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Configuring&lt;span class="w"&gt; &lt;/span&gt;firewall...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Configuring&lt;span class="w"&gt; &lt;/span&gt;LAN&lt;span class="w"&gt; &lt;/span&gt;interface...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Configuring&lt;span class="w"&gt; &lt;/span&gt;WAN&lt;span class="w"&gt; &lt;/span&gt;interface...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Starting&lt;span class="w"&gt; &lt;/span&gt;syslog&lt;span class="w"&gt; &lt;/span&gt;service...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Starting&lt;span class="w"&gt; &lt;/span&gt;webGUI...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Starting&lt;span class="w"&gt; &lt;/span&gt;DNS&lt;span class="w"&gt; &lt;/span&gt;forwarder...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Starting&lt;span class="w"&gt; &lt;/span&gt;DHCP&lt;span class="w"&gt; &lt;/span&gt;service...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
Starting&lt;span class="w"&gt; &lt;/span&gt;NTP&lt;span class="w"&gt; &lt;/span&gt;client...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;


***&lt;span class="w"&gt; &lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;m0n0wall,&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.33
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hope this helps some lost cave deweller&amp;nbsp;somewhere.&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;</content><category term="freebsd"></category><category term="FreeBSD"></category></entry><entry><title>FreeBSD 11 on the Acer Aspire One ZG5</title><link href="https://www.executionunit.com/blog/2017/08/19/freebsd-11-on-the-acer-aspire-one-zg5/" rel="alternate"></link><published>2017-08-19T10:20:00+01:00</published><updated>2017-08-19T19:30:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2017-08-19:/blog/2017/08/19/freebsd-11-on-the-acer-aspire-one-zg5/</id><summary type="html">&lt;p&gt;For no reason other than boredom I bought an Acer Aspire One &lt;span class="caps"&gt;ZG5&lt;/span&gt; notebook for £30 on ebay. I wanted to install &lt;a href="https://www.freebsd.org/"&gt;FreeBSD&lt;/a&gt; on it and with and little &lt;a href="https://wiki.freebsd.org/Laptops/Acer_AspireOne_ZG5"&gt;google-fu&lt;/a&gt; I checked that it was indeed &lt;em&gt;compatible&lt;/em&gt; with FreeBSD 11. Auction ended, off I go installing the best &lt;span class="caps"&gt;OS&lt;/span&gt; in …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For no reason other than boredom I bought an Acer Aspire One &lt;span class="caps"&gt;ZG5&lt;/span&gt; notebook for £30 on ebay. I wanted to install &lt;a href="https://www.freebsd.org/"&gt;FreeBSD&lt;/a&gt; on it and with and little &lt;a href="https://wiki.freebsd.org/Laptops/Acer_AspireOne_ZG5"&gt;google-fu&lt;/a&gt; I checked that it was indeed &lt;em&gt;compatible&lt;/em&gt; with FreeBSD 11. Auction ended, off I go installing the best &lt;span class="caps"&gt;OS&lt;/span&gt; in the&amp;nbsp;world!&lt;/p&gt;
&lt;h2 id="to-the-desktop"&gt;To The&amp;nbsp;Desktop!&lt;/h2&gt;
&lt;p&gt;Installation from a &lt;span class="caps"&gt;USB&lt;/span&gt; stick went without hitch. I then largely followed the excellent guide&lt;a href="https://cooltrainer.org/a-freebsd-desktop-howto/"&gt; here&lt;/a&gt; to get the machine to a reasonable desktop state in about 30 minutes using &lt;a href="https://wiki.freebsd.org/pkgng"&gt;pkg&lt;/a&gt;. I went with the more lightweight &lt;span class="caps"&gt;XFCE&lt;/span&gt; desktop and the little Atom &lt;span class="caps"&gt;CPU&lt;/span&gt; seems to run it just fine. I initially intended to run &lt;a href="http://windowmaker.org"&gt;Window Maker&lt;/a&gt; for that good old NeXT feeling but after a while I had to admit that there were a lot of packages that were not supported by the FreeBSD ports team and I needed something a little more complete. Window Maker ran really really fast though so I wish I had the time to upgrade the packages or even become the pkg maintainer for the FreeBSD&amp;nbsp;project.&lt;/p&gt;
&lt;h2 id="system-tweakssettings"&gt;System&amp;nbsp;Tweaks/Settings&lt;/h2&gt;
&lt;p&gt;I added the following tweaks to &lt;code&gt;/etc/sysctl.conf&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;hw.usb.no_shutdown_wait&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
hw.sdhci.enable_msi&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
hw.acpi.lid_switch_state&lt;span class="o"&gt;=&lt;/span&gt;s3
hint.apic.0.disabled&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately &lt;code&gt;hw.sdhci.enable_msi&lt;/code&gt; doesn&amp;#8217;t make the &lt;span class="caps"&gt;SD&lt;/span&gt; Card reader work but it does stop a storm of messages about the controller timing out if someone does insert an &lt;span class="caps"&gt;SD&lt;/span&gt;&amp;nbsp;Card.&lt;/p&gt;
&lt;p&gt;The default lid state &lt;code&gt;hw.acpi.lid_switch_state&lt;/code&gt; was &lt;code&gt;None&lt;/code&gt; so I changed the to &lt;code&gt;s3&lt;/code&gt;. On closing the lid the machine went to sleep but upon opening the lid the machine crashed or best case  the screen stayed black. Setting &lt;code&gt;hint.apic.0.disabled&lt;/code&gt; and adding &lt;code&gt;acpi_video_load="YES"&lt;/code&gt; to &lt;code&gt;/etc/rc.conf&lt;/code&gt; seemed to fix it but I am not sure why. There is a lot of black magic around the buggy drivers/&lt;span class="caps"&gt;BIOS&lt;/span&gt;/microcode for &lt;span class="caps"&gt;ACPI&lt;/span&gt; compliant&amp;nbsp;hardware.&lt;/p&gt;
&lt;p&gt;I added the following to &lt;code&gt;/etc/rc.conf&lt;/code&gt; to load the Intel driver and to get the acpi subsystem to work with the&amp;nbsp;screen.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;i915kms_load&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;YES&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The webcam didn&amp;#8217;t work out of the box, to get the system to recognise it I install webcamd and added&amp;nbsp;this&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;webcamd_enable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;YES&amp;quot;&lt;/span&gt;
&lt;span class="nv"&gt;webcamd_0_flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-N Sonix-Technology-Co---Ltd--USB-2-0-Camera -S unknown -M 0&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;to &lt;code&gt;/etc/rc.conf&lt;/code&gt; restarted &lt;code&gt;devd&lt;/code&gt; and used &lt;code&gt;pwcview&lt;/code&gt; to preview the glorious 320x240 video it generated at about 15fps. I commented out the settings in rc.conf in the end. Who wants a webcam that&amp;nbsp;bad!&lt;/p&gt;
&lt;h2 id="xrandr-external-monitors"&gt;Xrandr - External&amp;nbsp;Monitors&lt;/h2&gt;
&lt;p&gt;Setting up an external display worked with two of my spare monitors. An &lt;span class="caps"&gt;NEC&lt;/span&gt; 17&amp;#8221; and an &lt;span class="caps"&gt;LG&lt;/span&gt; (Goldstar) 22&amp;#8221;. Pretty seamless as&amp;nbsp;well. &lt;/p&gt;
&lt;p&gt;&lt;img alt="NEC 17 working" src="https://www.executionunit.com/static/media/uploads/blog/acernetbook/xrandr_working.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="LG 22 Working" src="https://www.executionunit.com/static/media/uploads/blog/acernetbook/xrandr_working2.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Whole Desktop" src="https://www.executionunit.com/static/media/uploads/blog/acernetbook/desktop.jpg"&gt;
&lt;em&gt;The two desktops, one placed below the&amp;nbsp;other.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="stripped-down-apps"&gt;Stripped down&amp;nbsp;apps&lt;/h2&gt;
&lt;p&gt;The Aspire One isn&amp;#8217;t powerful enough to run a full browser like &lt;code&gt;Firefox&lt;/code&gt; or &lt;code&gt;Chromium&lt;/code&gt; so I installed &lt;code&gt;Midori&lt;/code&gt; for web browsing. Midori uses about one third of the memory and renders nearly all pages I go to. For email Thunderbird was just as heavy weight as Firefox so I installed &lt;code&gt;Claws Mail&lt;/code&gt; for &lt;span class="caps"&gt;IMAP&lt;/span&gt; mail access. I actually use &lt;code&gt;Mutt&lt;/code&gt; with some custom commands but a lot of email comes through as &lt;span class="caps"&gt;HTML&lt;/span&gt; only and it can get annoying reading it in&amp;nbsp;Mutt.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall the installation went very smoothly, no crashes but of course a lot of tweaking needed to be done especially around sleep states and the&amp;nbsp;peripherals.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;FYI&lt;/span&gt; I am running this version of&amp;nbsp;FreeBSD11&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;uname&lt;span class="w"&gt; &lt;/span&gt;-a
FreeBSD&lt;span class="w"&gt; &lt;/span&gt;mitch&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;.1-RELEASE-p1&lt;span class="w"&gt; &lt;/span&gt;FreeBSD&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;.1-RELEASE-p1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0: Wed Aug  9 11:17:49 UTC 2017     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  i386&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Overall I&amp;#8217;m really happy with the little netbook. It&amp;#8217;s very light, I spent £30 on the pristine notebook, £8 on another &lt;span class="caps"&gt;GB&lt;/span&gt; of memory to max it at a whopping 1.&lt;span class="caps"&gt;5GB&lt;/span&gt; of &lt;span class="caps"&gt;RAM&lt;/span&gt; and £10 on a battery that gives it about four hours of reasonable&amp;nbsp;use.&lt;/p&gt;
&lt;p&gt;If an &lt;span class="caps"&gt;SSD&lt;/span&gt; becomes free from one of my other machines I&amp;#8217;ll pop that in but it&amp;#8217;s not worth buying an &lt;span class="caps"&gt;SSD&lt;/span&gt; for this machine at the moment. It&amp;#8217;s fine with it&amp;#8217;s &lt;span class="caps"&gt;120GB&lt;/span&gt; &lt;span class="caps"&gt;5400RPM&lt;/span&gt;&amp;nbsp;drive.&lt;/p&gt;
&lt;p&gt;The only downside I can see at the moment is that the fan is a little noisy. I&amp;#8217;m not sure how to fix that. I could replace the fan but all small fans have a high pitch whine. I&amp;#8217;ve eneabled powerd and I can see that the &lt;span class="caps"&gt;CPU&lt;/span&gt; is being slowed down so I guess I&amp;#8217;ll have to live with&amp;nbsp;it&lt;/p&gt;
&lt;p&gt;&lt;img alt="It's real and small" src="https://www.executionunit.com/static/media/uploads/blog/acernetbook/realmachine.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Hope this helps someone else who wants a small, cheap, light weight almost throw away&amp;nbsp;laptop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 171226&lt;/strong&gt; - Turns out installing &lt;a href="https://www.freshports.org/sysutils/acerhdf-kmod/"&gt;AcerHDF-kmod&lt;/a&gt; fixes the noisy fan which makes a &lt;span class="caps"&gt;HUGE&lt;/span&gt;&amp;nbsp;difference.&lt;/p&gt;
&lt;p&gt;dazza.&lt;/p&gt;</content><category term="freebsd"></category><category term="FreeBSD"></category></entry><entry><title>In Defence of Writing Your Own Engine</title><link href="https://www.executionunit.com/blog/2017/07/14/in-defence-of-writing-your-own-engine/" rel="alternate"></link><published>2017-07-14T00:00:00+01:00</published><updated>2017-07-14T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2017-07-14:/blog/2017/07/14/in-defence-of-writing-your-own-engine/</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;Here&amp;#8217;s to the crazy ones, the misfits, the trouble makers, &lt;strong&gt;the engine-eers!&lt;/strong&gt; -&amp;nbsp;dazza&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://www.executionunit.com/static/media/uploads/blog/icon_01_type_04.jpg"/ style="width:128px;float:left;margin-right: 1em;margin-bottom:1em;"&gt;&lt;/p&gt;
&lt;p&gt;After reading this excellent &lt;a href="http://www.zeroequalsfalse.press/2017/07/12/engine/"&gt;blog&lt;/a&gt; from ZeroEqualsFalse I thought I&amp;#8217;d counter with a defence for writing and deploying your own&amp;nbsp;engine.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been writing &amp;#8220;engines&amp;#8221; for 20 years both professionally and for fun. I …&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;Here&amp;#8217;s to the crazy ones, the misfits, the trouble makers, &lt;strong&gt;the engine-eers!&lt;/strong&gt; -&amp;nbsp;dazza&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://www.executionunit.com/static/media/uploads/blog/icon_01_type_04.jpg"/ style="width:128px;float:left;margin-right: 1em;margin-bottom:1em;"&gt;&lt;/p&gt;
&lt;p&gt;After reading this excellent &lt;a href="http://www.zeroequalsfalse.press/2017/07/12/engine/"&gt;blog&lt;/a&gt; from ZeroEqualsFalse I thought I&amp;#8217;d counter with a defence for writing and deploying your own&amp;nbsp;engine.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been writing &amp;#8220;engines&amp;#8221; for 20 years both professionally and for fun. I am in no way a Carmack and I am under no illusion that I can compete with all of Unreal or Unity on all fronts&amp;nbsp;but&amp;#8230;&lt;/p&gt;
&lt;div style="clear:left;"&gt;&lt;/div&gt;

&lt;h2 id="pushing-it"&gt;Pushing&amp;nbsp;it&lt;/h2&gt;
&lt;p&gt;If your game is in any way pushing the limits you can&amp;#8217;t stick with Unity and often even Unreal is not ideal. For Smith and Winston we need to regenerate detailed visible and collision meshes &lt;span class="caps"&gt;VERY&lt;/span&gt; quickly as the player can destroy nearly anything in the&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;We prototyped the game in Unity but it had slow mesh creation times and quite frankly shockingly bad collision mesh insertion times. By writing our own engine we managed to get orders of magnitude speed increases over Unity and about 10% faster than Unreal. Write a plugin you say! There you go assuming most of the speed boost didn&amp;#8217;t come from not working through multiple layers of abstraction that general engines necessarily&amp;nbsp;have.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This may have changed now, I see there are some excellent voxel plugins both Unity and Unreal but my point still stands in&amp;nbsp;general.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="its-part-of-the-fun"&gt;It&amp;#8217;s part of the&amp;nbsp;fun&lt;/h2&gt;
&lt;p&gt;Part of what attracted me to making games was the tech side. There are loads of people who have been &lt;em&gt;enabled&lt;/em&gt; to make games because the bar has been lowered and this is a great thing but there are many people like me that love the tech, love the challenge, love the low level, love the bus speed usage, love the lack of memory fragmentation, love the aligned cache access, love the parallel thread usage &lt;strong&gt;as well as love making games&lt;/strong&gt;. If you&amp;#8217;re one of them go for&amp;nbsp;it!&lt;/p&gt;
&lt;h2 id="we-need-skills"&gt;We need&amp;nbsp;skills&lt;/h2&gt;
&lt;p&gt;ZeroEqualsFalse make an excellent point that writing an engine is a great learning experience. You&amp;#8217;ll only really understand engines by writing one. They all have their own quirks, good points and bad points. But why would you waste your time writing an engine when Unity and Unreal are quite frankly great engines? As an industry we need these skillz to be honed and we need people that understand how to finish an engine as well as a&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;Taking an engine to market, getting it through &lt;span class="caps"&gt;QA&lt;/span&gt;, &lt;span class="caps"&gt;TRC&lt;/span&gt;, localisation and deploying it on a myriad of platforms is a valuable skill and a skill that is rapidly disappearing. During the &amp;#8220;democratisation of game making&amp;#8221; that has been going on for the last 10 years people have been actively discouraged from learning these valuable skills. Someone has to write the bloody engines of the&amp;nbsp;future!&lt;/p&gt;
&lt;h2 id="plurality"&gt;Plurality&lt;/h2&gt;
&lt;p&gt;It&amp;#8217;s quite frankly not healthy for our industry that there are two dominant engines (Unity and Unreal). There are other great engines (Godot being a great example) that are largely pushed to the margins. The industry already suffers from Autodesk dominating the creation pipeline with Maya and 3DSMax. At some point one of those engines will collapse under it&amp;#8217;s own weight, competition or market forces. This will leave a huge hole in the&amp;nbsp;scene.&lt;/p&gt;
&lt;h2 id="its-actually-not-that-hard"&gt;Its actually &amp;#8216;not that&amp;nbsp;hard&amp;#8217;&amp;#8230;&lt;/h2&gt;
&lt;p&gt;but &lt;em&gt;can be&lt;/em&gt; time consuming. 20 years ago when I wrote my first engine (as opposed to just a game) every single line of code was mine. It had custom string, vector, matrix, model, collision, physics, sound, rasteriser, input&amp;#8230; you get the point. I wrote it all in C and &amp;#8220;C with&amp;nbsp;classes&amp;#8221;! &lt;/p&gt;
&lt;p&gt;Nowadays you really don&amp;#8217;t want to be doing that and you don&amp;#8217;t need to! Here are the libraries that I use in the Smith and Winston&amp;nbsp;codebase&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.volumesoffun.com/polyvox-about/"&gt;PolyVox&lt;/a&gt; - excellent voxel library, I didn&amp;#8217;t even write the voxel&amp;nbsp;code!&lt;/li&gt;
&lt;li&gt;&lt;a href="http://bulletphysics.org/wordpress/"&gt;Bullet&lt;/a&gt; - world class physics (soft and rigid) and collision&amp;nbsp;library&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bkaradzic/bgfx"&gt;&lt;span class="caps"&gt;BGFX&lt;/span&gt;&lt;/a&gt; - world class low overhead rendering &lt;span class="caps"&gt;API&lt;/span&gt; with &lt;span class="caps"&gt;DX9&lt;/span&gt;/11/12, OpenGL, Vulkan and Metal&amp;nbsp;backends.&lt;/li&gt;
&lt;li&gt;C++11/&lt;span class="caps"&gt;STL&lt;/span&gt; - night and day compared to old C++. Basically cross platform code is way easier to write now with &lt;span class="caps"&gt;MSVC&lt;/span&gt;/&lt;span class="caps"&gt;GCC&lt;/span&gt; and&amp;nbsp;Clang.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cmake.org/"&gt;CMake&lt;/a&gt; - meta makefiles system that&amp;#8217;s arcane but makes cross platform project management so much&amp;nbsp;easier.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://opensteer.sourceforge.net/"&gt;OpenSteer&lt;/a&gt; - navigation library (bit dated but very&amp;nbsp;usable)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://glm.g-truc.net/0.9.5/index.html"&gt;&lt;span class="caps"&gt;GLM&lt;/span&gt;&lt;/a&gt; - video game maths and maths utility library. Apes the &lt;span class="caps"&gt;GLSL&lt;/span&gt;&amp;nbsp;syntax.&lt;/li&gt;
&lt;li&gt;LibZlib/lz4 - open, free and very&amp;nbsp;squashy.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.libsdl.org/"&gt;&lt;span class="caps"&gt;SDL&lt;/span&gt;&lt;/a&gt; - input, windows, sound, back&amp;nbsp;massages&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.fmod.com/"&gt;&lt;span class="caps"&gt;FMOD&lt;/span&gt;&lt;/a&gt; - For all your sound needs &lt;span class="caps"&gt;OK&lt;/span&gt;, it&amp;#8217;s not &amp;#8216;free&amp;#8217;. But it is &lt;em&gt;basically free&lt;/em&gt; for all indie games and it&amp;#8217;s amazingly good. It took two days to integrate in to my&amp;nbsp;codebase!&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.lua.org/"&gt;Lua&lt;/a&gt;/&lt;a href="http://luajit.org/"&gt;LuaJIT&lt;/a&gt; - you are not going to get a language as fast and expressive as Lua that fits in &amp;lt; &lt;span class="caps"&gt;1MB&lt;/span&gt; of memory. Scripting for&amp;nbsp;grownups!&lt;/li&gt;
&lt;li&gt;stb_* great collection of &lt;a href="https://github.com/nothings/stb"&gt;utility functions/classes&lt;/a&gt; by Sean&amp;nbsp;Barret&lt;/li&gt;
&lt;li&gt;&lt;em&gt;plus countless other small bits and&amp;nbsp;bobs&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Essentially &lt;em&gt;my&lt;/em&gt; engine is really just the glue between all of these off the shelf, highly polished and stable&amp;nbsp;libraries.&lt;/p&gt;
&lt;p&gt;For an editor just use Qt/WxWidgets or Mono. Integrate your engine with it and you&amp;#8217;re most of the way to having a very usable&amp;nbsp;editor.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You&amp;#8217;re not really writing my own engine because you&amp;#8217;re using all these great&amp;nbsp;components.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Well if that&amp;#8217;s true you&amp;#8217;re not making sprites unless you&amp;#8217;re typing in &lt;span class="caps"&gt;HEX&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="to-conclude"&gt;To&amp;nbsp;conclude&lt;/h2&gt;
&lt;p&gt;So it&amp;#8217;s not for everyone and it&amp;#8217;s great that more people can create all the varied games that we see and love but don&amp;#8217;t discourage the future Carmacks of the world. &lt;em&gt;&lt;span class="caps"&gt;GO&lt;/span&gt; &lt;span class="caps"&gt;FOR&lt;/span&gt; &lt;span class="caps"&gt;IT&lt;/span&gt;&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Whatever and how ever you decide to progress, be excellent to each other and &lt;span class="caps"&gt;PARTY&lt;/span&gt; &lt;span class="caps"&gt;ON&lt;/span&gt;, &lt;span class="caps"&gt;DUDES&lt;/span&gt;!.&lt;/p&gt;
&lt;p&gt;have fun,&amp;nbsp;dazza&lt;/p&gt;
&lt;p&gt;&lt;em&gt;updates&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;170723 - added facebook&amp;nbsp;link&lt;/li&gt;
&lt;li&gt;170723 - added links to the libs I mentioned as that&amp;#8217;s how the internet is supposed to&amp;nbsp;work.&lt;/li&gt;
&lt;li&gt;170720 - This post generated an interesting discussion on &lt;a href="https://redd.it/6n8k04"&gt;Reddit&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;220930 - removed links to smith and winston that are&amp;nbsp;dead.&lt;/li&gt;
&lt;/ul&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category><category term="Lua"></category></entry><entry><title>How to stick at it: Three years and still going strong!</title><link href="https://www.executionunit.com/blog/2017/07/11/how-to-stick-at-it/" rel="alternate"></link><published>2017-07-11T00:00:00+01:00</published><updated>2017-07-11T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2017-07-11:/blog/2017/07/11/how-to-stick-at-it/</id><summary type="html">&lt;p&gt;&lt;img src="https://www.executionunit.com/static/media/uploads/blog/sub1.jpg" style="float:left;width:200px" /&gt;
To celebrate (and commiserate) the fact that I&amp;#8217;ve been working on &lt;a href="http://www.smithandwinston.com"&gt;Smith and Winston&lt;/a&gt; for three years I thought I&amp;#8217;d answer the most commonly asked question: &lt;em&gt;How do you stick at it for so long&lt;/em&gt;? Some of this applies to anything in life, but it&amp;#8217;s mostly about …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img src="https://www.executionunit.com/static/media/uploads/blog/sub1.jpg" style="float:left;width:200px" /&gt;
To celebrate (and commiserate) the fact that I&amp;#8217;ve been working on &lt;a href="http://www.smithandwinston.com"&gt;Smith and Winston&lt;/a&gt; for three years I thought I&amp;#8217;d answer the most commonly asked question: &lt;em&gt;How do you stick at it for so long&lt;/em&gt;? Some of this applies to anything in life, but it&amp;#8217;s mostly about making games as that&amp;#8217;s all I&amp;nbsp;do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;TL&lt;/span&gt;;&lt;span class="caps"&gt;DR&lt;/span&gt;&lt;/strong&gt;: No one has a magic bullet, no one is especially driven, no one has an easy ride, it&amp;#8217;s all about hard work and&amp;nbsp;sacrifice.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The movies are only there to show how awesome Smith and Winston is, you can ignore them&amp;nbsp;;)&lt;/em&gt;&lt;/p&gt;
&lt;div style="clear:left;"&gt;&lt;/div&gt;

&lt;h2 id="stubbornness"&gt;Stubbornness&lt;/h2&gt;
&lt;p&gt;Firstly you&amp;#8217;ve got to be little bit stubborn. Life is full of distractions and you need to be able to park new ideas, new experiences and sometimes friends to focus on  your goal. Telling people you love that you need to sit on your own for hours on end doing something they don&amp;#8217;t understand is hard. For me it&amp;#8217;s easy because quite frankly I&amp;#8217;m stubborn and maybe selfish&amp;nbsp;but&amp;#8230;&lt;/p&gt;
&lt;h2 id="sacrifice"&gt;Sacrifice&lt;/h2&gt;
&lt;p&gt;Something has to give and anything worth doing comes at a cost. Whether it&amp;#8217;s money, time, relationships or health it&amp;#8217;s all going to come under strain. Balancing these things is probably the biggest challenge. &lt;strong&gt;Never sacrifice health&lt;/strong&gt;, money is easy to sacrifice to a point and sometimes you have to accept relationships are either not supportive of your goal or too expensive to maintain. Whatever you do, understand what you&amp;#8217;re sacrificing and make sure you understand the cost/gain ratio. Sometimes it&amp;#8217;s better to sacrifice the project totally and move&amp;nbsp;on.&lt;/p&gt;
&lt;div style='position:relative;padding-bottom:calc(100% / 1.78)'&gt;&lt;iframe src='https://gfycat.com/ifr/TanScarceBillygoat' frameborder='0' scrolling='no' width='100%' height='100%' style='position:absolute;top:0;left:0;' allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;h2 id="routine"&gt;Routine&lt;/h2&gt;
&lt;p&gt;It doesn&amp;#8217;t matter how driven you are: &lt;strong&gt;every day you don&amp;#8217;t do something you are one step closer to never doing it again&lt;/strong&gt;. It&amp;#8217;s inspiration and excitement that starts a project but it&amp;#8217;s discipline and hard work that finishes it. The initial excitement dissipates all too quickly and you are left with the long slog. No one is exempt from&amp;nbsp;this.&lt;/p&gt;
&lt;h2 id="time"&gt;Time&lt;/h2&gt;
&lt;p&gt;Time is indeed a cruel mistress. You need to work effectively to make progress. Install &lt;a href="https://www.rescuetime.com/"&gt;Rescue Time&lt;/a&gt; and learn how &lt;em&gt;you&lt;/em&gt; work. Balance this with the fact that &lt;strong&gt;you are not a machine&lt;/strong&gt;. Rescue Time will tell you when you are not working effectively. Learn why, if you&amp;#8217;re bored shift to something more interesting that needs doing but don&amp;#8217;t forget to complete the boring thing. If you&amp;#8217;re tired then take a nap and come back. If you&amp;#8217;re totally lacking inspiration take time off, play some games, get inspired. Come back. &lt;strong&gt;Sometimes you just need for force yourself to work&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="nurture-the-initial-spark"&gt;Nurture the initial&amp;nbsp;spark&lt;/h2&gt;
&lt;p&gt;Smith and Winston was inspired by memories of playing Ikari Warriors on my Commodore 64. We&amp;#8217;d just canned our previous game, I took a few weeks off and was seriously considering going to work for megacorp to make mucho-dinero. Replaying Ikari Warriors totally rejuvenated my energy for making games. I go back to it frequently to remind me why I started this marathon. &lt;strong&gt;Don&amp;#8217;t expect every day to be fun. It won&amp;#8217;t be.&lt;/strong&gt; Famously the &lt;a href="https://en.wikipedia.org/wiki/Ninety-ninety_rule"&gt;last 10%&lt;/a&gt; of any project takes 90% of the time and it&amp;#8217;s mostly not fun. Remember the initial spark and be stubborn. Never forget to stop&amp;nbsp;playing.&lt;/p&gt;
&lt;h2 id="understanding-criticism"&gt;Understanding&amp;nbsp;criticism&lt;/h2&gt;
&lt;p&gt;As soon as people close to you know you&amp;#8217;re doing something off the beaten track they will offer support and criticism. Both are vital but both are double&amp;nbsp;edged.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You need to see all unsolicitied comments through the prism of the person making it&lt;/strong&gt;. Not everyone has your best interests at heart and some people (hello mum) can&amp;#8217;t see anything bad in you. Everyone&amp;#8217;s opinion is valid and should be considered but some are &amp;#8220;more&amp;nbsp;valid&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Learning to take it professionally and &lt;span class="caps"&gt;NOT&lt;/span&gt; personally is something even the longest, greyest beards of the games industry are still learning to&amp;nbsp;do.&lt;/p&gt;
&lt;h2 id="orders-of-magnitude"&gt;Orders of&amp;nbsp;magnitude&lt;/h2&gt;
&lt;p&gt;A player might get 100 hours of gameplay from your game (if it&amp;#8217;s huge or repetative) but you will see your game for thousands of hours and it will look boring stale and repetitive. Resist the urge to change, revise and upgrade constantly. &lt;strong&gt;Always seek to cut and hone&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="seeking-constant-resssurance"&gt;Seeking constant&amp;nbsp;resssurance&lt;/h2&gt;
&lt;p&gt;If you rely on constant reassurance from your peers you&amp;#8217;ll hit the rocks. People spend a lot of their time and energy blogging every little detail and live streaming. This offers instant reward for minimal effort. &lt;strong&gt;You need to reward true effort to sustain yourself&lt;/strong&gt;. There is a lot to be said for building up the resillience of the lonely artist working through problems without the safety net of your peers holding your hands. &lt;em&gt;They&lt;/em&gt; won&amp;#8217;t always be there but &lt;em&gt;you&lt;/em&gt; always will&amp;nbsp;be.&lt;/p&gt;
&lt;div style='position:relative;padding-bottom:calc(100% / 1.78)'&gt;&lt;iframe src='https://gfycat.com/ifr/ScalyImaginativeDrever' frameborder='0' scrolling='no' width='100%' height='100%' style='position:absolute;top:0;left:0;' allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;This is my game &lt;a href="http://www.smithandwinston.com"&gt;Smith and Winston&lt;/a&gt;, it&amp;#8217;s&amp;nbsp;awesome&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;updates&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;170723 - added link to Smith and Winston below&amp;nbsp;gif.&lt;/li&gt;
&lt;li&gt;170723 - changed title from &amp;#8220;Three Year and Still Going Strong&amp;#8221; to &amp;#8220;How to Stick at it: Three Year and Still Going Strong&amp;#8221; to make it more&amp;nbsp;clear.&lt;/li&gt;
&lt;/ul&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Smith and Winston Alpha 4</title><link href="https://www.executionunit.com/blog/2016/08/03/smith-and-winston-alpha-4/" rel="alternate"></link><published>2016-08-03T00:00:00+01:00</published><updated>2016-08-03T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2016-08-03:/blog/2016/08/03/smith-and-winston-alpha-4/</id><summary type="html">&lt;h2 id="9-months"&gt;9&amp;nbsp;months!&lt;/h2&gt;
&lt;p&gt;It&amp;#8217;s been nine months since the last video update. Of course we&amp;#8217;ve been busy working on Smith and Winston. Here is the latest&amp;nbsp;video:&lt;/p&gt;
&lt;iframe width="800" height="450" src="https://www.youtube.com/embed/Weza0mqeEL8" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;We&amp;#8217;ve&amp;nbsp;added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Depth of field effect to soften the distant&amp;nbsp;voxels.&lt;/li&gt;
&lt;li&gt;Complete change of enemy and weapon strategy to bring the …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;h2 id="9-months"&gt;9&amp;nbsp;months!&lt;/h2&gt;
&lt;p&gt;It&amp;#8217;s been nine months since the last video update. Of course we&amp;#8217;ve been busy working on Smith and Winston. Here is the latest&amp;nbsp;video:&lt;/p&gt;
&lt;iframe width="800" height="450" src="https://www.youtube.com/embed/Weza0mqeEL8" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;We&amp;#8217;ve&amp;nbsp;added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Depth of field effect to soften the distant&amp;nbsp;voxels.&lt;/li&gt;
&lt;li&gt;Complete change of enemy and weapon strategy to bring the combat closer to the&amp;nbsp;player.&lt;/li&gt;
&lt;li&gt;Weapons: You now get a pea shooter, sub machine gun, rocket launcher and assault rifle as well as your trusty&amp;nbsp;grenades.&lt;/li&gt;
&lt;li&gt;Enemies throw&amp;nbsp;grenades.&lt;/li&gt;
&lt;li&gt;Island level&amp;nbsp;design.&lt;/li&gt;
&lt;li&gt;Skybox with cubey voxel&amp;nbsp;goodness.&lt;/li&gt;
&lt;li&gt;Clouds!&lt;/li&gt;
&lt;li&gt;Many more particle effects on explosions, birds, butterflys and&amp;nbsp;flowers.&lt;/li&gt;
&lt;li&gt;A more functional if still not very pretty &lt;span class="caps"&gt;HUD&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;A front end (you don&amp;#8217;t know how nice it is to have a front&amp;nbsp;end!)&lt;/li&gt;
&lt;li&gt;removed nearly &lt;span class="caps"&gt;1GB&lt;/span&gt; of memory&amp;nbsp;leaks!&lt;/li&gt;
&lt;li&gt;2 player co-op&amp;nbsp;working&lt;/li&gt;
&lt;li&gt;Explosions cause&amp;nbsp;explosions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="island-level-design"&gt;Island Level&amp;nbsp;Design&lt;/h2&gt;
&lt;p&gt;With the previous monolithic level design we were finding it really time consuming balancing the levels. If we wanted to change the structure of the level it took a long time to copy and paste the voxels about. Now we can move the islands around and add bridges trivially. This is a big win for a two person&amp;nbsp;team.&lt;/p&gt;
&lt;p&gt;Another problem we&amp;#8217;ve had is on low end machines the monolithic levels were too expensive to modify during explosions. One of the downsides of voxels is that they can take a lot of memory to store and slow machines crawled modifying the voxels, rebuilding the models and collision meshes. Monolithic levels were also taking up 1.&lt;span class="caps"&gt;5GB&lt;/span&gt; of memory. Our new levels take up about 0.&lt;span class="caps"&gt;8GB&lt;/span&gt; helping out the lower end&amp;nbsp;machines.&lt;/p&gt;
&lt;h2 id="networking-folly"&gt;Networking&amp;nbsp;Folly.&lt;/h2&gt;
&lt;p&gt;I spent about six months adding networking to our codebase and in the end it was a failure. I didn&amp;#8217;t have enough experience to pull it off and despite it &amp;#8216;working&amp;#8217; on a &lt;span class="caps"&gt;LAN&lt;/span&gt; it was too dodgy for public consumption. This doesn&amp;#8217;t mean it&amp;#8217;s abandoned but it wont be added until after the game is released or maybe Smith and Winston 2. Replicating all the damage the player makes to the voxel world and keeping everyone in sync proved to be too much for my small brain to cope with :( The upside is that I&amp;#8217;m making progress on the actual game play&amp;nbsp;now.&lt;/p&gt;
&lt;h2 id="two-player-is-great-fun"&gt;Two player is great&amp;nbsp;fun&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Two Player" src="http://i.imgur.com/CZWSDEy.gif"&gt;&lt;/p&gt;
&lt;h2 id="chained-explosions"&gt;Chained&amp;nbsp;Explosions&lt;/h2&gt;
&lt;p&gt;I tweaked the explosion code so that it affects objects in the world, this allows you to chain up events so a grenade explodes a mine that blows up a barrel that blows up the enemy :) See how the proximity mine explosions cascade but also the turret is destroyed by the crab emeny exploding next to&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Chain reaction" src="http://i.imgur.com/ZOG7Rpl.gif"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Explosions" src="http://i.imgur.com/FeavVfP.gif"&gt;&lt;/p&gt;
&lt;h2 id="front-end"&gt;Front&amp;nbsp;End&lt;/h2&gt;
&lt;p&gt;Getting a front end, however simple, always makes a game feel more&amp;nbsp;complete.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Front End" src="http://i.imgur.com/Txv5DOR.gif"&gt;&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Steam Refund Policy</title><link href="https://www.executionunit.com/blog/2015/06/04/steam-refund-policy/" rel="alternate"></link><published>2015-06-04T00:00:00+01:00</published><updated>2015-06-04T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2015-06-04:/blog/2015/06/04/steam-refund-policy/</id><summary type="html">&lt;p&gt;If you haven&amp;#8217;t heard, &lt;a href="http://store.steampowered.com/steam_refunds?snr=1_41_4__42"&gt;steam is offering a refund scheme&lt;/a&gt; to&amp;nbsp;players. &lt;/p&gt;
&lt;p&gt;Anyone can get a refund&amp;nbsp;if&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they&amp;#8217;ve played the game for less than two&amp;nbsp;hours.&lt;/li&gt;
&lt;li&gt;they&amp;#8217;ve owned the game for less than 14&amp;nbsp;days.&lt;/li&gt;
&lt;li&gt;they ask for&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;they aren&amp;#8217;t taking the piss by …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;If you haven&amp;#8217;t heard, &lt;a href="http://store.steampowered.com/steam_refunds?snr=1_41_4__42"&gt;steam is offering a refund scheme&lt;/a&gt; to&amp;nbsp;players. &lt;/p&gt;
&lt;p&gt;Anyone can get a refund&amp;nbsp;if&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;they&amp;#8217;ve played the game for less than two&amp;nbsp;hours.&lt;/li&gt;
&lt;li&gt;they&amp;#8217;ve owned the game for less than 14&amp;nbsp;days.&lt;/li&gt;
&lt;li&gt;they ask for&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;they aren&amp;#8217;t taking the piss by repeatedly asking for&amp;nbsp;refunds.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of the day players need a way to get their money back. Some games are a total abuse of steam and players. This is inevitable within any system and it&amp;#8217;s only right to weed those &lt;strike&gt;devs&lt;/strike&gt; practices out. While it may be possible for players to abuse the new system &lt;strong&gt;it&amp;#8217;s never fair that it&amp;#8217;s possible for developers to abuse players&lt;/strong&gt;. So on the one hand I applaud the Steam team for confronting this &lt;em&gt;poisoning of the well&lt;/em&gt; by the few bad devs and keeping the well clean for the rest of us. However I do have some concerns and it&amp;#8217;s mostly about how developers will respond, not&amp;nbsp;players:&lt;/p&gt;
&lt;h2 id="14-daystwo-hours"&gt;14 days/Two&amp;nbsp;hours&lt;/h2&gt;
&lt;p&gt;As an old man I regularly go 14 days where I can&amp;#8217;t find two hours to play a game. As a youngster, especially, during the holidays, I had a seemingly infinite amount of time to play games so this would have been amazing. I would predict a lot of churn of the store as gamers churn through endless games trying them for two hours&amp;#8230;&amp;nbsp;however:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Refunds are designed to remove the risk from purchasing titles on Steam—not as a way to get free games. If it appears to us that you are abusing refunds, we may stop offering them to you. We do not consider it abuse to request a refund on a title that was purchased just before a sale and then immediately rebuying that title for the sale&amp;nbsp;price.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So hopefully this will stop the churn, the heuristic that Steam uses can make or break the&amp;nbsp;system.&lt;/p&gt;
&lt;h2 id="dlc-crap"&gt;&lt;span class="caps"&gt;DLC&lt;/span&gt;&amp;nbsp;Crap&lt;/h2&gt;
&lt;p&gt;These new rules also apply to &lt;span class="caps"&gt;DLC&lt;/span&gt;. Some &lt;span class="caps"&gt;DLC&lt;/span&gt; is utter tripe and clearly there to take money from the weak or gullable. Getting refunds on this is totally appropriate. I&amp;#8217;d actually rather see a much stricter system where if a &lt;span class="caps"&gt;DLC&lt;/span&gt; is constantly getting refunded it&amp;#8217;s taken down from the store until the developer can justify it&amp;#8217;s inclusion. &lt;em&gt;Actually I&amp;#8217;d rather see micro &lt;span class="caps"&gt;DLC&lt;/span&gt;&amp;#8217;s banned but I&amp;#8217;m old so I&amp;#8217;ll ignore&amp;nbsp;it.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="unintended-consequences"&gt;Unintended&amp;nbsp;Consequences&lt;/h2&gt;
&lt;p&gt;As a game dev I&amp;#8217;ll admit that we always front load the gameplay and testing to the early stages of the game. We know that most gamers will &lt;strong&gt;not&lt;/strong&gt; make it to the end boss and we want as many people as possible to have a great experience. With limited resources we priorities the areas of the game that most people will&amp;nbsp;experience.&lt;/p&gt;
&lt;p&gt;This doesn&amp;#8217;t mean we don&amp;#8217;t care about the end of the game but, being honest, it does get slightly less attention than the&amp;nbsp;beginning. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;However, for some, this hard limit of two hours will force them (or maybe even allow them) to only concentrate on the first two hours leaving the rest of the game a bit of a waste&amp;nbsp;land.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How to stop developers doing this is a &lt;strong&gt;much&lt;/strong&gt; harder problem. The only thing I can think is for players to review games and that&amp;#8217;s pretty much how it works&amp;nbsp;now.&lt;/p&gt;
&lt;p&gt;What ever rules Steam enforce will be abused by some game developers and I believe &lt;em&gt;that&lt;/em&gt; abuse is more detremental than any abuse that players can throw at Steam (not that I would condone any abuse by players against the ramen eating developers of the&amp;nbsp;world).&lt;/p&gt;
&lt;h2 id="will-this-stop-any-dev-using-steam"&gt;Will this stop any dev using&amp;nbsp;steam?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;NO&lt;/span&gt;&lt;/strong&gt;. Actually it will probably make steam a better place. Steam has all the players and a great community as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;See how our game, Smith and Winston, is doing &lt;a href="http://www.indiedb.com/games/smith-winston"&gt;IndieDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Smith and Winston" src="http://i.imgur.com/y7wlOZK.gif"&gt;&lt;/p&gt;</content><category term="misc"></category></entry><entry><title>Bullet Physics: Query objects within a volume</title><link href="https://www.executionunit.com/blog/2015/03/27/bullet-physics-query-objects-with-a-volume/" rel="alternate"></link><published>2015-03-27T00:00:00+00:00</published><updated>2015-03-27T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2015-03-27:/blog/2015/03/27/bullet-physics-query-objects-with-a-volume/</id><summary type="html">&lt;p&gt;I need to preform a query of the game world to find all Game Objects within a volume. Preferably a sphere but any convex shape would be good. I struggled with this for a few hours before realising it&amp;#8217;s actually pretty easy. Bullet Physics is amazing but sometimes simple …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I need to preform a query of the game world to find all Game Objects within a volume. Preferably a sphere but any convex shape would be good. I struggled with this for a few hours before realising it&amp;#8217;s actually pretty easy. Bullet Physics is amazing but sometimes simple things aren&amp;#8217;t that&amp;nbsp;obvious.&lt;/p&gt;
&lt;p&gt;My first approach was to use a sphere and &lt;code&gt;btCollsiionWorld::contactTest&lt;/code&gt;. This worked&lt;sup&gt;tm&lt;/sup&gt; in that when I tested it a few months ago all was well but actually it only looks for collision shapes that &lt;em&gt;overlap&lt;/em&gt; the boundary of the test shape. So a collision shape that was completely inside a test sphere would be missed. I guess the clue was i the name&amp;nbsp;really.&lt;/p&gt;
&lt;p&gt;Next up I tried a &lt;code&gt;btCollisionWorld::convexSweepTest&lt;/code&gt; where the from and too transforms of the sweep were very close together. This seemed to return basically the same as &lt;code&gt;btCollisionWorld::contactTest&lt;/code&gt; and it felt a little dirty as I didn&amp;#8217;t really want a sweep test I just wanted to know what was in the volume of the&amp;nbsp;sphere.&lt;/p&gt;
&lt;p&gt;Now, I know, that bullet holds this information internally because it uses a tree structure of &lt;span class="caps"&gt;AABB&lt;/span&gt; to optimize it&amp;#8217;s collision/physics system so it must have an accelerated way of modifiying this tree and keeping track of things that overlap or&amp;nbsp;collide.&lt;/p&gt;
&lt;p&gt;After stepping back for an hour or so I remembered that one of the collision shapes in Bullet is &lt;code&gt;btPairCachingGhostObject&lt;/code&gt; and it is specifically designed to cache all the things that overlap it. I use it in the character controller for Smith and Winston. So here is the code is wrote to query a sphere of space for all objects that overlap this&amp;nbsp;volume:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GameObjectShPtr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//[1]&lt;/span&gt;
&lt;span class="n"&gt;btSphereShape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sphere&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;btPairCachingGhostObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;btTransform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;xform&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;xform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setOrigin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCollisionShape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sphere&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setWorldTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xform&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ObjectColMask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ocm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ObjectColMask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colflags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColFlags&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;kAll&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUserPointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ocm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//[2]&lt;/span&gt;
&lt;span class="n"&gt;mDynamicsWorld&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addCollisionObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//[3]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getNumOverlappingObjects&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;btCollisionObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;btco&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getOverlappingObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ObjectColMask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ocm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ObjectColMask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;btco&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;getUserPointer&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ocm&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ObjectCol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ocm&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;UpcastToObjectCol&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;GameObjectShPtr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GOFromTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oc&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetTransform&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//[4]&lt;/span&gt;
&lt;span class="n"&gt;mDynamicsWorld&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;removeCollisionObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ghost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ocm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h3 id="step-1"&gt;Step&amp;nbsp;1&lt;/h3&gt;
&lt;p&gt;Create a sphere with the disired radius of the volume to test (I believe that any convex collision primitive will do, tri meshes wont work as they have no concept ot &lt;em&gt;inside&lt;/em&gt; or &lt;em&gt;outside&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Create a &lt;code&gt;btPairCachingGhostObject&lt;/code&gt; set its collison shape to the sphere and set it&amp;#8217;s collison flags. I&amp;#8217;ve extended the collision flags with my own mechanism called an &lt;code&gt;ObjectColMask&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="step-2"&gt;Step&amp;nbsp;2&lt;/h3&gt;
&lt;p&gt;Add the ghost object to the collision world. The act of adding the objects causes it&amp;#8217;s overlapping object list to be updated with, you&amp;#8217;ve guessed it, all of it&amp;#8217;s overlapping&amp;nbsp;objects.&lt;/p&gt;
&lt;h3 id="step-3"&gt;Step&amp;nbsp;3&lt;/h3&gt;
&lt;p&gt;Iterate over the overlapping objects doing your own magic to extract what ever information you&amp;nbsp;need.&lt;/p&gt;
&lt;h3 id="step-4"&gt;Step&amp;nbsp;4&lt;/h3&gt;
&lt;p&gt;Remove the Ghost Object from the collision&amp;nbsp;world.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s it, pretty simple but not too obvious. Hope this helps someone&amp;nbsp;else.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category></entry><entry><title>LuaJIT bit.band stopped working</title><link href="https://www.executionunit.com/blog/2015/03/24/luajit-bitband-stopped-working/" rel="alternate"></link><published>2015-03-24T00:00:00+00:00</published><updated>2015-03-24T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2015-03-24:/blog/2015/03/24/luajit-bitband-stopped-working/</id><summary type="html">&lt;p&gt;Came across an interesting feature/artifact of using LuaJIT&amp;nbsp;today.&lt;/p&gt;
&lt;p&gt;In Smith and Winston we use the bit package that LuaJIT provides to flag and mask collisions. The types of collision (for example world, bullet, vehicle) were hard coded on both the engine and Lua side. Today I moved toward …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Came across an interesting feature/artifact of using LuaJIT&amp;nbsp;today.&lt;/p&gt;
&lt;p&gt;In Smith and Winston we use the bit package that LuaJIT provides to flag and mask collisions. The types of collision (for example world, bullet, vehicle) were hard coded on both the engine and Lua side. Today I moved toward the types being loaded from an external file by the engine/editor and injecting those in to the Lua global space for use by the scripts. No more hard coding, everything in one place, what&amp;#8217;s not to&amp;nbsp;like?&lt;/p&gt;
&lt;p&gt;Well it didn&amp;#8217;t work. Take the following&amp;nbsp;code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;function&lt;/span&gt; &lt;span class="nc"&gt;Projectile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nf"&gt;collision_trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;othergo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;localpos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                                      &lt;span class="n"&gt;worldpos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;otherlocalpos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                                      &lt;span class="n"&gt;othercoltype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;--othercoltype = bit.tobit(othercoltype)&lt;/span&gt;
    &lt;span class="c1"&gt;--vox.print(string.format(&amp;quot;bang %d\n&amp;quot;, 23))&lt;/span&gt;
    &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;othercoltype&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WORLD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;

        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;explosion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;worldpos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kr"&gt;end&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;othertype&lt;/code&gt; should be a bit field showing the type of thing this GameObject has hit (for example &lt;code&gt;WORLD&lt;/code&gt;). If it&amp;#8217;s the world I want to cause an explosion at the impact location (worldpos) and move on. This didn&amp;#8217;t&amp;nbsp;work!&lt;/p&gt;
&lt;p&gt;The weird things is that if I printed out &lt;code&gt;othercoltype&lt;/code&gt; then the if statement&amp;nbsp;worked!&lt;/p&gt;
&lt;p&gt;The constant &lt;code&gt;vox.col.WORLD&lt;/code&gt; is injected in to the Lua state using LuaBridge before anything gets a chance to&amp;nbsp;run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kWorld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColFlags&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;kWorld&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;getGlobalNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beginNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;vox&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beginNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;col&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;WORLD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kWorld&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;and has the value&amp;nbsp;2.&lt;/p&gt;
&lt;p&gt;So it seems that &lt;code&gt;bit.band(othercoltype, 2)&lt;/code&gt; doesn&amp;#8217;t work so there is a difference between bitfields and number in LuaJIT. There is a clue to this in the &lt;a href="http://bitop.luajit.org"&gt;LuaJIT bit documentation&lt;/a&gt;. The fact that it has a &lt;a href="http://bitop.luajit.org/api.html"&gt;bit.tobit&lt;/a&gt; function implies there is something &lt;em&gt;magic&lt;/em&gt; going on. To test this I changed the code to &lt;code&gt;bit.band(othercoltype, bit.tobit(2))&lt;/code&gt; and it started working. I have &lt;span class="caps"&gt;NO&lt;/span&gt; idea why printing the value worked but I that&amp;#8217;s not a long term solution&amp;nbsp;obviously.&lt;/p&gt;
&lt;p&gt;So now I need to inject the &lt;em&gt;normalized&lt;/em&gt; bit values in to the Lua state, not just the power of two numbers I&amp;nbsp;thought.&lt;/p&gt;
&lt;p&gt;Unfortunately this means playing with the Lua stack. I&amp;#8217;ve been using LuaBridge to do all the heavy lifting up til&amp;nbsp;now.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ColFlags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;colflags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColFlags&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;lua_createtable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colflags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetNumFlags&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="cm"&gt;/* table */&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colflags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetNumFlags&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ColGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colgroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ColGroup&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colflags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameFromFlag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colgroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lua_pushstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="cm"&gt;/* table | name */&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lua_getglobal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bit&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="cm"&gt;/* table | name | bit table */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lua_getfield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tobit&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="cm"&gt;/* table | name | bit table | tobit func */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lua_pushinteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colgroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="cm"&gt;/* table | name | bit table | tobit func | colgroup*/&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lua_pcall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="cm"&gt;/* table | name | bit table | hexified colgroup */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lua_remove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                                         &lt;/span&gt;&lt;span class="cm"&gt;/* table | name | hexified colgroup */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;lua_settable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="cm"&gt;/* table */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;lua_setglobal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;const&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;                                      &lt;/span&gt;&lt;span class="cm"&gt;/* &amp;lt;empty stack&amp;gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In true Lua example fashion I&amp;#8217;ve added comments showing the state of the Lua stack (relative to where the createtable code starts). I use a singleton called ColFlags that is initialized with the names and values of all the collision flags when the editor or engine is started&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;Now everything works, I&amp;#8217;ve got all the collision flags defined in one place for both the Editor, Engine and Lua&amp;nbsp;Scripts.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category><category term="Lua"></category></entry><entry><title>First Year of Smith and Winston</title><link href="https://www.executionunit.com/blog/2015/03/10/first-year-of-smith-and-winston/" rel="alternate"></link><published>2015-03-10T00:00:00+00:00</published><updated>2015-03-10T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2015-03-10:/blog/2015/03/10/first-year-of-smith-and-winston/</id><summary type="html">&lt;p&gt;&lt;em&gt;I posted most of this to &lt;a href="http://forums.tigsource.com/index.php?topic=46796.0"&gt;&lt;span class="caps"&gt;TIG&lt;/span&gt; Forums&lt;/a&gt; but thought I&amp;#8217;d reproduce it here
for people that don&amp;#8217;t want to read a&amp;nbsp;forum.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Smith and Winston is a twin stick shooter for Win, Mac, Linux and &lt;span class="caps"&gt;PS4&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;S&amp;amp;W is Inspired by Ikari Warriors and Heavy Barrel, two …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;I posted most of this to &lt;a href="http://forums.tigsource.com/index.php?topic=46796.0"&gt;&lt;span class="caps"&gt;TIG&lt;/span&gt; Forums&lt;/a&gt; but thought I&amp;#8217;d reproduce it here
for people that don&amp;#8217;t want to read a&amp;nbsp;forum.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Smith and Winston is a twin stick shooter for Win, Mac, Linux and &lt;span class="caps"&gt;PS4&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;S&amp;amp;W is Inspired by Ikari Warriors and Heavy Barrel, two great arcade games that are great fun to play even&amp;nbsp;now.&lt;/p&gt;
&lt;p&gt;Charlie (artist) and I (dazza the coder) have been working on Smith and Winston for just over a year now. We&amp;#8217;ve come a long way in that time and this post is a sort of walk through time to show you where we are in the&amp;nbsp;journey.&lt;/p&gt;
&lt;h2 id="initial-concept-november-2013"&gt;Initial Concept November&amp;nbsp;2013&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Concept landscape" src="http://i.imgur.com/4pWFw5L.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Concept Enemy" src="http://i.imgur.com/7rqT2mV.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Prototype in Unity" src="http://i.imgur.com/x3WBmWT.jpg"&gt;&lt;/p&gt;
&lt;p&gt;We started out using Unity. Neither of us had used Unity before so it was a bit of a ride. After a few weeks we had a guy running around and shooting things. We weren&amp;#8217;t really happy with the art style though, it just wasn&amp;#8217;t coming together for us. Although Unity is great I didn&amp;#8217;t really enjoy using it. Lots of crashes and lots of weirdness that as a coder I just wanted to&amp;nbsp;fix.&lt;/p&gt;
&lt;h2 id="change-of-art-direction-jan-2014"&gt;Change of Art Direction Jan&amp;nbsp;2014&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Different Art Style" src="http://i.imgur.com/PLTeyom.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Initial 8bit character designs. We started to like what we were doing but how were we going to translate this in to a 3D game. We didn&amp;#8217;t want to make it purely 2D like the originals but polygon work is very labour intensive and as a two man team that made us&amp;nbsp;nervous.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Move to Voxels for enemies" src="http://i.imgur.com/ePYWm0j.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Charlie creates these concept baddies using Qubicle (great voxel editor) and we seriously start to think we should make it a voxel based game (March 2014). I think in hindsight I was more reluctant than Charlie to make a voxel game. It seemed quite risky and Unity was already a bit if a&amp;nbsp;risk.&lt;/p&gt;
&lt;h2 id="ditch-unity"&gt;Ditch&amp;nbsp;Unity&lt;/h2&gt;
&lt;p&gt;I decide we should ditch Unity and run with our own code base so we can voxel this game up. While this seems bat shit it meant that I could say to Charlie what we definitely could and couldn&amp;#8217;t do without worrying about Unity getting in the way. We both know it&amp;#8217;s a lot of work though but it&amp;#8217;s so exciting at the beginning isn&amp;#8217;t&amp;nbsp;it?&lt;/p&gt;
&lt;p&gt;&lt;img alt="Start of BSEd" src="http://i.imgur.com/tk7d3R6.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The editor starts and as always it&amp;#8217;s a bit shit at the beginning. We really weren&amp;#8217;t sure if we were doing the right thing dropping Unity but it seemed like a big risk to me and I knew I could get and engine/editor up and running and realise this&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;&lt;img alt="More BSEd" src="http://i.imgur.com/xtYS7T5.jpg"&gt;&lt;/p&gt;
&lt;p&gt;After a long few months (that&amp;#8217;s coder speak for six months) the editor is starting to come together pretty well and we&amp;#8217;re rocking some designs and playing some levels. The gap in writing the Editor and pulling the engine together gives Charlie a long time to pull concepts together and really nail the art&amp;nbsp;style.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Starting to come together" src="http://i.imgur.com/tNMjQP8.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Here is a video showing: 
* how awful it looked in March 2014: https://www.youtube.com/watch?v=Pvriq8puKuU
* looking better a few months later: https://www.youtube.com/watch?v=OjGY7pV3PUc
* July 2014 and the editor is coming together: https://www.youtube.com/watch?v=hWTFmYu3k6g
* August and the game is looking quite good:&amp;nbsp;https://www.youtube.com/watch?v=NtrimC_TWe4&lt;/p&gt;
&lt;h2 id="august-we-decided-on-the-logo-and-name-set-in-stone-now"&gt;August - We decided on the Logo and name, set in stone&amp;nbsp;now&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Smith and Winston Logo" src="http://i.imgur.com/QkxBOqk.jpg"&gt;&lt;/p&gt;
&lt;h2 id="vertical-slice-new-year-bosses"&gt;Vertical Slice - New year&amp;nbsp;Bosses&lt;/h2&gt;
&lt;p&gt;We started working on a &amp;#8216;vertical slice&amp;#8217; in the new year. We wanted something to show potential publishers or maybe, if we can pluck up the courage, a kick starter campaign. For a vertical slice we needed a boss so we started to prototype&amp;nbsp;one:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Spider Boss" src="http://i.imgur.com/wNR3jAh.jpg"&gt;&lt;/p&gt;
&lt;p&gt;We want to show the varing terrains that the game will have so far we&amp;#8217;ve got desert and jungle plus inside a military base type thing (ok not original but who&amp;nbsp;cares!)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Moving Gif" src="http://i.imgur.com/dMDF21X.gif"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Moving Gif" src="http://i.imgur.com/3C6v0Ap.gif"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Moving Gif" src="http://i.imgur.com/y7wlOZK.gif"&gt;&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="SmithAndWinston"></category></entry><entry><title>Grabbing keyboard input in Qt</title><link href="https://www.executionunit.com/blog/2014/03/21/grabbing-keyboard-input-in-qt/" rel="alternate"></link><published>2014-03-21T00:00:00+00:00</published><updated>2014-03-21T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2014-03-21:/blog/2014/03/21/grabbing-keyboard-input-in-qt/</id><summary type="html">&lt;p&gt;I&amp;#8217;m currently writing an editor for our next game. We&amp;#8217;ve used many tool in the past (&lt;a href="http://www.blender.org"&gt;Blender&lt;/a&gt;, &lt;a href="http://www.mapeditor.org"&gt;Tiled&lt;/a&gt; &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; &lt;a href="http://tilemap.co.uk/mappy.php"&gt;Mappy&lt;/a&gt;) to make games but we thought it was really time to invest in our own code base. This was heavily influenced by the great experience we had using &lt;a href="https://unity3d.com"&gt;Unity3D …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;m currently writing an editor for our next game. We&amp;#8217;ve used many tool in the past (&lt;a href="http://www.blender.org"&gt;Blender&lt;/a&gt;, &lt;a href="http://www.mapeditor.org"&gt;Tiled&lt;/a&gt; &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; &lt;a href="http://tilemap.co.uk/mappy.php"&gt;Mappy&lt;/a&gt;) to make games but we thought it was really time to invest in our own code base. This was heavily influenced by the great experience we had using &lt;a href="https://unity3d.com"&gt;Unity3D&lt;/a&gt; to prototype our next&amp;nbsp;game.&lt;/p&gt;
&lt;p&gt;&lt;img alt="image" src="https://www.executionunit.com/static/media/uploads/blog/bsed.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I think you can see how much we were influenced by Unity3D in this&amp;nbsp;shot.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Anyway, to write the editor I turned to Qt as a reliable cross platform library. I wanted to be able to play the game &lt;span class="caps"&gt;IN&lt;/span&gt; the editor so we could get some of the quick turn around for tweaking that you get in&amp;nbsp;Unity3D.&lt;/p&gt;
&lt;p&gt;The editor already uses &lt;span class="caps"&gt;SFML&lt;/span&gt; to read controllers and exposes this input to the Lua scripting system. However the &lt;span class="caps"&gt;SFML&lt;/span&gt; keyboard code (&lt;code&gt;sf::keyboard&lt;/code&gt;) does not work because it&amp;#8217;s not hooked in to the applications event loop as Qt owns (and basically hides away) the event&amp;nbsp;loop.&lt;/p&gt;
&lt;p&gt;To work around this I learned that you can install an Event Filter in the main application QWidget and filter out/redirect keyboard events. Using this I can stop keyboard short cuts from changing the editor state and pass the key presses to the Lua scripting&amp;nbsp;system.&lt;/p&gt;
&lt;h2 id="the-code"&gt;The&amp;nbsp;Code.&lt;/h2&gt;
&lt;p&gt;So when the user presses the play button on the toolbar the code installs the Event&amp;nbsp;Filter&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="nt"&gt;-&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;installEventFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;mEventFilter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;and when the game stops, the user presses pause or stop the Event Filter is&amp;nbsp;removed&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;QApplication&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="nt"&gt;-&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;removeEventFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;mEventFilter&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The event filter itself is pretty&amp;nbsp;simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;EventFilter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Q_OBJECT&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eventFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;with the main actual Filter function looking like&amp;nbsp;this&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;EventFilter::eventFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="cm"&gt;/*object*/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QEvent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;KeyPress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;QKeyEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;keyEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QKeyEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;voxity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RegisterKeydown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtKeyToSFML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyEvent&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QEvent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;KeyRelease&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;QKeyEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;keyEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QKeyEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;voxity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RegisterKeyup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtKeyToSFML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyEvent&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QEvent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Shortcut&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;QShortcutEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;QShortcutEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;QKeySequence&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;voxity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RegisterKeydown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QtKeyToSFML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If the filter function returns true then the event should be ignored by the rest of the application and the event is discarded. Otherwise it carries on it&amp;#8217;s&amp;nbsp;way. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;The Qt docs talk about filter functions slowing down the app but it doesn&amp;#8217;t seem to make much difference to our editor. It&amp;#8217;s only installed when the game us running anyway so most of the load is in running the&amp;nbsp;game.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Basically if it&amp;#8217;s a keypress/keyrelease event the RegisterKeydown or RegisterKeyup is called. This records the keypress in a way that the Lua scripting system can pick up that a key is down or up. The Qt keycode is converted to an &lt;span class="caps"&gt;SFML&lt;/span&gt; code as the game runtime (when it running outside of the editor) will just be using &lt;span class="caps"&gt;SFML&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The one quirk is if the event is a &lt;code&gt;Shortcut&lt;/code&gt;. The editor has many single keys that map to actions (for example &lt;code&gt;w&lt;/code&gt; activates translate mode and &lt;code&gt;e&lt;/code&gt; activates rotate mode). These come through as shortcuts &lt;span class="caps"&gt;NOT&lt;/span&gt; keypresses. This hints  that there is a lot of code beneath this filter playing with the raw input. For the initial keypress of a shortcut a Shortcut event is triggered but the release of the key comes through as a &lt;code&gt;KeyRelease&lt;/code&gt; event.&lt;/p&gt;
&lt;h2 id="not-perfect-though"&gt;Not Perfect&amp;nbsp;Though&lt;/h2&gt;
&lt;p&gt;This scheme doesn&amp;#8217;t seem to intercept &lt;span class="caps"&gt;CMD&lt;/span&gt;-Q, &lt;span class="caps"&gt;CMD&lt;/span&gt;-P etc events that are assumed by all apps to be Quit and Print. Further investigation may reveal how they can be intercepted but I don&amp;#8217;t need to grab them at the&amp;nbsp;moment.&lt;/p&gt;
&lt;p&gt;I hope this helps&amp;nbsp;someone.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category><category term="Qt"></category></entry><entry><title>Why I Chose Not To Use Unity3D</title><link href="https://www.executionunit.com/blog/2014/03/21/why-i-chose-not-to-use-unity3d/" rel="alternate"></link><published>2014-03-21T00:00:00+00:00</published><updated>2014-03-21T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2014-03-21:/blog/2014/03/21/why-i-chose-not-to-use-unity3d/</id><summary type="html">&lt;p&gt;I evaluated &lt;a href="http://unity3d.com"&gt;Unity3D&lt;/a&gt; for a few months before deciding &lt;span class="caps"&gt;NOT&lt;/span&gt; to use it. It&amp;#8217;s a really, really great tool and it was a tough decision. Ultimately I felt like there was more resitance to steady progress using Unity3D over extending/upgrading my own code. Here is a rough guide …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I evaluated &lt;a href="http://unity3d.com"&gt;Unity3D&lt;/a&gt; for a few months before deciding &lt;span class="caps"&gt;NOT&lt;/span&gt; to use it. It&amp;#8217;s a really, really great tool and it was a tough decision. Ultimately I felt like there was more resitance to steady progress using Unity3D over extending/upgrading my own code. Here is a rough guide to why I decided not to use&amp;nbsp;it.&lt;/p&gt;
&lt;h2 id="c-is-not-a-natural-ai-language"&gt;C# is not a natural &lt;span class="caps"&gt;AI&lt;/span&gt;&amp;nbsp;language&lt;/h2&gt;
&lt;p&gt;Now for many this isn&amp;#8217;t an issue. C# is a great language. Compared to Lua though C# is too verbose and too cumbersome (not as cumbersome as C++ but close). It just takes too long to express simple things in C#. The screen is filled with too many curly braces. A lot of the verboseness comes from C# strong typing. Strong typing is a great feature and many bugs are caught early using it. However for me the slowest bit of writing a game is writing the scripting/behaviours/&lt;span class="caps"&gt;AI&lt;/span&gt;. It&amp;#8217;s also the bit I&amp;#8217;m least comfortable with as it&amp;#8217;s all about nuance and anything that resists quick change and &amp;#8216;play&amp;#8217; is a&amp;nbsp;hinderance.&lt;/p&gt;
&lt;p&gt;Of course you can use &lt;a href="https://en.wikipedia.org/wiki/Boo_(programming_language)"&gt;Boo&lt;/a&gt; and Javascript but it&amp;#8217;s really very clear that they are second class citizens in the Unity3D world compared to&amp;nbsp;C#.&lt;/p&gt;
&lt;h2 id="crash-after-crash-at-least-at-the-start"&gt;Crash after crash (at least at the&amp;nbsp;start)&lt;/h2&gt;
&lt;p&gt;For the first two weeks of using Unity3D I just got too many crashes in the editor. Most were to do with importing animations. I reported a bug and nothing really happened about it. The bugs were &lt;span class="caps"&gt;OS&lt;/span&gt; X specific (the same steps didn&amp;#8217;t crash on Windows &lt;span class="caps"&gt;XP&lt;/span&gt; or 7). Once I&amp;#8217;d got through that animation rough patch I only had the odd crash, nothing I&amp;#8217;m not used to with my own software&amp;nbsp;;)&lt;/p&gt;
&lt;p&gt;Most of the crashes I could work around by using windows or chosing a different path through the editor. This left a bad vibe with me though. What other bugs might be lurking within. Probability says &amp;#8220;not many&amp;#8221; since so many other devs are using Unity3D, but what lurks&amp;nbsp;beneath?&lt;/p&gt;
&lt;h2 id="community"&gt;Community&lt;/h2&gt;
&lt;p&gt;Unity3D&amp;#8217;s strength comes from it&amp;#8217;s flexibility and price point. It just can&amp;#8217;t be beaten at the moment&amp;#8230; apart from the forums. I imagine since going &amp;#8216;free&amp;#8217; Unity3D&amp;#8217;s forums have taken a real nose dive. There is frequent incivility, frequent arguments about the &amp;#8216;best way to do something&amp;#8217; and no one with authority seems to step&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;I realise this is the internet and every asshat with a keyboard is Carmack but I don&amp;#8217;t want to wade through Asshat Carmack stupidity when I am&amp;nbsp;stuck.&lt;/p&gt;
&lt;h2 id="lack-of-control"&gt;Lack of&amp;nbsp;Control&lt;/h2&gt;
&lt;p&gt;Personally I like to control the code that I work with. I&amp;#8217;ve been writing games for thirty years and I&amp;#8217;ve always controlled the code. While I enjoyed making a prototype game and I learned a hell of a lot I was nervous being this far from the&amp;nbsp;metal.&lt;/p&gt;
&lt;h2 id="extending-unity3d"&gt;Extending&amp;nbsp;Unity3D&lt;/h2&gt;
&lt;p&gt;The game I was prototyping needed voxels. So I looked at how to extend Unity3D with my own type of mesh and collision primitives. C# is a poor scripting language but it&amp;#8217;s a great systems language so I thought this would be easy, maybe there was a good module I could&amp;nbsp;buy?&lt;/p&gt;
&lt;p&gt;I really struggled to get an overview of the system and how to extend it. There are bits and pieces all over the place but I wanted one canonical document on how to extend the codebase. I wanted to interface &lt;a href="http://www.volumesoffun.com/polyvox-about/"&gt;Polyvox&lt;/a&gt; with Unity3D (something they would later announce they were doing anyway). Once again there was too much resistance stopping me from making&amp;nbsp;progress.&lt;/p&gt;
&lt;p&gt;I looked at buying modules but at the time (late 2013) there didn&amp;#8217;t seem to be any modules I could buy to get me over this hump. No modules offered an evaluation period. I had very specific needs of speed and voxel density, I didn&amp;#8217;t want to pay $2000 for something that didn&amp;#8217;t meet my requirements. Since I wasn&amp;#8217;t cloning Minecraft and didn&amp;#8217;t need an infinite draw distance I was worried I was too&amp;nbsp;niche.&lt;/p&gt;
&lt;h2 id="the-hud-code"&gt;The &lt;span class="caps"&gt;HUD&lt;/span&gt;&amp;nbsp;Code&lt;/h2&gt;
&lt;p&gt;Oh my god, the immediate mode &lt;span class="caps"&gt;HUD&lt;/span&gt; stuff is bloody rubbish. I know this is a well documented problem and it&amp;#8217;s being fixed but how long is it taking and how many devs have complained and oh my god how much of a &lt;span class="caps"&gt;PITA&lt;/span&gt; is it. Compared to the rest of the code base this is undergraduate&amp;nbsp;quality.&lt;/p&gt;
&lt;h2 id="controllers"&gt;Controllers&lt;/h2&gt;
&lt;p&gt;The way unity deals with controllers is amazingly bad. Of all the interfaces they provide this is the one where there is no justitifcation for such a bad interface. It makes dealing with &lt;span class="caps"&gt;PS3&lt;/span&gt;/4 and XBox controllers a real &lt;span class="caps"&gt;PITA&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="in-conclusion"&gt;In&amp;nbsp;Conclusion&lt;/h2&gt;
&lt;p&gt;Everyone writing games should spend some time using Unity3D. It&amp;#8217;s an amazing piece of software written by an amazing group of people. If you&amp;#8217;re just starting out making games, have limited time or limited budget then it&amp;#8217;s basically a no-brainer. If however you have a niche technical angle, a shit load of experience, a codebase you can work with then, well it&amp;#8217;s not quite so&amp;nbsp;clear.&lt;/p&gt;
&lt;p&gt;Many of the stress points in making a game come from the polish end 10% (that famously takes 90% of the time). Unity does a lot to empower the non-coders in a team to polish. For me as a coder it doesn&amp;#8217;t add much and may even hold me back by pushing C# and limiting&amp;nbsp;extension.&lt;/p&gt;
&lt;p&gt;Ultimately for me, as an engine coder, the crash bugs just gave me the willies. I&amp;#8217;ve spent many a long night fixing crash bugs and burning &lt;span class="caps"&gt;CD&lt;/span&gt;&amp;#8217;s for, or uploading to, Sony, Nintendo and Microsoft and not being in control just adds too much stress. Despite knowing many devs are happy with that I&amp;#8217;m personally not happy with that lack of&amp;nbsp;control.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category></entry><entry><title>Integrating Lua and my C++ Game Engine</title><link href="https://www.executionunit.com/blog/2014/03/09/integrating-lua-and-my-c-game-engine/" rel="alternate"></link><published>2014-03-09T00:00:00+00:00</published><updated>2014-03-09T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2014-03-09:/blog/2014/03/09/integrating-lua-and-my-c-game-engine/</id><summary type="html">&lt;p&gt;&lt;em&gt;If you want to cut to the chase you can download the code &lt;a href="https://bitbucket.org/executionunit/exunit_public/src/8d3f14710dadbbe21ed682fc51c08231d6303736/LuaBridgeTest/"&gt;here&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This isn&amp;#8217;t a very well written blog post, it&amp;#8217;s more of a dump of my thoughts as I tested out LuaBridge and didn&amp;#8217;t get to trying out OOLua&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Once again I am starting …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;If you want to cut to the chase you can download the code &lt;a href="https://bitbucket.org/executionunit/exunit_public/src/8d3f14710dadbbe21ed682fc51c08231d6303736/LuaBridgeTest/"&gt;here&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This isn&amp;#8217;t a very well written blog post, it&amp;#8217;s more of a dump of my thoughts as I tested out LuaBridge and didn&amp;#8217;t get to trying out OOLua&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Once again I am starting to integrate Lua in to the next generation of my engine. It&amp;#8217;s never a completely smooth process. Exactly where to draw the line between C++ and Lua logic is never immedietly&amp;nbsp;clear.&lt;/p&gt;
&lt;p&gt;This is the fifth major revision of my engine (that I can remember) and it&amp;#8217;s move toward a component based system has made the dividing line more&amp;nbsp;obvious.&lt;/p&gt;
&lt;p&gt;Previously I had driven the engine completely from Lua, the main loop essentially being the first script that the engine loaded. This script drove everything. With a component based system and a new custom editor the &amp;#8220;data driving&amp;#8221; is done by the editor as it packs levels or scenes&amp;nbsp;together.&lt;/p&gt;
&lt;h2 id="bridging-the-divide"&gt;Bridging the&amp;nbsp;divide&lt;/h2&gt;
&lt;p&gt;In previous incarnations of my engine integration of Lua and C++ has be done&amp;nbsp;with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;handcrafted lua&amp;nbsp;code&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.swig.org"&gt;&lt;span class="caps"&gt;SWIG&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.codenix.com/~tolua/"&gt;tolua++&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I never want to handcraft it ever again, it&amp;#8217;s just too time consuming and brittle. &lt;span class="caps"&gt;SWIG&lt;/span&gt;, while easy to use and clever, produces glue code that is slower than needs be and very complicated. tolua++ produces better code than &lt;span class="caps"&gt;SWIG&lt;/span&gt; and has some really nice features but seems to be unmaintained and there are some bugs that need to be worked&amp;nbsp;around.&lt;/p&gt;
&lt;h2 id="luabridge-over-oolua"&gt;LuaBridge over&amp;nbsp;OOlua&lt;/h2&gt;
&lt;p&gt;So I turned to the internet and the top two contenders (that don&amp;#8217;t require boost) seem to be &lt;a href="https://code.google.com/p/oolua/"&gt;OOLua&lt;/a&gt; and &lt;a href="https://github.com/vinniefalco/LuaBridge"&gt;LuaBridge&lt;/a&gt;. They both employ a set of C++ templates to wrap your code, exposing it to&amp;nbsp;Lua.&lt;/p&gt;
&lt;p&gt;OOLua has some &lt;a href="https://code.google.com/p/oolua/wiki/Speed_comparisons"&gt;nice tables&lt;/a&gt; showing it is the fastest thing in the world which enticed me &lt;span class="caps"&gt;BUT&lt;/span&gt; it requires &lt;a href="http://industriousone.com/premake"&gt;Premake&lt;/a&gt;, &lt;a href="http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page"&gt;Cpp Unit&lt;/a&gt; and &lt;a href="https://code.google.com/p/googlemock/"&gt;Google Mock&lt;/a&gt; to build it. This &lt;em&gt;really&lt;/em&gt; put me off. I just want to wrap my code, not install another build system and unit testing framework. LuaBridge doesn&amp;#8217;t require any external tools or&amp;nbsp;libraries.&lt;/p&gt;
&lt;p&gt;LuaBrdge has a more pleasant syntax and the underlying template code seems easier to decipher. To expose a simple struct (taken from the OOLua&amp;nbsp;docs)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;foo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In OOLua you would&amp;nbsp;enter:   &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;OOLUA_CLASS_NO_BASES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;OOLUA_NO_TYPEDEFS&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;OOLUA_ONLY_DEFAULT_CONSTRUCTOR&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;OOLUA_MEM_FUNC_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="cm"&gt;/*return type*/&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="cm"&gt;/*function name*/&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="cm"&gt;/*parameter type*/&lt;/span&gt;
&lt;span class="n"&gt;OOLUA_CLASS_END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;while in&amp;nbsp;LuaBridge:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;getGlobalNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beginNamespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;vox&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beginClass&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endClass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;LuaBridge seems more concise, less brittle (it uses C++ templates to infer the paramter types and return types) and quite frankly who wants &lt;span class="caps"&gt;CAPITALS&lt;/span&gt; &lt;span class="caps"&gt;ALL&lt;/span&gt; &lt;span class="caps"&gt;THROUGH&lt;/span&gt; &lt;span class="caps"&gt;THEIR&lt;/span&gt; &lt;span class="caps"&gt;CODE&lt;/span&gt;?&lt;/p&gt;
&lt;p&gt;Both seem like very well written libraries though so it&amp;#8217;s really a matter of personal preference as opposed to some major technical flaw in&amp;nbsp;OOlua.&lt;/p&gt;
&lt;p&gt;So I decided to test LuaBridge first. If I could get what I wanted from it then I&amp;#8217;d move&amp;nbsp;forward.&lt;/p&gt;
&lt;h2 id="overview-of-requirements"&gt;Overview of&amp;nbsp;Requirements.&lt;/h2&gt;
&lt;p&gt;The scripts that I want to attach to my &lt;code&gt;GameObjects&lt;/code&gt; are more like behaviours than massive all emcompassing &lt;span class="caps"&gt;AI&lt;/span&gt; scripts. This design is something I learned to like while playing with Unity3D a few months ago. While it adds a certain amount of managment overhead on the engine side it allows a lot of the day to day scripting of a game to be built from small scripts. For example you can write a small script to look at the player and attach it to every enemies head, add a parameter to limit it to when the player is within &lt;code&gt;n&lt;/code&gt; meters and you&amp;#8217;ve got a nice reusable component that anyone (even non programmers) can drop on trees, pickups, bosses, chickens, anything you&amp;nbsp;want.&lt;/p&gt;
&lt;p&gt;I want my scripts to be able to be&amp;nbsp;updated&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;every&amp;nbsp;frame&lt;/li&gt;
&lt;li&gt;before&amp;nbsp;physics&lt;/li&gt;
&lt;li&gt;after&amp;nbsp;physics&lt;/li&gt;
&lt;li&gt;on a&amp;nbsp;trigger&lt;/li&gt;
&lt;li&gt;on a&amp;nbsp;collisions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Or any combination of these&lt;/em&gt;. So I need a mechanism where the script lets the engine know how to use the&amp;nbsp;script.&lt;/p&gt;
&lt;h2 id="prototype-interface"&gt;Prototype&amp;nbsp;Interface&lt;/h2&gt;
&lt;p&gt;Rather then screw up my codebase I created a test project to play with LuaBridge. You can get the code &lt;a href="https://bitbucket.org/executionunit/exunit_public/src/8d3f14710dadbbe21ed682fc51c08231d6303736/LuaBridgeTest/"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;All of the code is in the one &lt;code&gt;cpp&lt;/code&gt; file &lt;code&gt;main.cpp&lt;/code&gt;. &lt;code&gt;test.lua&lt;/code&gt; is a test script to attach to &lt;code&gt;GameObject&lt;/code&gt;s. It depends on &lt;code&gt;class.lua&lt;/code&gt; (fairly generic class definition based on the lua wiki example) and utility.lua (old code, probably also taken from the lua wiki over the years to manipulate&amp;nbsp;tables).&lt;/p&gt;
&lt;p&gt;The code is fairly well commented but here is an overview of how it&amp;nbsp;works.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GameObject&lt;/code&gt; is a hollowed out container class for entities in a game. It has a few token members to test exposing them to&amp;nbsp;lua.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LoadScript&lt;/code&gt; loads a lua script and executes it. The script is expected to register a global function &lt;code&gt;register_script&lt;/code&gt; that is called returning a class definition (lua table). This definition is instanstiated and attached to the game object. Load script does some simple caching to prevent test.lua being run multiple&amp;nbsp;times.&lt;/p&gt;
&lt;p&gt;Once &lt;code&gt;numscripts&lt;/code&gt; &lt;code&gt;GameObject&lt;/code&gt;s are created with &lt;code&gt;test.lua&lt;/code&gt; attached the GameObjects are ticked. The GameObject::Tick function looks for a function called &lt;code&gt;tick&lt;/code&gt; in it&amp;#8217;s lua class and if it&amp;#8217;s there calls&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Once that&amp;#8217;s all done, everything is deleted to see if we&amp;#8217;re leaking&amp;nbsp;memory.&lt;/p&gt;
&lt;h2 id="thoughts"&gt;Thoughts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;really like LuaRef it&amp;#8217;s a very nice way to program&amp;nbsp;lua.&lt;/li&gt;
&lt;li&gt;don&amp;#8217;t like the way the scripts have to define a callback function, would prefere to return the class definition during the inital script run. However I don&amp;#8217;t want to play with the Lua stack and LuaBridge doesn&amp;#8217;t seem to provide a clean way to get the table off of the&amp;nbsp;stack.&lt;/li&gt;
&lt;li&gt;In tolua++ you could write and expose a C++ function is such a way as it would appear, in Lua, to return multiple values. This was very nice and Lua-ish (search for &lt;code&gt;Multiple returned values&lt;/code&gt; &lt;a href="http://www.codenix.com/~tolua/tolua++.html"&gt;here&lt;/a&gt;). I can&amp;#8217;t see how to do this in&amp;nbsp;LuaBridge.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="gotchas"&gt;Gotchas.&lt;/h2&gt;
&lt;h4 id="four-character-literal-expansion-bit-me"&gt;Four Character Literal expansion bit&amp;nbsp;me:&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;LuaRef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tickfunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mLuaClass&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;tick&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tickfunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isFunction&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;tickfunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mLuaClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; tick isn&amp;#39;t a function: &amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tickfunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;tickfun will &lt;span class="caps"&gt;ALWAYS&lt;/span&gt; be &lt;code&gt;nil&lt;/code&gt; in because clang will convert &amp;#8216;tick&amp;#8217; in to an integer (note the single quotes, not double quotes for the string &lt;code&gt;tick&lt;/code&gt;). You need to access the table&amp;nbsp;thusly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;LuaRef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tickfunc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mLuaClass&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tick&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;to get access to the&amp;nbsp;function.&lt;/p&gt;
&lt;p&gt;There is a setting in XCode to warn about this conversion but it&amp;#8217;s off by default. Using single quotes is a habit I&amp;#8217;ve picked up from Python&amp;nbsp;unfortunately.&lt;/p&gt;
&lt;h4 id="cant-use-luaref-in-a-std-container"&gt;Can&amp;#8217;t use LuaRef in a std::&amp;nbsp;container&lt;/h4&gt;
&lt;p&gt;Because the default constructor for a &lt;code&gt;LuaRef&lt;/code&gt; takes one parameter (the &lt;code&gt;lua_State&lt;/code&gt; that it belongs to) if you try to create a map&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LuaRef&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You will get a compiler&amp;nbsp;error.&lt;/p&gt;</content><category term="gamedev"></category><category term="C++"></category><category term="GameDev"></category><category term="Lua"></category></entry><entry><title>Moving from qmake to CMake</title><link href="https://www.executionunit.com/blog/2014/01/22/moving-from-qmake-to-cmake/" rel="alternate"></link><published>2014-01-22T00:00:00+00:00</published><updated>2014-01-22T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2014-01-22:/blog/2014/01/22/moving-from-qmake-to-cmake/</id><summary type="html">&lt;p&gt;After working with Qt5.x for a few months and really starting to enjoy the flexibility of &lt;code&gt;qmake&lt;/code&gt; and &lt;code&gt;QtCreator&lt;/code&gt; I decided to try using &lt;a href="http://www.cmake.oth"&gt;CMake&lt;/a&gt; to build &lt;code&gt;XCode&lt;/code&gt; and &lt;code&gt;MSVC&lt;/code&gt; proejcts.&lt;/p&gt;
&lt;p&gt;After turning on &lt;code&gt;C++11&lt;/code&gt; a few weeks ago I found that &lt;code&gt;QtCreator&lt;/code&gt; debugging became more difficult as …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After working with Qt5.x for a few months and really starting to enjoy the flexibility of &lt;code&gt;qmake&lt;/code&gt; and &lt;code&gt;QtCreator&lt;/code&gt; I decided to try using &lt;a href="http://www.cmake.oth"&gt;CMake&lt;/a&gt; to build &lt;code&gt;XCode&lt;/code&gt; and &lt;code&gt;MSVC&lt;/code&gt; proejcts.&lt;/p&gt;
&lt;p&gt;After turning on &lt;code&gt;C++11&lt;/code&gt; a few weeks ago I found that &lt;code&gt;QtCreator&lt;/code&gt; debugging became more difficult as it couldn&amp;#8217;t show me the contents of any of the &lt;code&gt;std&lt;/code&gt; containers (vector, list, map etc) without me manually digging in the the internal structure of the class which is quite&amp;nbsp;tedious.&lt;/p&gt;
&lt;p&gt;I was worried about leaving begind &lt;code&gt;qmake&lt;/code&gt; which to be honst is one of the better make systems out there but I couldn&amp;#8217;t tolerate not being able to easily see the data in my app and there has always been a nagging doubt that &lt;code&gt;qmake&lt;/code&gt; isn&amp;#8217;t flexible enough to allow me to build an editor and a game engine from the same source code with the minimum of&amp;nbsp;fuss.&lt;/p&gt;
&lt;p&gt;There are a lot of posts on the internet about &lt;code&gt;CMake&lt;/code&gt; not working with the lastest XCode but, bar a few gripes, those issues seem to have been ironed out with the latest CMake (I&amp;#8217;m using CMake&amp;nbsp;2.8.12.1).&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve never used CMake before it uses a heirachy of &lt;code&gt;CMakeLists.txt&lt;/code&gt; files to generate platform specific make file, XCode projects or &lt;span class="caps"&gt;MSVC&lt;/span&gt; Solutions (amongst other&amp;nbsp;targets).&lt;/p&gt;
&lt;p&gt;The qmake project I started with used the template &lt;code&gt;subdirs&lt;/code&gt; which means it was a folder with sub folders with the actual code in it. This is the most common scenario for a reasonably large Qt&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;Creating the CMakeLists.txt files was a manual process of taking the &lt;code&gt;.pro&lt;/code&gt; file and copying across the &lt;code&gt;SOURCE&lt;/code&gt;and &lt;code&gt;HEADERS&lt;/code&gt; definitions to the &lt;code&gt;add_executable&lt;/code&gt; statement within the CMakeLists.txt file. For example the &lt;a href="http://glew.sourceforge.net"&gt;glew&lt;/a&gt;&amp;nbsp;library:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cache()
! include( ../common.pri ) {
    error( &amp;quot;Couldn&amp;#39;t find the common.pri file!&amp;quot; )
}

DEFINES += GLEW_STATIC

TARGET = glew
TEMPLATE = lib
CONFIG += staticlib

SOURCES += \
    glew.c

HEADERS += \
    glew.h \
    glxew.h \
    wglew.h
unix:!symbian {
    target.path = /usr/lib
    INSTALLS += target
}

OTHER_FILES += \
    readme.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;is transformed&amp;nbsp;to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;add_definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;-DGLEW_STATIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;#disable all warning for third party libs&lt;/span&gt;
&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Darwin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_CXX_FLAGS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;${CMAKE_CXX_FLAGS} -w&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Darwin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nb"&gt;add_library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;glew&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;glew.c&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;glew.h&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;glxew.h&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;wglew.h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nice and short and fairly simple to&amp;nbsp;read.&lt;/p&gt;
&lt;p&gt;CMake has specific support building and linking Qt5 applications and it makes the process of working with Qt &lt;em&gt;reasonably&lt;/em&gt;&amp;nbsp;simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_PREFIX_PATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;C:\\Qt\\Qt5.2.0\\5.2.0\\msvc2010_opengl&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;C:\\WinDDK\\7600.16385.1\\lib\\win7\\i386&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;else&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_PREFIX_PATH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;~/Qt5.2.0/5.2.0/clang_64/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c"&gt;# Find includes in corresponding build directories&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_INCLUDE_CURRENT_DIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# Instruct CMake to run moc automatically when needed.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;CMAKE_AUTOMOC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Find the QtWidgets library&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Qt5Widgets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;Qt5Declarative&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;find_package&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;OpenGL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;add_definitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;-DGLEW_STATIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nb"&gt;qt5_wrap_ui&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;UI_HEADERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mainwindow.ui&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;qt5_add_resources&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;UI_RESOURCES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;bsed.qrc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;add_executable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BSEd&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;MACOSX_BUNDLE&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;mainwindow.cpp&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;BSEd.icns&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;UI_HEADERS&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;UI_RESOURCES&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;MACOSX_BUNDLE_ICON_FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;BSEd.icns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;SET_SOURCE_FILES_PROPERTIES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;BSEd.icns&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;PROPERTIES&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;MACOSX_PACKAGE_LOCATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Resources&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;target_link_libraries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BSEd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Bullet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;glew&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;LibPng&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;LibZLib&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;Polyvox&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;voxcol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;voxcore&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;voxdata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;voxmath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;voxrend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;voxscene&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OPENGL_LIBRARY&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Qt5Core_QTMAIN_LIBRARIES&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set_target_properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BSEd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PROPERTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;LINK_FLAGS_DEBUG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/SUBSYSTEM:WINDOWS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set_target_properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BSEd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PROPERTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;LINK_FLAGS_RELEASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/SUBSYSTEM:WINDOWS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;qt5_use_modules&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BSEd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Widgets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;OpenGL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important parts&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;set &lt;code&gt;CMAKE_PREFIX_PATH&lt;/code&gt; to include the path to Qt. Otherwise &lt;code&gt;find_package&lt;/code&gt; will fail. It&amp;#8217;s probably better to use some sort of environment variable for this but since I work on my own I can hard code&amp;nbsp;things.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set(CMAKE_INCLUDE_CURRENT_DIR ON)&lt;/code&gt; so that moc&amp;#8217;ed files can be found during the&amp;nbsp;build.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set(CMAKE_AUTOMOC ON)&lt;/code&gt; enable the mocing of files with &lt;code&gt;QOBJECT&lt;/code&gt; defined in&amp;nbsp;them.&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;find_package&lt;/code&gt; to find the Qt libraries that the app&amp;nbsp;uses.&lt;/li&gt;
&lt;li&gt;tell cmake which &lt;span class="caps"&gt;UI&lt;/span&gt; files you are using. &lt;code&gt;qt5_wrap_ui(UI_HEADERS mainwindow.ui)&lt;/code&gt; stores the result in the variable &lt;code&gt;UI_HEADERS&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;tell cmake which resource files you are compiling. &lt;code&gt;qt5_add_resources(UI_RESOURCES bsed.qrc)&lt;/code&gt; stores the result in the variable&lt;code&gt;UI_RESOURCES&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;make sure you add &lt;code&gt;UI_HEADERS&lt;/code&gt; and &lt;code&gt;UI_RESOURCES&lt;/code&gt; to the &lt;code&gt;add_executable&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;tell cmake to link with the Qt libraires in &lt;code&gt;target_link_libraries&lt;/code&gt; using &lt;code&gt;{Qt5Core_QTMAIN_LIBRARIES}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On windows I found that the default application type was a console app. I didn&amp;#8217;t want a little dos box to appear when I ran my app so I changed the subsystem from &lt;code&gt;CONSOLE&lt;/code&gt; to &lt;code&gt;WINDOWS&lt;/code&gt; with the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set_target_properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BSEd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PROPERTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;LINK_FLAGS_DEBUG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/SUBSYSTEM:WINDOWS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;set_target_properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;BSEd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;PROPERTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;LINK_FLAGS_RELEASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/SUBSYSTEM:WINDOWS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_SYSTEM_NAME&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;MATCHES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All of this took about three hours to figure out and get working on &lt;span class="caps"&gt;OSX&lt;/span&gt; and&amp;nbsp;Windows7.&lt;/p&gt;
&lt;p&gt;What I&amp;#8217;ve&amp;nbsp;gained:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I get to use the native debugging tools which on &lt;span class="caps"&gt;OSX&lt;/span&gt; and Windows7 are faster than&amp;nbsp;QtCreator.&lt;/li&gt;
&lt;li&gt;I get to use Xcode and &lt;span class="caps"&gt;MSVC&lt;/span&gt; for editting code both of which has useful features. Especially Xcodes real time error detection. It&amp;#8217;s nice to be told your code is &lt;em&gt;fail&lt;/em&gt; before you&amp;#8217;ve even finished typing it all&amp;nbsp;in.&lt;/li&gt;
&lt;li&gt;I get to see inside std containers on both platforms with C++11&amp;nbsp;enabled.&lt;/li&gt;
&lt;li&gt;I much more powerful build system that can cater for multiple targets and build&amp;nbsp;configurations.&lt;/li&gt;
&lt;li&gt;A blog post about something&amp;nbsp;;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;what I&amp;#8217;ve&amp;nbsp;lost:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the same editor/debugger (QtCreator) on all platforms. It&amp;#8217;s quite nice to move from one machine to the next and the default key bindings are the&amp;nbsp;same.&lt;/li&gt;
&lt;li&gt;precompiled headers. This is a big one. CMake doesn&amp;#8217;t support &lt;span class="caps"&gt;PCH&lt;/span&gt; out of the box, there is a plugin for CMake called &lt;a href="https://github.com/sakra/cotire"&gt;cotire&lt;/a&gt; but I haven&amp;#8217;t tried it&amp;nbsp;yet.&lt;/li&gt;
&lt;li&gt;the simplicity of &lt;code&gt;qmake&lt;/code&gt;. CMake is much more powerful and consequently much more tricky to use. Cmake has a lot of documentation but you&amp;#8217;ll need good google-fu to find answers&amp;nbsp;quickly.&lt;/li&gt;
&lt;li&gt;If you use QtCreator and qmake it feels like you are inside the Qt club. Using CMake seems more brittle and I am now worried that any upgrade to XCode (in particular) will break the build&amp;nbsp;process.&lt;/li&gt;
&lt;li&gt;A few hours of my&amp;nbsp;time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hope that helps someone out&amp;nbsp;there.&lt;/p&gt;</content><category term="gamedev"></category><category term="C++"></category><category term="GameDev"></category></entry><entry><title>GLSL: Getting active uniforms</title><link href="https://www.executionunit.com/blog/2014/01/03/glsl-getting-active-uniforms/" rel="alternate"></link><published>2014-01-03T00:00:00+00:00</published><updated>2014-01-03T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2014-01-03:/blog/2014/01/03/glsl-getting-active-uniforms/</id><summary type="html">&lt;p&gt;When you load a vertex and fragment shader in OpenGL you need to pass in data such as the current viewport transform, camera transform and lighting data. You do this via &lt;code&gt;Uniform&lt;/code&gt; variables.&lt;/p&gt;
&lt;p&gt;Each of these Uniforms is addressed via a location which in true OpenGL style is a &lt;code&gt;GLuint …&lt;/code&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;When you load a vertex and fragment shader in OpenGL you need to pass in data such as the current viewport transform, camera transform and lighting data. You do this via &lt;code&gt;Uniform&lt;/code&gt; variables.&lt;/p&gt;
&lt;p&gt;Each of these Uniforms is addressed via a location which in true OpenGL style is a &lt;code&gt;GLuint&lt;/code&gt;. It&amp;#8217;s pretty slow to get the location of a Uniform so it&amp;#8217;s advisable to cache the location before using the shader in anger. Here is the code to get the location of all &lt;strong&gt;&lt;span class="caps"&gt;ACTIVE&lt;/span&gt;&lt;/strong&gt; uniforms in a &lt;a href="http://www.opengl.org/sdk/docs/man4/xhtml/glCompileShader.xml"&gt;compiled&lt;/a&gt; and &lt;a href="http://www.opengl.org/sdk/docs/man4/xhtml/glLinkProgram.xml"&gt;linked&lt;/a&gt; shader&amp;nbsp;program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numUni&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;GLCHECK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;glGetProgramiv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mProgram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GL_ACTIVE_UNIFORMS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;numUni&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numUni&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;namelen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;GLenum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GL_ZERO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//assume no variable names longer than 256&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Get the name of the ith Uniform */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;glGetActiveUniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mProgram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GLuint&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;namelen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;namelen&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* Get the location of the named uniform */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;GLuint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;glGetUniformLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mProgram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* cache the location of the Uniforms in a std::map&lt;/span&gt;
&lt;span class="cm"&gt;    mUniformMap[name] = location;&lt;/span&gt;
&lt;span class="cm"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The docs for &lt;a href="http://www.opengl.org/sdk/docs/man4/xhtml/glGetActiveUniform.xml"&gt;glGetActiveUniform&lt;/a&gt; document the types returned in &lt;code&gt;type&lt;/code&gt; but in general it&amp;#8217;s not useful information during&amp;nbsp;runtime.&lt;/p&gt;
&lt;p&gt;Note this only finds &lt;strong&gt;active&lt;/strong&gt; uniforms so if you have a uniform declared but &lt;strong&gt;you don&amp;#8217;t use it&lt;/strong&gt; it&amp;#8217;s stripped by the shader compiler and will not&amp;nbsp;appear.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="OpenGL"></category><category term="C++"></category></entry><entry><title>QMAKE_BUNDLE_DATA doesn’t bundle frameworks</title><link href="https://www.executionunit.com/blog/2013/12/16/qmake_bundle_data-doesnt-bundle-frameworks/" rel="alternate"></link><published>2013-12-16T00:00:00+00:00</published><updated>2013-12-16T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2013-12-16:/blog/2013/12/16/qmake_bundle_data-doesnt-bundle-frameworks/</id><summary type="html">&lt;p&gt;I&amp;#8217;ve been playing with building an App using &lt;a href="http://qt-project.org/doc/qt-5/qmake-manual.html"&gt;qmake&lt;/a&gt; as the build system. I started with a simple &lt;span class="caps"&gt;QT&lt;/span&gt; App built using the wizard in QTCreator and tweaking&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;I ran in to the problem that I needed to copy the &lt;a href="http://www.sfml-dev.org"&gt;&lt;span class="caps"&gt;SFML&lt;/span&gt;&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Software_framework"&gt;frameworks&lt;/a&gt; in to the App Bundle. The …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve been playing with building an App using &lt;a href="http://qt-project.org/doc/qt-5/qmake-manual.html"&gt;qmake&lt;/a&gt; as the build system. I started with a simple &lt;span class="caps"&gt;QT&lt;/span&gt; App built using the wizard in QTCreator and tweaking&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;I ran in to the problem that I needed to copy the &lt;a href="http://www.sfml-dev.org"&gt;&lt;span class="caps"&gt;SFML&lt;/span&gt;&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Software_framework"&gt;frameworks&lt;/a&gt; in to the App Bundle. The &lt;span class="caps"&gt;QT&lt;/span&gt; docs say to use the variable &lt;code&gt;QMAKE_BUNDLE_DATA&lt;/code&gt; to trigger the copy but I couldn&amp;#8217;t get it to work in &lt;span class="caps"&gt;QT5&lt;/span&gt;.2.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mac{
    PRIVATE_FRAMEWORKS.files = /Users/dazza/work/SFML-2.1-osx-clang-universal/Frameworks/sfml-audio.framework
    PRIVATE_FRAMEWORKS.path = Contents/Frameworks
    QMAKE_BUNDLE_DATA += PRIVATE_FRAMEWORKS
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No matter what I tried I couldn&amp;#8217;t trigger the copying of the&amp;nbsp;framework.&lt;/p&gt;
&lt;p&gt;The work around I came up with involves adding a post link step to copy the frameworks using &lt;a href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/ditto.1.html"&gt;ditto&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mac{
    BUNDLE_DIR = $$OUT_PWD/$$TARGET$$quote(.app)/Contents
    QMAKE_POST_LINK += echo Copy Frameworks; \
                   mkdir -p $$BUNDLE_DIR/Frameworks;\
                   ditto \&amp;quot;/Users/dazza/work/SFML-2.1-osx-clang-universal/Frameworks/\&amp;quot; \&amp;quot;$$BUNDLE_DIR/Frameworks\&amp;quot;;\
                   ditto \&amp;quot;/Users/dazza/work/SFML-2.1-osx-clang-universal/extlibs/\&amp;quot; \&amp;quot;$$BUNDLE_DIR/Frameworks\&amp;quot;;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;QMAKE_POST_LINK&lt;/code&gt; variable has a script&amp;nbsp;to&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;echo that it&amp;#8217;s copying the frameworks&amp;nbsp;across.&lt;/li&gt;
&lt;li&gt;make sure there is a framework directory in the App&amp;nbsp;Bundle.&lt;/li&gt;
&lt;li&gt;Copy the &lt;span class="caps"&gt;SFML&lt;/span&gt; frameworks&amp;nbsp;across.&lt;/li&gt;
&lt;li&gt;Copy the &lt;span class="caps"&gt;SFML&lt;/span&gt; external dependencies&amp;nbsp;across.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Note I know there is a horrible hardcoded path in there that shouldn&amp;#8217;t be there but this is just for&amp;nbsp;testing!&lt;/em&gt;&lt;/p&gt;</content><category term="misc"></category><category term="C++"></category><category term="Dev"></category></entry><entry><title>Python Script to build a Texture Page or Sprite Sheet</title><link href="https://www.executionunit.com/blog/2013/04/12/python-script-to-build-a-texture-page-or-sprite-sheet/" rel="alternate"></link><published>2013-04-12T00:00:00+01:00</published><updated>2013-04-12T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2013-04-12:/blog/2013/04/12/python-script-to-build-a-texture-page-or-sprite-sheet/</id><summary type="html">&lt;h2 id="why-pack-texturesimages"&gt;Why pack&amp;nbsp;textures/images?&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;re making a game then it&amp;#8217;s more efficient to tell the&amp;nbsp;hardware:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;packed&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="n"&gt;primitive&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;packed&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="n"&gt;primitive&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;than&amp;nbsp;to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3 …&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;</summary><content type="html">&lt;h2 id="why-pack-texturesimages"&gt;Why pack&amp;nbsp;textures/images?&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;re making a game then it&amp;#8217;s more efficient to tell the&amp;nbsp;hardware:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;packed&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="n"&gt;primitive&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;packed&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="n"&gt;primitive&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;than&amp;nbsp;to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="n"&gt;primitive&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="n"&gt;primitive&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The less you do, the more efficient rendering&amp;nbsp;is.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re making a website then again it&amp;#8217;s quicker to ask the client browser to load one large image (often called a &lt;strong&gt;sprite sheet&lt;/strong&gt;) than to ask it to load many more smaller&amp;nbsp;textures.&lt;/p&gt;
&lt;h2 id="algorithm"&gt;Algorithm&lt;/h2&gt;
&lt;p&gt;The algorithm we are going to use in called &lt;a href="https://en.wikipedia.org/wiki/Bin_packing_problem_"&gt;Bin Packing&lt;/a&gt;. We want to pack the textures in to one larger texture with the minimum of wasted space. &lt;em&gt;Note that there will always be some wasted space, this is an &lt;a href="http://en.wikipedia.org/wiki/NP_complete"&gt;&lt;span class="caps"&gt;NP&lt;/span&gt; complete&lt;/a&gt; problem and Bin Packing just gives you a very good solution &lt;strong&gt;not&lt;/strong&gt; a perfect&amp;nbsp;one&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;2D bin packing works by using the source images to subdivide the destination image creating a tree of &amp;#8216;used&amp;#8217; areas of the destination image. This sounds a little complication but it&amp;#8217;s actually pretty&amp;nbsp;simple.&lt;/p&gt;
&lt;h2 id="code-overview"&gt;Code&amp;nbsp;Overview&lt;/h2&gt;
&lt;h3 id="class-binpacknode"&gt;class&amp;nbsp;BinPackNode&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;BinPackNode&lt;/code&gt; does the work of subdividing space and recording the tree structure of subdivisions creating left and right children. The &lt;code&gt;BinPackNode&lt;/code&gt; has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;area&lt;/code&gt; which represent the sub rectangle of this image this node&amp;nbsp;covers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;leftchild&lt;/code&gt;, &lt;code&gt;rightchild&lt;/code&gt; if this node has been subdivided &lt;code&gt;leftchild&lt;/code&gt; and &lt;code&gt;rightchild&lt;/code&gt; are &lt;code&gt;BinPackNode&lt;/code&gt;s representing the split of this&amp;nbsp;node.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;leftchild&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rightchild&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;filled&lt;/code&gt; is a boolean indicating that this node has been filled with an image and can&amp;#8217;t be&amp;nbsp;subdivided.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="def-pack_images"&gt;def&amp;nbsp;pack_images&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pack_images&lt;/code&gt; is a function that does the grunt work of trawling through the images, sorting them in to size order (largest to smallest) and the iteratively adding them to the &lt;code&gt;BinPackNode&lt;/code&gt; tree.&lt;/p&gt;
&lt;h3 id="class-rect"&gt;class&amp;nbsp;Rect&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Rect&lt;/code&gt; is a utility class that represents a rectangle. I used this just to make the logic within &lt;code&gt;BinPackNode.insert&lt;/code&gt; more concise and easier to&amp;nbsp;follow.&lt;/p&gt;
&lt;h3 id="how-does-it-work"&gt;How does it&amp;nbsp;work&lt;/h3&gt;
&lt;p&gt;The psuedocode for &lt;code&gt;pack_images&lt;/code&gt; is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sort&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;
&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="n"&gt;BinPackNode&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;initial&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="n"&gt;BinPackNode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pseudocode for &lt;code&gt;BinPackNode.insert&lt;/code&gt; is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;cant&lt;/span&gt; &lt;span class="n"&gt;fit&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t fit the image in then&lt;/span&gt;
        &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t find the image in to this node&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;filled&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;bigger&lt;/span&gt; &lt;span class="n"&gt;than&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;we&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t fit the image in this node&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;mark&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;filled&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="n"&gt;based&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;
&lt;span class="n"&gt;ask&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2 id="usage"&gt;Usage&lt;/h2&gt;
&lt;p&gt;The python code can be run from the command line to pack a set of PNGs that are in a&amp;nbsp;directory:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;usage:&lt;span class="w"&gt; &lt;/span&gt;txtrpacker.py&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-h&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-v&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-pad&lt;span class="w"&gt; &lt;/span&gt;PAD&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-sort&lt;span class="w"&gt; &lt;/span&gt;SORT&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-maxdim&lt;span class="w"&gt; &lt;/span&gt;MAXDIM&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;--log&lt;span class="w"&gt; &lt;/span&gt;LOG&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;src&lt;span class="w"&gt; &lt;/span&gt;dst

A&lt;span class="w"&gt; &lt;/span&gt;utility&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;take&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;png&lt;span class="w"&gt; &lt;/span&gt;images&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;pack&lt;span class="w"&gt; &lt;/span&gt;them&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;power&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;two&lt;span class="w"&gt; &lt;/span&gt;image
with&lt;span class="w"&gt; &lt;/span&gt;pading.&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;placements&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;images&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;printed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;stdout&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;the
format:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;filename x y x2 y2&amp;quot;&lt;/span&gt;

positional&lt;span class="w"&gt; &lt;/span&gt;arguments:
&lt;span class="w"&gt;  &lt;/span&gt;src&lt;span class="w"&gt;             &lt;/span&gt;src&lt;span class="w"&gt; &lt;/span&gt;directory
&lt;span class="w"&gt;  &lt;/span&gt;dst&lt;span class="w"&gt;             &lt;/span&gt;dest&lt;span class="w"&gt; &lt;/span&gt;png&lt;span class="w"&gt; &lt;/span&gt;file

optional&lt;span class="w"&gt; &lt;/span&gt;arguments:
&lt;span class="w"&gt;  &lt;/span&gt;-h,&lt;span class="w"&gt; &lt;/span&gt;--help&lt;span class="w"&gt;      &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;help&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;message&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;-v&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;verbose&lt;span class="w"&gt; &lt;/span&gt;mode
&lt;span class="w"&gt;  &lt;/span&gt;-pad&lt;span class="w"&gt; &lt;/span&gt;PAD&lt;span class="w"&gt;        &lt;/span&gt;padding&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;each&lt;span class="w"&gt; &lt;/span&gt;side&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;texture&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;default:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;-sort&lt;span class="w"&gt; &lt;/span&gt;SORT&lt;span class="w"&gt;      &lt;/span&gt;sort&lt;span class="w"&gt; &lt;/span&gt;algorithm&lt;span class="w"&gt; &lt;/span&gt;one&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;maxheight,maxwidth,maxarea&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;default:
&lt;span class="w"&gt;                  &lt;/span&gt;maxarea&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;-maxdim&lt;span class="w"&gt; &lt;/span&gt;MAXDIM&lt;span class="w"&gt;  &lt;/span&gt;maximum&lt;span class="w"&gt; &lt;/span&gt;texture&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;permissable.
&lt;span class="w"&gt;  &lt;/span&gt;--log&lt;span class="w"&gt; &lt;/span&gt;LOG&lt;span class="w"&gt;       &lt;/span&gt;Logging&lt;span class="w"&gt; &lt;/span&gt;level&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;INFO,&lt;span class="w"&gt; &lt;/span&gt;DEBUG,&lt;span class="w"&gt; &lt;/span&gt;WARN&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;default:&lt;span class="w"&gt; &lt;/span&gt;INFO&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;using the example data you could&amp;nbsp;enter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./txtrpacker.py&lt;span class="w"&gt; &lt;/span&gt;-pad&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./testart&lt;span class="w"&gt; &lt;/span&gt;output.png
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2 id="code"&gt;Code&lt;/h2&gt;
&lt;p&gt;This code can be &lt;a href="http://www.executionunit.com/media/filer_public/2013/04/12/txtrpackertar.gz"&gt;downloaded from this gzip&lt;/a&gt; along with some test art from our iOS game &lt;a href="https://itunes.apple.com/gb/app/max-astro-stranded-beyond/id464084216?mt=8"&gt;Max Astro&lt;/a&gt; and our upcoming game (which isn&amp;#8217;t public yet). I&amp;#8217;ve used to code for a few years so I am pretty confident that it&amp;nbsp;works.&lt;/p&gt;
&lt;h3 id="rectpy"&gt;rect.py&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;
&lt;span class="normal"&gt;56&lt;/span&gt;
&lt;span class="normal"&gt;57&lt;/span&gt;
&lt;span class="normal"&gt;58&lt;/span&gt;
&lt;span class="normal"&gt;59&lt;/span&gt;
&lt;span class="normal"&gt;60&lt;/span&gt;
&lt;span class="normal"&gt;61&lt;/span&gt;
&lt;span class="normal"&gt;62&lt;/span&gt;
&lt;span class="normal"&gt;63&lt;/span&gt;
&lt;span class="normal"&gt;64&lt;/span&gt;
&lt;span class="normal"&gt;65&lt;/span&gt;
&lt;span class="normal"&gt;66&lt;/span&gt;
&lt;span class="normal"&gt;67&lt;/span&gt;
&lt;span class="normal"&gt;68&lt;/span&gt;
&lt;span class="normal"&gt;69&lt;/span&gt;
&lt;span class="normal"&gt;70&lt;/span&gt;
&lt;span class="normal"&gt;71&lt;/span&gt;
&lt;span class="normal"&gt;72&lt;/span&gt;
&lt;span class="normal"&gt;73&lt;/span&gt;
&lt;span class="normal"&gt;74&lt;/span&gt;
&lt;span class="normal"&gt;75&lt;/span&gt;
&lt;span class="normal"&gt;76&lt;/span&gt;
&lt;span class="normal"&gt;77&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;__all__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Rect&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Represent a rectangle in the BinPack tree.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x1&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;  &lt;span class="c1"&gt;# bottom&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x2&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y2&lt;/span&gt;  &lt;span class="c1"&gt;# top&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_width&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_height&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_width&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_top&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_top&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_height&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_bottom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_bottom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_height&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y1&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;return a rect which is this rect inset by d in each direction&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inside&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;return true if this rectangle is inside r&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;\
               &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt;

    &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;set_width&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;set_height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;set_left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;set_top&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;set_bottom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;[&lt;/span&gt;&lt;span class="si"&gt;%f&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;%f&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;%f&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;%f&lt;/span&gt;&lt;span class="s2"&gt;]&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Rect[&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;]&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h3 id="txtrpackerpy"&gt;txtrpacker.py&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;  1&lt;/span&gt;
&lt;span class="normal"&gt;  2&lt;/span&gt;
&lt;span class="normal"&gt;  3&lt;/span&gt;
&lt;span class="normal"&gt;  4&lt;/span&gt;
&lt;span class="normal"&gt;  5&lt;/span&gt;
&lt;span class="normal"&gt;  6&lt;/span&gt;
&lt;span class="normal"&gt;  7&lt;/span&gt;
&lt;span class="normal"&gt;  8&lt;/span&gt;
&lt;span class="normal"&gt;  9&lt;/span&gt;
&lt;span class="normal"&gt; 10&lt;/span&gt;
&lt;span class="normal"&gt; 11&lt;/span&gt;
&lt;span class="normal"&gt; 12&lt;/span&gt;
&lt;span class="normal"&gt; 13&lt;/span&gt;
&lt;span class="normal"&gt; 14&lt;/span&gt;
&lt;span class="normal"&gt; 15&lt;/span&gt;
&lt;span class="normal"&gt; 16&lt;/span&gt;
&lt;span class="normal"&gt; 17&lt;/span&gt;
&lt;span class="normal"&gt; 18&lt;/span&gt;
&lt;span class="normal"&gt; 19&lt;/span&gt;
&lt;span class="normal"&gt; 20&lt;/span&gt;
&lt;span class="normal"&gt; 21&lt;/span&gt;
&lt;span class="normal"&gt; 22&lt;/span&gt;
&lt;span class="normal"&gt; 23&lt;/span&gt;
&lt;span class="normal"&gt; 24&lt;/span&gt;
&lt;span class="normal"&gt; 25&lt;/span&gt;
&lt;span class="normal"&gt; 26&lt;/span&gt;
&lt;span class="normal"&gt; 27&lt;/span&gt;
&lt;span class="normal"&gt; 28&lt;/span&gt;
&lt;span class="normal"&gt; 29&lt;/span&gt;
&lt;span class="normal"&gt; 30&lt;/span&gt;
&lt;span class="normal"&gt; 31&lt;/span&gt;
&lt;span class="normal"&gt; 32&lt;/span&gt;
&lt;span class="normal"&gt; 33&lt;/span&gt;
&lt;span class="normal"&gt; 34&lt;/span&gt;
&lt;span class="normal"&gt; 35&lt;/span&gt;
&lt;span class="normal"&gt; 36&lt;/span&gt;
&lt;span class="normal"&gt; 37&lt;/span&gt;
&lt;span class="normal"&gt; 38&lt;/span&gt;
&lt;span class="normal"&gt; 39&lt;/span&gt;
&lt;span class="normal"&gt; 40&lt;/span&gt;
&lt;span class="normal"&gt; 41&lt;/span&gt;
&lt;span class="normal"&gt; 42&lt;/span&gt;
&lt;span class="normal"&gt; 43&lt;/span&gt;
&lt;span class="normal"&gt; 44&lt;/span&gt;
&lt;span class="normal"&gt; 45&lt;/span&gt;
&lt;span class="normal"&gt; 46&lt;/span&gt;
&lt;span class="normal"&gt; 47&lt;/span&gt;
&lt;span class="normal"&gt; 48&lt;/span&gt;
&lt;span class="normal"&gt; 49&lt;/span&gt;
&lt;span class="normal"&gt; 50&lt;/span&gt;
&lt;span class="normal"&gt; 51&lt;/span&gt;
&lt;span class="normal"&gt; 52&lt;/span&gt;
&lt;span class="normal"&gt; 53&lt;/span&gt;
&lt;span class="normal"&gt; 54&lt;/span&gt;
&lt;span class="normal"&gt; 55&lt;/span&gt;
&lt;span class="normal"&gt; 56&lt;/span&gt;
&lt;span class="normal"&gt; 57&lt;/span&gt;
&lt;span class="normal"&gt; 58&lt;/span&gt;
&lt;span class="normal"&gt; 59&lt;/span&gt;
&lt;span class="normal"&gt; 60&lt;/span&gt;
&lt;span class="normal"&gt; 61&lt;/span&gt;
&lt;span class="normal"&gt; 62&lt;/span&gt;
&lt;span class="normal"&gt; 63&lt;/span&gt;
&lt;span class="normal"&gt; 64&lt;/span&gt;
&lt;span class="normal"&gt; 65&lt;/span&gt;
&lt;span class="normal"&gt; 66&lt;/span&gt;
&lt;span class="normal"&gt; 67&lt;/span&gt;
&lt;span class="normal"&gt; 68&lt;/span&gt;
&lt;span class="normal"&gt; 69&lt;/span&gt;
&lt;span class="normal"&gt; 70&lt;/span&gt;
&lt;span class="normal"&gt; 71&lt;/span&gt;
&lt;span class="normal"&gt; 72&lt;/span&gt;
&lt;span class="normal"&gt; 73&lt;/span&gt;
&lt;span class="normal"&gt; 74&lt;/span&gt;
&lt;span class="normal"&gt; 75&lt;/span&gt;
&lt;span class="normal"&gt; 76&lt;/span&gt;
&lt;span class="normal"&gt; 77&lt;/span&gt;
&lt;span class="normal"&gt; 78&lt;/span&gt;
&lt;span class="normal"&gt; 79&lt;/span&gt;
&lt;span class="normal"&gt; 80&lt;/span&gt;
&lt;span class="normal"&gt; 81&lt;/span&gt;
&lt;span class="normal"&gt; 82&lt;/span&gt;
&lt;span class="normal"&gt; 83&lt;/span&gt;
&lt;span class="normal"&gt; 84&lt;/span&gt;
&lt;span class="normal"&gt; 85&lt;/span&gt;
&lt;span class="normal"&gt; 86&lt;/span&gt;
&lt;span class="normal"&gt; 87&lt;/span&gt;
&lt;span class="normal"&gt; 88&lt;/span&gt;
&lt;span class="normal"&gt; 89&lt;/span&gt;
&lt;span class="normal"&gt; 90&lt;/span&gt;
&lt;span class="normal"&gt; 91&lt;/span&gt;
&lt;span class="normal"&gt; 92&lt;/span&gt;
&lt;span class="normal"&gt; 93&lt;/span&gt;
&lt;span class="normal"&gt; 94&lt;/span&gt;
&lt;span class="normal"&gt; 95&lt;/span&gt;
&lt;span class="normal"&gt; 96&lt;/span&gt;
&lt;span class="normal"&gt; 97&lt;/span&gt;
&lt;span class="normal"&gt; 98&lt;/span&gt;
&lt;span class="normal"&gt; 99&lt;/span&gt;
&lt;span class="normal"&gt;100&lt;/span&gt;
&lt;span class="normal"&gt;101&lt;/span&gt;
&lt;span class="normal"&gt;102&lt;/span&gt;
&lt;span class="normal"&gt;103&lt;/span&gt;
&lt;span class="normal"&gt;104&lt;/span&gt;
&lt;span class="normal"&gt;105&lt;/span&gt;
&lt;span class="normal"&gt;106&lt;/span&gt;
&lt;span class="normal"&gt;107&lt;/span&gt;
&lt;span class="normal"&gt;108&lt;/span&gt;
&lt;span class="normal"&gt;109&lt;/span&gt;
&lt;span class="normal"&gt;110&lt;/span&gt;
&lt;span class="normal"&gt;111&lt;/span&gt;
&lt;span class="normal"&gt;112&lt;/span&gt;
&lt;span class="normal"&gt;113&lt;/span&gt;
&lt;span class="normal"&gt;114&lt;/span&gt;
&lt;span class="normal"&gt;115&lt;/span&gt;
&lt;span class="normal"&gt;116&lt;/span&gt;
&lt;span class="normal"&gt;117&lt;/span&gt;
&lt;span class="normal"&gt;118&lt;/span&gt;
&lt;span class="normal"&gt;119&lt;/span&gt;
&lt;span class="normal"&gt;120&lt;/span&gt;
&lt;span class="normal"&gt;121&lt;/span&gt;
&lt;span class="normal"&gt;122&lt;/span&gt;
&lt;span class="normal"&gt;123&lt;/span&gt;
&lt;span class="normal"&gt;124&lt;/span&gt;
&lt;span class="normal"&gt;125&lt;/span&gt;
&lt;span class="normal"&gt;126&lt;/span&gt;
&lt;span class="normal"&gt;127&lt;/span&gt;
&lt;span class="normal"&gt;128&lt;/span&gt;
&lt;span class="normal"&gt;129&lt;/span&gt;
&lt;span class="normal"&gt;130&lt;/span&gt;
&lt;span class="normal"&gt;131&lt;/span&gt;
&lt;span class="normal"&gt;132&lt;/span&gt;
&lt;span class="normal"&gt;133&lt;/span&gt;
&lt;span class="normal"&gt;134&lt;/span&gt;
&lt;span class="normal"&gt;135&lt;/span&gt;
&lt;span class="normal"&gt;136&lt;/span&gt;
&lt;span class="normal"&gt;137&lt;/span&gt;
&lt;span class="normal"&gt;138&lt;/span&gt;
&lt;span class="normal"&gt;139&lt;/span&gt;
&lt;span class="normal"&gt;140&lt;/span&gt;
&lt;span class="normal"&gt;141&lt;/span&gt;
&lt;span class="normal"&gt;142&lt;/span&gt;
&lt;span class="normal"&gt;143&lt;/span&gt;
&lt;span class="normal"&gt;144&lt;/span&gt;
&lt;span class="normal"&gt;145&lt;/span&gt;
&lt;span class="normal"&gt;146&lt;/span&gt;
&lt;span class="normal"&gt;147&lt;/span&gt;
&lt;span class="normal"&gt;148&lt;/span&gt;
&lt;span class="normal"&gt;149&lt;/span&gt;
&lt;span class="normal"&gt;150&lt;/span&gt;
&lt;span class="normal"&gt;151&lt;/span&gt;
&lt;span class="normal"&gt;152&lt;/span&gt;
&lt;span class="normal"&gt;153&lt;/span&gt;
&lt;span class="normal"&gt;154&lt;/span&gt;
&lt;span class="normal"&gt;155&lt;/span&gt;
&lt;span class="normal"&gt;156&lt;/span&gt;
&lt;span class="normal"&gt;157&lt;/span&gt;
&lt;span class="normal"&gt;158&lt;/span&gt;
&lt;span class="normal"&gt;159&lt;/span&gt;
&lt;span class="normal"&gt;160&lt;/span&gt;
&lt;span class="normal"&gt;161&lt;/span&gt;
&lt;span class="normal"&gt;162&lt;/span&gt;
&lt;span class="normal"&gt;163&lt;/span&gt;
&lt;span class="normal"&gt;164&lt;/span&gt;
&lt;span class="normal"&gt;165&lt;/span&gt;
&lt;span class="normal"&gt;166&lt;/span&gt;
&lt;span class="normal"&gt;167&lt;/span&gt;
&lt;span class="normal"&gt;168&lt;/span&gt;
&lt;span class="normal"&gt;169&lt;/span&gt;
&lt;span class="normal"&gt;170&lt;/span&gt;
&lt;span class="normal"&gt;171&lt;/span&gt;
&lt;span class="normal"&gt;172&lt;/span&gt;
&lt;span class="normal"&gt;173&lt;/span&gt;
&lt;span class="normal"&gt;174&lt;/span&gt;
&lt;span class="normal"&gt;175&lt;/span&gt;
&lt;span class="normal"&gt;176&lt;/span&gt;
&lt;span class="normal"&gt;177&lt;/span&gt;
&lt;span class="normal"&gt;178&lt;/span&gt;
&lt;span class="normal"&gt;179&lt;/span&gt;
&lt;span class="normal"&gt;180&lt;/span&gt;
&lt;span class="normal"&gt;181&lt;/span&gt;
&lt;span class="normal"&gt;182&lt;/span&gt;
&lt;span class="normal"&gt;183&lt;/span&gt;
&lt;span class="normal"&gt;184&lt;/span&gt;
&lt;span class="normal"&gt;185&lt;/span&gt;
&lt;span class="normal"&gt;186&lt;/span&gt;
&lt;span class="normal"&gt;187&lt;/span&gt;
&lt;span class="normal"&gt;188&lt;/span&gt;
&lt;span class="normal"&gt;189&lt;/span&gt;
&lt;span class="normal"&gt;190&lt;/span&gt;
&lt;span class="normal"&gt;191&lt;/span&gt;
&lt;span class="normal"&gt;192&lt;/span&gt;
&lt;span class="normal"&gt;193&lt;/span&gt;
&lt;span class="normal"&gt;194&lt;/span&gt;
&lt;span class="normal"&gt;195&lt;/span&gt;
&lt;span class="normal"&gt;196&lt;/span&gt;
&lt;span class="normal"&gt;197&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;Image&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;copy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;os.path&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;join&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;glob&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rect&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Rect&lt;/span&gt;

&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BinPackNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;A Node in a tree of recursively smaller areas within which images can be placed.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Create a binpack node&lt;/span&gt;
&lt;span class="sd"&gt;        @param area a Rect describing the area the node covers in texture coorinates&lt;/span&gt;
&lt;span class="sd"&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="c1"&gt;#the area that I take up in the image.&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;
        &lt;span class="c1"&gt;# if I&amp;#39;ve been subdivided then I always have a left/right child&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftchild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rightchild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
        &lt;span class="c1"&gt;#I&amp;#39;m a leaf node and an image would be placed here, I can&amp;#39;t be suddivided.&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__class__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Insert the newarea in to my area.&lt;/span&gt;
&lt;span class="sd"&gt;        @param newarea a Rect to insert in to me by subdividing myself up&lt;/span&gt;
&lt;span class="sd"&gt;        @return the area filled or None if the newarea couldn&amp;#39;t be accommodated within this&lt;/span&gt;
&lt;span class="sd"&gt;            node tree&lt;/span&gt;
&lt;span class="sd"&gt;        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="c1"&gt;#if I&amp;#39;ve been subdivided already then get my child trees to insert the image.&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftchild&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rightchild&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftchild&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rightchild&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;#If my area has been used (filled) or the area requested is bigger then my&lt;/span&gt;
        &lt;span class="c1"&gt;# area return None. I can&amp;#39;t help you.&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filled&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

        &lt;span class="c1"&gt;#if the image fits exactly in me then yep, the are has been filled&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;

        &lt;span class="c1"&gt;#I am going to subdivide myself, copy my area in to the two children&lt;/span&gt;
        &lt;span class="c1"&gt;# and then massage them to be useful sizes for placing the newarea.&lt;/span&gt;
        &lt;span class="n"&gt;leftarea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;rightarea&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;widthdifference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="n"&gt;heightdifference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;widthdifference&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;heightdifference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;leftarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
            &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
            &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;leftarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
            &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
            &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;

        &lt;span class="c1"&gt;#create my children and then insert it in to the left child which&lt;/span&gt;
        &lt;span class="c1"&gt;#was carefully crafted about to fit in one dimension.&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftchild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BinPackNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;leftarea&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rightchild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BinPackNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rightarea&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftchild&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newarea&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_imagesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;#table of heuristics to sort the list of images by before placing&lt;/span&gt;
&lt;span class="c1"&gt;# them in the BinPack Tree NOTE that they are compared backwards&lt;/span&gt;
&lt;span class="c1"&gt;# as we want to go from big to small (r2-&amp;gt;r1 as opposed to r1-&amp;gt;r2)&lt;/span&gt;
&lt;span class="n"&gt;sort_heuristics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;maxarea&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_imagesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;_imagesize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])),&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;maxwidth&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;maxheight&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pack_images&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imagelist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxdim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dstfilename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;pack the images in image list in to a pow2 PNg file&lt;/span&gt;
&lt;span class="sd"&gt;    @param imagelist iterable of tuples (image name, image)&lt;/span&gt;
&lt;span class="sd"&gt;    @param padding padding to be applied to all sides of the image&lt;/span&gt;
&lt;span class="sd"&gt;    @param dstfilename the filename to save the packed image to.&lt;/span&gt;
&lt;span class="sd"&gt;    @return a list of ( rect, name, image) tuples describing where the images were placed.&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;unsorted order:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;imagelist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="c1"&gt;#sort the images based on the heuristic passed in&lt;/span&gt;
    &lt;span class="n"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imagelist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sort_heuristics&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sorted order:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="c1"&gt;#the start dimension of the target image. this grows&lt;/span&gt;
    &lt;span class="c1"&gt;# by doubling to accomodate the images. Should start&lt;/span&gt;
    &lt;span class="c1"&gt;# on a power of two otherwise it wont end on a power&lt;/span&gt;
    &lt;span class="c1"&gt;# of two. Could possibly start this on the first pow2&lt;/span&gt;
    &lt;span class="c1"&gt;# above the largest image but this works.&lt;/span&gt;
    &lt;span class="n"&gt;targetdim_x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
    &lt;span class="n"&gt;targetdim_y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
    &lt;span class="n"&gt;placement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;placement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BinPackNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetdim_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetdim_y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

            &lt;span class="c1"&gt;#insert each image into the BinPackNode area. If an image fails to insert&lt;/span&gt;
            &lt;span class="c1"&gt;# we start again with a slightly bigger target size.&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;imsize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
                &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Rect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imsize&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imsize&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;uv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;uv&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="c1"&gt;#the tree couldn&amp;#39;t accomodate the area, we&amp;#39;ll need to start again.&lt;/span&gt;
                    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Pack size too small.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;uv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;placement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

            &lt;span class="c1"&gt;#if we get here we&amp;#39;ve found a place for all the images so&lt;/span&gt;
            &lt;span class="c1"&gt;# break from the while True loop&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Taget Dim [&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;] too small&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetdim_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetdim_y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;targetdim_x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;targetdim_y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;targetdim_x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;targetdim_x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;targetdim_x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maxdim&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Too many textures to pack in to max texture size &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxdim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxdim&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;targetdim_y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;targetdim_x&lt;/span&gt;

    &lt;span class="c1"&gt;#save the images to the target file packed&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Packing &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt; images in to &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imagelist&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;targetdim_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetdim_y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;RGBA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetdim_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetdim_y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;placement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;paste&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;#image.show()&lt;/span&gt;
    &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dstfilename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;PNG&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;placement&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;__main__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;A utility to take a set of png images and pack them in to&lt;/span&gt;
&lt;span class="s2"&gt;    a power of two image with padding. The placements of the source images is&lt;/span&gt;
&lt;span class="s2"&gt;    printed to stdout in the format: &amp;quot;filename x y x2 y2&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;_epilog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; example: txtrpacker.py hud/images data/hud/texturepage.png&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epilog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;_epilog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;store_true&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;enable verbose mode&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-pad&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;padding on each side of the texture (default: 2)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-sort&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;maxarea&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sort algorithm one of &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; (default: maxarea)&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sort_heuristics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-maxdim&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;maximum texture size permissable.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;--log&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Logging level (INFO, DEBUG, WARN) (default: INFO)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;INFO&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;src directory&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dst&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dest png file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;numeric_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numeric_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Invalid log level: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;numeric_level&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sort_heuristics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Uknown sort parameter &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#get a list of PNG files in the current directory&lt;/span&gt;
    &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*.png&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;#create a list of PIL Image objects, sorted by size&lt;/span&gt;
    &lt;span class="n"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;placements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pack_images&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxdim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;placements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="Python"></category></entry><entry><title>HP ProLiant MicroServer: thoughts</title><link href="https://www.executionunit.com/blog/2013/03/03/hp-proliant-microserver-thoughts/" rel="alternate"></link><published>2013-03-03T00:00:00+00:00</published><updated>2013-03-03T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2013-03-03:/blog/2013/03/03/hp-proliant-microserver-thoughts/</id><summary type="html">&lt;p&gt;I&amp;#8217;ve been looking for a new home server for a few months. Recently (the last six years) have been running &lt;span class="caps"&gt;EPIA&lt;/span&gt; &lt;a href="http://en.wikipedia.org/wiki/Mini-ITX" title="Wikipedia Mini-ITX page"&gt;Mini-itx&lt;/a&gt; motherboards in &lt;a href="http://www.mini-itx.com/reviews/2688R/"&gt;Cubid&lt;/a&gt; cases. They are basically silent and powerful enough to run a small fileserver and&amp;nbsp;webserver.&lt;/p&gt;
&lt;p&gt;My &lt;span class="caps"&gt;EPIA&lt;/span&gt; boards were starting to show their age …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve been looking for a new home server for a few months. Recently (the last six years) have been running &lt;span class="caps"&gt;EPIA&lt;/span&gt; &lt;a href="http://en.wikipedia.org/wiki/Mini-ITX" title="Wikipedia Mini-ITX page"&gt;Mini-itx&lt;/a&gt; motherboards in &lt;a href="http://www.mini-itx.com/reviews/2688R/"&gt;Cubid&lt;/a&gt; cases. They are basically silent and powerful enough to run a small fileserver and&amp;nbsp;webserver.&lt;/p&gt;
&lt;p&gt;My &lt;span class="caps"&gt;EPIA&lt;/span&gt; boards were starting to show their age. My longest standing board started to emit a high pitched squeel and sure enough it was a sign of an impending capacitor failure. I swapped it out for an identical replacement and within a few months that motherboard started to show similar problems. I now suspect that the power supply is surging, or in some way, &amp;#8216;breaking&amp;#8217; my&amp;nbsp;motherboards.&lt;/p&gt;
&lt;p&gt;So I looked around and noticed that &lt;a href="http://h10010.www1.hp.com/wwpc/uk/en/sm/WF02a/15351-15351-4237916.html?dnr=1" title="HP Microserver landing page"&gt;&lt;span class="caps"&gt;HP&lt;/span&gt; ProLiant Microservers&lt;/a&gt; were back on special offer (£100 cash back from &lt;span class="caps"&gt;HP&lt;/span&gt; if you meet their&amp;nbsp;requirements).&lt;/p&gt;
&lt;p&gt;The specs looked good but I was dubious about it being quiet enough for my home office. I decided to take the plunge mainly because I could buy the &lt;span class="caps"&gt;N40L&lt;/span&gt; for £209 (with £100 cashback so net cost of £109) from &lt;a href="http://www.ebuyer.com"&gt;ebuyer.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here are my brief notes on running it as a &lt;a href="http://www.freebsd.org" title="FreeBSD homepage"&gt;FreeBSD9.x&lt;/a&gt;&amp;nbsp;server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;About 38dB which is quiet enough to have in the next room but too noisy to sleep next&amp;nbsp;to.&lt;/li&gt;
&lt;li&gt;Lights on front very&amp;nbsp;bright.&lt;/li&gt;
&lt;li&gt;Really well built. It&amp;#8217;s not enterprise quality but good enough to sit in the corner of an&amp;nbsp;office.&lt;/li&gt;
&lt;li&gt;Excellent access to drives. The four drive caddies are slightly cheap plastic but once they have a drive they are sturdy enough. Since they are not hot swappable they don&amp;#8217;t need to be rock solid&amp;nbsp;anyway.&lt;/li&gt;
&lt;li&gt;Access to the Motherboard is restrictive due to cabling. You need to unclip a lot of cables from the case and unscrew two thumb screws before you can slide the monthboard out. While this isn&amp;#8217;t done too often it&amp;#8217;s not for the faint&amp;nbsp;hearted.&lt;/li&gt;
&lt;li&gt;Non standard power supply. Might be hard to source a new&amp;nbsp;one.&lt;/li&gt;
&lt;li&gt;I wanted to mount a 2.5&amp;#8221; &lt;span class="caps"&gt;SSD&lt;/span&gt; drive but it didn&amp;#8217;t fit in the caddy. I ended up taping it in to the slot where a &lt;span class="caps"&gt;DVD&lt;/span&gt; drive would go. The motherboard has an extra &lt;span class="caps"&gt;SATA&lt;/span&gt; connector for a &lt;span class="caps"&gt;DVD&lt;/span&gt; drive. This runs at half speed and requires a bios flash to enable full &lt;span class="caps"&gt;SATA&lt;/span&gt;&amp;nbsp;speed.&lt;/li&gt;
&lt;li&gt;The motherboard has an exposed &lt;span class="caps"&gt;USB&lt;/span&gt; slot so it can be booted from a &lt;span class="caps"&gt;USB&lt;/span&gt; stick. The case design leaves space for a &lt;span class="caps"&gt;USB&lt;/span&gt; stick to be permenantly mounted in&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;Runs FreeBSD very well. &lt;span class="caps"&gt;USB&lt;/span&gt;, &lt;span class="caps"&gt;ACPI&lt;/span&gt;, temperature sensors (&lt;a href="http://www.freebsd.org/cgi/man.cgi?query=amdtemp&amp;amp;manpath=FreeBSD+9.1-RELEASE"&gt;amdtemp&lt;/a&gt; module) work. &lt;a href="http://www.freebsd.org/cgi/man.cgi?query=bge&amp;amp;manpath=FreeBSD+9.1-RELEASE"&gt;Broadcom network interface&lt;/a&gt; works well although only tested on my 100mb&amp;nbsp;network.&lt;/li&gt;
&lt;li&gt;Even without the cash back deal this is a very good value server for a small&amp;nbsp;office.&lt;/li&gt;
&lt;li&gt;I am running the i386 version of FreeBSD, I really should run the &lt;span class="caps"&gt;AMD64&lt;/span&gt; but at the moment the box isn&amp;#8217;t too loaded and it was easier to just plug in the drive the the previous server, start it up, change a few /etc/rc.conf entries and be done with&amp;nbsp;it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Basically, when this machine comes back on &lt;em&gt;special offer&lt;/em&gt; at &lt;a href="http://www.ebuyer.com"&gt;ebuyer.com&lt;/a&gt; I will be buying another&amp;nbsp;one.&lt;/p&gt;
&lt;h2 id="output-from-dmesg"&gt;Output from &lt;code&gt;dmesg&lt;/code&gt;&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;  1&lt;/span&gt;
&lt;span class="normal"&gt;  2&lt;/span&gt;
&lt;span class="normal"&gt;  3&lt;/span&gt;
&lt;span class="normal"&gt;  4&lt;/span&gt;
&lt;span class="normal"&gt;  5&lt;/span&gt;
&lt;span class="normal"&gt;  6&lt;/span&gt;
&lt;span class="normal"&gt;  7&lt;/span&gt;
&lt;span class="normal"&gt;  8&lt;/span&gt;
&lt;span class="normal"&gt;  9&lt;/span&gt;
&lt;span class="normal"&gt; 10&lt;/span&gt;
&lt;span class="normal"&gt; 11&lt;/span&gt;
&lt;span class="normal"&gt; 12&lt;/span&gt;
&lt;span class="normal"&gt; 13&lt;/span&gt;
&lt;span class="normal"&gt; 14&lt;/span&gt;
&lt;span class="normal"&gt; 15&lt;/span&gt;
&lt;span class="normal"&gt; 16&lt;/span&gt;
&lt;span class="normal"&gt; 17&lt;/span&gt;
&lt;span class="normal"&gt; 18&lt;/span&gt;
&lt;span class="normal"&gt; 19&lt;/span&gt;
&lt;span class="normal"&gt; 20&lt;/span&gt;
&lt;span class="normal"&gt; 21&lt;/span&gt;
&lt;span class="normal"&gt; 22&lt;/span&gt;
&lt;span class="normal"&gt; 23&lt;/span&gt;
&lt;span class="normal"&gt; 24&lt;/span&gt;
&lt;span class="normal"&gt; 25&lt;/span&gt;
&lt;span class="normal"&gt; 26&lt;/span&gt;
&lt;span class="normal"&gt; 27&lt;/span&gt;
&lt;span class="normal"&gt; 28&lt;/span&gt;
&lt;span class="normal"&gt; 29&lt;/span&gt;
&lt;span class="normal"&gt; 30&lt;/span&gt;
&lt;span class="normal"&gt; 31&lt;/span&gt;
&lt;span class="normal"&gt; 32&lt;/span&gt;
&lt;span class="normal"&gt; 33&lt;/span&gt;
&lt;span class="normal"&gt; 34&lt;/span&gt;
&lt;span class="normal"&gt; 35&lt;/span&gt;
&lt;span class="normal"&gt; 36&lt;/span&gt;
&lt;span class="normal"&gt; 37&lt;/span&gt;
&lt;span class="normal"&gt; 38&lt;/span&gt;
&lt;span class="normal"&gt; 39&lt;/span&gt;
&lt;span class="normal"&gt; 40&lt;/span&gt;
&lt;span class="normal"&gt; 41&lt;/span&gt;
&lt;span class="normal"&gt; 42&lt;/span&gt;
&lt;span class="normal"&gt; 43&lt;/span&gt;
&lt;span class="normal"&gt; 44&lt;/span&gt;
&lt;span class="normal"&gt; 45&lt;/span&gt;
&lt;span class="normal"&gt; 46&lt;/span&gt;
&lt;span class="normal"&gt; 47&lt;/span&gt;
&lt;span class="normal"&gt; 48&lt;/span&gt;
&lt;span class="normal"&gt; 49&lt;/span&gt;
&lt;span class="normal"&gt; 50&lt;/span&gt;
&lt;span class="normal"&gt; 51&lt;/span&gt;
&lt;span class="normal"&gt; 52&lt;/span&gt;
&lt;span class="normal"&gt; 53&lt;/span&gt;
&lt;span class="normal"&gt; 54&lt;/span&gt;
&lt;span class="normal"&gt; 55&lt;/span&gt;
&lt;span class="normal"&gt; 56&lt;/span&gt;
&lt;span class="normal"&gt; 57&lt;/span&gt;
&lt;span class="normal"&gt; 58&lt;/span&gt;
&lt;span class="normal"&gt; 59&lt;/span&gt;
&lt;span class="normal"&gt; 60&lt;/span&gt;
&lt;span class="normal"&gt; 61&lt;/span&gt;
&lt;span class="normal"&gt; 62&lt;/span&gt;
&lt;span class="normal"&gt; 63&lt;/span&gt;
&lt;span class="normal"&gt; 64&lt;/span&gt;
&lt;span class="normal"&gt; 65&lt;/span&gt;
&lt;span class="normal"&gt; 66&lt;/span&gt;
&lt;span class="normal"&gt; 67&lt;/span&gt;
&lt;span class="normal"&gt; 68&lt;/span&gt;
&lt;span class="normal"&gt; 69&lt;/span&gt;
&lt;span class="normal"&gt; 70&lt;/span&gt;
&lt;span class="normal"&gt; 71&lt;/span&gt;
&lt;span class="normal"&gt; 72&lt;/span&gt;
&lt;span class="normal"&gt; 73&lt;/span&gt;
&lt;span class="normal"&gt; 74&lt;/span&gt;
&lt;span class="normal"&gt; 75&lt;/span&gt;
&lt;span class="normal"&gt; 76&lt;/span&gt;
&lt;span class="normal"&gt; 77&lt;/span&gt;
&lt;span class="normal"&gt; 78&lt;/span&gt;
&lt;span class="normal"&gt; 79&lt;/span&gt;
&lt;span class="normal"&gt; 80&lt;/span&gt;
&lt;span class="normal"&gt; 81&lt;/span&gt;
&lt;span class="normal"&gt; 82&lt;/span&gt;
&lt;span class="normal"&gt; 83&lt;/span&gt;
&lt;span class="normal"&gt; 84&lt;/span&gt;
&lt;span class="normal"&gt; 85&lt;/span&gt;
&lt;span class="normal"&gt; 86&lt;/span&gt;
&lt;span class="normal"&gt; 87&lt;/span&gt;
&lt;span class="normal"&gt; 88&lt;/span&gt;
&lt;span class="normal"&gt; 89&lt;/span&gt;
&lt;span class="normal"&gt; 90&lt;/span&gt;
&lt;span class="normal"&gt; 91&lt;/span&gt;
&lt;span class="normal"&gt; 92&lt;/span&gt;
&lt;span class="normal"&gt; 93&lt;/span&gt;
&lt;span class="normal"&gt; 94&lt;/span&gt;
&lt;span class="normal"&gt; 95&lt;/span&gt;
&lt;span class="normal"&gt; 96&lt;/span&gt;
&lt;span class="normal"&gt; 97&lt;/span&gt;
&lt;span class="normal"&gt; 98&lt;/span&gt;
&lt;span class="normal"&gt; 99&lt;/span&gt;
&lt;span class="normal"&gt;100&lt;/span&gt;
&lt;span class="normal"&gt;101&lt;/span&gt;
&lt;span class="normal"&gt;102&lt;/span&gt;
&lt;span class="normal"&gt;103&lt;/span&gt;
&lt;span class="normal"&gt;104&lt;/span&gt;
&lt;span class="normal"&gt;105&lt;/span&gt;
&lt;span class="normal"&gt;106&lt;/span&gt;
&lt;span class="normal"&gt;107&lt;/span&gt;
&lt;span class="normal"&gt;108&lt;/span&gt;
&lt;span class="normal"&gt;109&lt;/span&gt;
&lt;span class="normal"&gt;110&lt;/span&gt;
&lt;span class="normal"&gt;111&lt;/span&gt;
&lt;span class="normal"&gt;112&lt;/span&gt;
&lt;span class="normal"&gt;113&lt;/span&gt;
&lt;span class="normal"&gt;114&lt;/span&gt;
&lt;span class="normal"&gt;115&lt;/span&gt;
&lt;span class="normal"&gt;116&lt;/span&gt;
&lt;span class="normal"&gt;117&lt;/span&gt;
&lt;span class="normal"&gt;118&lt;/span&gt;
&lt;span class="normal"&gt;119&lt;/span&gt;
&lt;span class="normal"&gt;120&lt;/span&gt;
&lt;span class="normal"&gt;121&lt;/span&gt;
&lt;span class="normal"&gt;122&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1992&lt;/span&gt;-2012&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;FreeBSD&lt;span class="w"&gt; &lt;/span&gt;Project.
Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;c&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1979&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1980&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1983&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1986&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1988&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1989&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1991&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1992&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1993&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1994&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;Regents&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;University&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;California.&lt;span class="w"&gt; &lt;/span&gt;All&lt;span class="w"&gt; &lt;/span&gt;rights&lt;span class="w"&gt; &lt;/span&gt;reserved.
FreeBSD&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;registered&lt;span class="w"&gt; &lt;/span&gt;trademark&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;FreeBSD&lt;span class="w"&gt; &lt;/span&gt;Foundation.
FreeBSD&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.0-RELEASE&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#0: Tue Jan  3 07:15:25 UTC 2012&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;root@obrian.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC&lt;span class="w"&gt; &lt;/span&gt;i386
CPU:&lt;span class="w"&gt; &lt;/span&gt;AMD&lt;span class="w"&gt; &lt;/span&gt;Turion&lt;span class="o"&gt;(&lt;/span&gt;tm&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;II&lt;span class="w"&gt; &lt;/span&gt;Neo&lt;span class="w"&gt; &lt;/span&gt;N40L&lt;span class="w"&gt; &lt;/span&gt;Dual-Core&lt;span class="w"&gt; &lt;/span&gt;Processor&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1497&lt;/span&gt;.55-MHz&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;686&lt;/span&gt;-class&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;AuthenticAMD&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;0x100f63&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Family&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Model&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Stepping&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x178bfbff&amp;lt;FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CLFLUSH,MMX,FXSR,SSE,SSE2,HTT&amp;gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;Features2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x802009&amp;lt;SSE3,MON,CX16,POPCNT&amp;gt;
&lt;span class="w"&gt;  &lt;/span&gt;AMD&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0xee500800&amp;lt;SYSCALL,NX,MMX+,FFXSR,Page1GB,RDTSCP,LM,3DNow!+,3DNow!&amp;gt;
&lt;span class="w"&gt;  &lt;/span&gt;AMD&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Features2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x837ff&amp;lt;LAHF,CMP,SVM,ExtAPIC,CR8,ABM,SSE4A,MAS,Prefetch,OSVW,IBS,SKINIT,WDT,NodeId&amp;gt;
&lt;span class="w"&gt;  &lt;/span&gt;TSC:&lt;span class="w"&gt; &lt;/span&gt;P-state&lt;span class="w"&gt; &lt;/span&gt;invariant
real&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2147483648&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2048&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MB&lt;span class="o"&gt;)&lt;/span&gt;
avail&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2020139008&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1926&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;MB&lt;span class="o"&gt;)&lt;/span&gt;
Event&lt;span class="w"&gt; &lt;/span&gt;timer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;LAPIC&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;400&lt;/span&gt;
ACPI&lt;span class="w"&gt; &lt;/span&gt;APIC&lt;span class="w"&gt; &lt;/span&gt;Table:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;HP&lt;span class="w"&gt;     &lt;/span&gt;ProLiant&amp;gt;
FreeBSD/SMP:&lt;span class="w"&gt; &lt;/span&gt;Multiprocessor&lt;span class="w"&gt; &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;Detected:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;CPUs
FreeBSD/SMP:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;package&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;x&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;core&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;cpu0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;BSP&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;APIC&lt;span class="w"&gt; &lt;/span&gt;ID:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;cpu1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;AP&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;APIC&lt;span class="w"&gt; &lt;/span&gt;ID:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
ioapic0&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.1&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;irqs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;-23&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;motherboard
kbd1&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;kbdmux0
acpi0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;HP&lt;span class="w"&gt; &lt;/span&gt;ProLiant&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;motherboard
acpi0:&lt;span class="w"&gt; &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Button&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;fixed&lt;span class="o"&gt;)&lt;/span&gt;
acpi0:&lt;span class="w"&gt; &lt;/span&gt;reservation&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;fee00000,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;failed
acpi0:&lt;span class="w"&gt; &lt;/span&gt;reservation&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;ffb80000,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;80000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;failed
acpi0:&lt;span class="w"&gt; &lt;/span&gt;reservation&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;fec10000,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;failed
acpi0:&lt;span class="w"&gt; &lt;/span&gt;reservation&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;fed80000,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;failed
acpi0:&lt;span class="w"&gt; &lt;/span&gt;reservation&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;a0000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;failed
acpi0:&lt;span class="w"&gt; &lt;/span&gt;reservation&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100000&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;7bf00000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;failed
Timecounter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ACPI-fast&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3579545&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;900&lt;/span&gt;
acpi_timer0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="m"&gt;32&lt;/span&gt;-bit&lt;span class="w"&gt; &lt;/span&gt;timer&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.579545MHz&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x808-0x80b&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
cpu0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;CPU&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
cpu1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;CPU&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
pcib0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;Host-PCI&lt;span class="w"&gt; &lt;/span&gt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0xcf8-0xcff&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
pci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;PCI&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pcib0
pcib1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;PCI-PCI&lt;span class="w"&gt; &lt;/span&gt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
pci1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;PCI&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pcib1
vgapci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;VGA-compatible&lt;span class="w"&gt; &lt;/span&gt;display&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0xe000-0xe0ff&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xf8000000-0xfbffffff,0xfe8f0000-0xfe8fffff,0xfe700000-0xfe7fffff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci1
pcib2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;PCI-PCI&lt;span class="w"&gt; &lt;/span&gt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
pci2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;PCI&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pcib2
bge0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;HP&lt;span class="w"&gt; &lt;/span&gt;NC107i&lt;span class="w"&gt; &lt;/span&gt;PCIe&lt;span class="w"&gt; &lt;/span&gt;Gigabit&lt;span class="w"&gt; &lt;/span&gt;Server&lt;span class="w"&gt; &lt;/span&gt;Adapter,&lt;span class="w"&gt; &lt;/span&gt;ASIC&lt;span class="w"&gt; &lt;/span&gt;rev.&lt;span class="w"&gt; &lt;/span&gt;0x5784100&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe9f0000-0xfe9fffff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci2
bge0:&lt;span class="w"&gt; &lt;/span&gt;CHIP&lt;span class="w"&gt; &lt;/span&gt;ID&lt;span class="w"&gt; &lt;/span&gt;0x05784100&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ASIC&lt;span class="w"&gt; &lt;/span&gt;REV&lt;span class="w"&gt; &lt;/span&gt;0x5784&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;CHIP&lt;span class="w"&gt; &lt;/span&gt;REV&lt;span class="w"&gt; &lt;/span&gt;0x57841&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PCI-E
miibus0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;MII&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;bge0
brgphy0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;BCM5784&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;/100/1000baseT&lt;span class="w"&gt; &lt;/span&gt;PHY&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;PHY&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;miibus0
brgphy0:&lt;span class="w"&gt;  &lt;/span&gt;10baseT,&lt;span class="w"&gt; &lt;/span&gt;10baseT-FDX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX,&lt;span class="w"&gt; &lt;/span&gt;100baseTX-FDX,&lt;span class="w"&gt; &lt;/span&gt;1000baseT,&lt;span class="w"&gt; &lt;/span&gt;1000baseT-master,&lt;span class="w"&gt; &lt;/span&gt;1000baseT-FDX,&lt;span class="w"&gt; &lt;/span&gt;1000baseT-FDX-master,&lt;span class="w"&gt; &lt;/span&gt;auto,&lt;span class="w"&gt; &lt;/span&gt;auto-flow
bge0:&lt;span class="w"&gt; &lt;/span&gt;Ethernet&lt;span class="w"&gt; &lt;/span&gt;address:&lt;span class="w"&gt; &lt;/span&gt;xx:xx:xx:xx:xx:xx
ahci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&lt;span class="w"&gt; &lt;/span&gt;IXP700&lt;span class="w"&gt; &lt;/span&gt;AHCI&lt;span class="w"&gt; &lt;/span&gt;SATA&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0xd000-0xd007,0xc000-0xc003,0xb000-0xb007,0xa000-0xa003,0x9000-0x900f&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe6ffc00-0xfe6fffff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
ahci0:&lt;span class="w"&gt; &lt;/span&gt;AHCI&lt;span class="w"&gt; &lt;/span&gt;v1.20&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;3Gbps&lt;span class="w"&gt; &lt;/span&gt;ports,&lt;span class="w"&gt; &lt;/span&gt;Port&lt;span class="w"&gt; &lt;/span&gt;Multiplier&lt;span class="w"&gt; &lt;/span&gt;supported
ahcich0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AHCI&lt;span class="w"&gt; &lt;/span&gt;channel&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ahci0
ahcich1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AHCI&lt;span class="w"&gt; &lt;/span&gt;channel&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ahci0
ahcich2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AHCI&lt;span class="w"&gt; &lt;/span&gt;channel&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ahci0
ahcich3:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AHCI&lt;span class="w"&gt; &lt;/span&gt;channel&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ahci0
ahcich4:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AHCI&lt;span class="w"&gt; &lt;/span&gt;channel&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ahci0
ahcich5:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AHCI&lt;span class="w"&gt; &lt;/span&gt;channel&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;channel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ahci0
ohci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;OHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe6fe000-0xfe6fefff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
usbus0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;OHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ohci0
ehci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;EHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe6ff800-0xfe6ff8ff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
usbus1:&lt;span class="w"&gt; &lt;/span&gt;EHCI&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.0
usbus1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;EHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ehci0
ohci1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;OHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe6fd000-0xfe6fdfff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
usbus2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;OHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ohci1
ehci1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;EHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe6ff400-0xfe6ff4ff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
usbus3:&lt;span class="w"&gt; &lt;/span&gt;EHCI&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.0
usbus3:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;EHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ehci1
pci0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;serial&lt;span class="w"&gt; &lt;/span&gt;bus,&lt;span class="w"&gt; &lt;/span&gt;SMBus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;driver&lt;span class="w"&gt; &lt;/span&gt;attached&lt;span class="o"&gt;)&lt;/span&gt;
isab0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;PCI-ISA&lt;span class="w"&gt; &lt;/span&gt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
isa0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ISA&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isab0
pcib3:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;PCI-PCI&lt;span class="w"&gt; &lt;/span&gt;bridge&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;.4&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
pci3:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;PCI&lt;span class="w"&gt; &lt;/span&gt;bus&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pcib3
ohci2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;OHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe6fc000-0xfe6fcfff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
usbus4:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;OHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ohci2
ehci2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;EHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;mem&lt;span class="w"&gt; &lt;/span&gt;0xfe6ff000-0xfe6ff0ff&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;device&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;pci0
usbus5:&lt;span class="w"&gt; &lt;/span&gt;EHCI&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.0
usbus5:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;EHCI&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;generic&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;controller&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;ehci2
acpi_button0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Power&lt;span class="w"&gt; &lt;/span&gt;Button&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
attimer0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AT&lt;span class="w"&gt; &lt;/span&gt;timer&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x40-0x43&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
Timecounter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;i8254&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1193182&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
Event&lt;span class="w"&gt; &lt;/span&gt;timer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;i8254&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1193182&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;
atrtc0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;AT&lt;span class="w"&gt; &lt;/span&gt;realtime&lt;span class="w"&gt; &lt;/span&gt;clock&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x70-0x71&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
Event&lt;span class="w"&gt; &lt;/span&gt;timer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;RTC&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32768&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
hpet0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;High&lt;span class="w"&gt; &lt;/span&gt;Precision&lt;span class="w"&gt; &lt;/span&gt;Event&lt;span class="w"&gt; &lt;/span&gt;Timer&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;iomem&lt;span class="w"&gt; &lt;/span&gt;0xfed00000-0xfed003ff&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;acpi0
Timecounter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HPET&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14318180&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;950&lt;/span&gt;
Event&lt;span class="w"&gt; &lt;/span&gt;timer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HPET&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14318180&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;550&lt;/span&gt;
Event&lt;span class="w"&gt; &lt;/span&gt;timer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HPET1&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14318180&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;450&lt;/span&gt;
pmtimer0&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
sc0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;System&lt;span class="w"&gt; &lt;/span&gt;console&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;flags&lt;span class="w"&gt; &lt;/span&gt;0x100&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
sc0:&lt;span class="w"&gt; &lt;/span&gt;VGA&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="m"&gt;16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;virtual&lt;span class="w"&gt; &lt;/span&gt;consoles,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x300&amp;gt;
vga0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Generic&lt;span class="w"&gt; &lt;/span&gt;ISA&lt;span class="w"&gt; &lt;/span&gt;VGA&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x3c0-0x3df&lt;span class="w"&gt; &lt;/span&gt;iomem&lt;span class="w"&gt; &lt;/span&gt;0xa0000-0xbffff&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
ata0&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x1f0-0x1f7,0x3f6&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
ata1&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;0x170-0x177,0x376&lt;span class="w"&gt; &lt;/span&gt;irq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;isa0
ppc0:&lt;span class="w"&gt; &lt;/span&gt;parallel&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;found.
acpi_throttle0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ACPI&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;Throttling&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;cpu0
hwpstate0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;Cool&lt;span class="sb"&gt;`&lt;/span&gt;n&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;Quiet&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.0&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;cpu0
Timecounters&lt;span class="w"&gt; &lt;/span&gt;tick&lt;span class="w"&gt; &lt;/span&gt;every&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.000&lt;span class="w"&gt; &lt;/span&gt;msec
usbus0:&lt;span class="w"&gt; &lt;/span&gt;12Mbps&lt;span class="w"&gt; &lt;/span&gt;Full&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;v1.0
usbus1:&lt;span class="w"&gt; &lt;/span&gt;480Mbps&lt;span class="w"&gt; &lt;/span&gt;High&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;v2.0
usbus2:&lt;span class="w"&gt; &lt;/span&gt;12Mbps&lt;span class="w"&gt; &lt;/span&gt;Full&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;v1.0
usbus3:&lt;span class="w"&gt; &lt;/span&gt;480Mbps&lt;span class="w"&gt; &lt;/span&gt;High&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;v2.0
usbus4:&lt;span class="w"&gt; &lt;/span&gt;12Mbps&lt;span class="w"&gt; &lt;/span&gt;Full&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;v1.0
usbus5:&lt;span class="w"&gt; &lt;/span&gt;480Mbps&lt;span class="w"&gt; &lt;/span&gt;High&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt; &lt;/span&gt;USB&lt;span class="w"&gt; &lt;/span&gt;v2.0
ugen0.1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;usbus0
uhub0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&lt;span class="w"&gt; &lt;/span&gt;OHCI&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;HUB,&lt;span class="w"&gt; &lt;/span&gt;class&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;/0,&lt;span class="w"&gt; &lt;/span&gt;rev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.00/1.00,&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;usbus0
ugen1.1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;usbus1
uhub1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&lt;span class="w"&gt; &lt;/span&gt;EHCI&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;HUB,&lt;span class="w"&gt; &lt;/span&gt;class&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;/0,&lt;span class="w"&gt; &lt;/span&gt;rev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.00/1.00,&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;usbus1
ugen2.1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;usbus2
uhub2:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&lt;span class="w"&gt; &lt;/span&gt;OHCI&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;HUB,&lt;span class="w"&gt; &lt;/span&gt;class&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;/0,&lt;span class="w"&gt; &lt;/span&gt;rev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.00/1.00,&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;usbus2
ugen3.1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;usbus3
uhub3:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&lt;span class="w"&gt; &lt;/span&gt;EHCI&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;HUB,&lt;span class="w"&gt; &lt;/span&gt;class&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;/0,&lt;span class="w"&gt; &lt;/span&gt;rev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.00/1.00,&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;usbus3
ugen4.1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;usbus4
uhub4:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&lt;span class="w"&gt; &lt;/span&gt;OHCI&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;HUB,&lt;span class="w"&gt; &lt;/span&gt;class&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;/0,&lt;span class="w"&gt; &lt;/span&gt;rev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.00/1.00,&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;usbus4
ugen5.1:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;usbus5
uhub5:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ATI&lt;span class="w"&gt; &lt;/span&gt;EHCI&lt;span class="w"&gt; &lt;/span&gt;root&lt;span class="w"&gt; &lt;/span&gt;HUB,&lt;span class="w"&gt; &lt;/span&gt;class&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;/0,&lt;span class="w"&gt; &lt;/span&gt;rev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.00/1.00,&lt;span class="w"&gt; &lt;/span&gt;addr&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;usbus5
ada0&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;ahcich5&lt;span class="w"&gt; &lt;/span&gt;bus&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;scbus5&lt;span class="w"&gt; &lt;/span&gt;target&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;lun&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
ada0:&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;V4-CT032V4SSD2&lt;span class="w"&gt; &lt;/span&gt;S5FAMM22&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;ATA-8&lt;span class="w"&gt; &lt;/span&gt;SATA&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.x&lt;span class="w"&gt; &lt;/span&gt;device
ada0:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;300&lt;/span&gt;.000MB/s&lt;span class="w"&gt; &lt;/span&gt;transfers&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;SATA&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.x,&lt;span class="w"&gt; &lt;/span&gt;UDMA5,&lt;span class="w"&gt; &lt;/span&gt;PIO&lt;span class="w"&gt; &lt;/span&gt;8192bytes&lt;span class="o"&gt;)&lt;/span&gt;
ada0:&lt;span class="w"&gt; &lt;/span&gt;Command&lt;span class="w"&gt; &lt;/span&gt;Queueing&lt;span class="w"&gt; &lt;/span&gt;enabled
ada0:&lt;span class="w"&gt; &lt;/span&gt;30533MB&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;62533296&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;512&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;byte&lt;span class="w"&gt; &lt;/span&gt;sectors:&lt;span class="w"&gt; &lt;/span&gt;16H&lt;span class="w"&gt; &lt;/span&gt;63S/T&lt;span class="w"&gt; &lt;/span&gt;16383C&lt;span class="o"&gt;)&lt;/span&gt;
ada0:&lt;span class="w"&gt; &lt;/span&gt;Previously&lt;span class="w"&gt; &lt;/span&gt;was&lt;span class="w"&gt; &lt;/span&gt;known&lt;span class="w"&gt; &lt;/span&gt;as&lt;span class="w"&gt; &lt;/span&gt;ad14
SMP:&lt;span class="w"&gt; &lt;/span&gt;AP&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;#1 Launched!&lt;/span&gt;
Timecounter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TSC-low&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;frequency&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11699573&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hz&lt;span class="w"&gt; &lt;/span&gt;quality&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;800&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output from &lt;code&gt;pciconf -lv&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;
&lt;span class="normal"&gt;51&lt;/span&gt;
&lt;span class="normal"&gt;52&lt;/span&gt;
&lt;span class="normal"&gt;53&lt;/span&gt;
&lt;span class="normal"&gt;54&lt;/span&gt;
&lt;span class="normal"&gt;55&lt;/span&gt;
&lt;span class="normal"&gt;56&lt;/span&gt;
&lt;span class="normal"&gt;57&lt;/span&gt;
&lt;span class="normal"&gt;58&lt;/span&gt;
&lt;span class="normal"&gt;59&lt;/span&gt;
&lt;span class="normal"&gt;60&lt;/span&gt;
&lt;span class="normal"&gt;61&lt;/span&gt;
&lt;span class="normal"&gt;62&lt;/span&gt;
&lt;span class="normal"&gt;63&lt;/span&gt;
&lt;span class="normal"&gt;64&lt;/span&gt;
&lt;span class="normal"&gt;65&lt;/span&gt;
&lt;span class="normal"&gt;66&lt;/span&gt;
&lt;span class="normal"&gt;67&lt;/span&gt;
&lt;span class="normal"&gt;68&lt;/span&gt;
&lt;span class="normal"&gt;69&lt;/span&gt;
&lt;span class="normal"&gt;70&lt;/span&gt;
&lt;span class="normal"&gt;71&lt;/span&gt;
&lt;span class="normal"&gt;72&lt;/span&gt;
&lt;span class="normal"&gt;73&lt;/span&gt;
&lt;span class="normal"&gt;74&lt;/span&gt;
&lt;span class="normal"&gt;75&lt;/span&gt;
&lt;span class="normal"&gt;76&lt;/span&gt;
&lt;span class="normal"&gt;77&lt;/span&gt;
&lt;span class="normal"&gt;78&lt;/span&gt;
&lt;span class="normal"&gt;79&lt;/span&gt;
&lt;span class="normal"&gt;80&lt;/span&gt;
&lt;span class="normal"&gt;81&lt;/span&gt;
&lt;span class="normal"&gt;82&lt;/span&gt;
&lt;span class="normal"&gt;83&lt;/span&gt;
&lt;span class="normal"&gt;84&lt;/span&gt;
&lt;span class="normal"&gt;85&lt;/span&gt;
&lt;span class="normal"&gt;86&lt;/span&gt;
&lt;span class="normal"&gt;87&lt;/span&gt;
&lt;span class="normal"&gt;88&lt;/span&gt;
&lt;span class="normal"&gt;89&lt;/span&gt;
&lt;span class="normal"&gt;90&lt;/span&gt;
&lt;span class="normal"&gt;91&lt;/span&gt;
&lt;span class="normal"&gt;92&lt;/span&gt;
&lt;span class="normal"&gt;93&lt;/span&gt;
&lt;span class="normal"&gt;94&lt;/span&gt;
&lt;span class="normal"&gt;95&lt;/span&gt;
&lt;span class="normal"&gt;96&lt;/span&gt;
&lt;span class="normal"&gt;97&lt;/span&gt;
&lt;span class="normal"&gt;98&lt;/span&gt;
&lt;span class="normal"&gt;99&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;hostb0@pci0:0:0:0:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x96011022&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Advanced Micro Devices [AMD]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;RS880 Host Bridge&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;HOST-PCI
pcib1@pci0:0:1:0:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060400&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x9602103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x01
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hewlett-Packard Company&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PCI-PCI
pcib2@pci0:0:6:0:&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060400&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x96061022&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x01
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Advanced Micro Devices [AMD]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;RS780 PCI to PCI bridge (PCIE port 2)&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PCI-PCI
ahci0@pci0:0:17:0:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x010601&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43911002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x40&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mass&lt;span class="w"&gt; &lt;/span&gt;storage
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;SATA
ohci0@pci0:0:18:0:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x0c0310&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43971002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 USB OHCI0 Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;bus
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB
ehci0@pci0:0:18:2:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x0c0320&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43961002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 USB EHCI Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;bus
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB
ohci1@pci0:0:19:0:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x0c0310&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43971002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 USB OHCI0 Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;bus
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB
ehci1@pci0:0:19:2:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x0c0320&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43961002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 USB EHCI Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;bus
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB
none0@pci0:0:20:0:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x0c0500&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00000000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43851002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x42&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SBx00 SMBus Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;bus
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;SMBus
isab0@pci0:0:20:3:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060100&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x439d1002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x40&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 LPC host controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PCI-ISA
pcib3@pci0:0:20:4:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060401&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00000000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43841002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x40&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x01
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SBx00 PCI to PCI Bridge&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PCI-PCI
ohci2@pci0:0:22:0:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x0c0310&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43971002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 USB OHCI0 Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;bus
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB
ehci2@pci0:0:22:2:&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x0c0320&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x43961002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SB7x0/SB8x0/SB9x0 USB EHCI Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;serial&lt;span class="w"&gt; &lt;/span&gt;bus
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;USB
hostb1@pci0:0:24:0:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00000000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x12001022&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Advanced Micro Devices [AMD]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Family 10h Processor HyperTransport Configuration&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;HOST-PCI
hostb2@pci0:0:24:1:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00000000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x12011022&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Advanced Micro Devices [AMD]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Family 10h Processor Address Map&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;HOST-PCI
hostb3@pci0:0:24:2:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00000000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x12021022&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Advanced Micro Devices [AMD]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Family 10h Processor DRAM Controller&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;HOST-PCI
hostb4@pci0:0:24:3:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00000000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x12031022&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Advanced Micro Devices [AMD]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Family 10h Processor Miscellaneous Control&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;HOST-PCI
hostb5@pci0:0:24:4:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x060000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00000000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x12041022&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Advanced Micro Devices [AMD]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Family 10h Processor Link Control&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bridge
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;HOST-PCI
vgapci0@pci0:1:5:0:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x030000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x1609103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x97121002&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ATI Technologies Inc&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;M880G [Mobility Radeon HD 4200]&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;display
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;VGA
bge0@pci0:2:0:0:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x020000&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x705d103c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;chip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x165b14e4&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;rev&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;hdr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;vendor&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Broadcom Corporation&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;NetXtreme BCM5723 Gigabit Ethernet PCIe&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;network
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;subclass&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ethernet
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hope this helps&amp;nbsp;someone,&lt;/p&gt;
&lt;p&gt;be seeing&amp;nbsp;you.&lt;/p&gt;</content><category term="misc"></category><category term="Hardware"></category></entry><entry><title>Graphing Electricity Usage with Current Cost and Munin</title><link href="https://www.executionunit.com/blog/2013/02/26/graphing-electricity-usage-with-current-cost-and-munin/" rel="alternate"></link><published>2013-02-26T00:00:00+00:00</published><updated>2013-02-26T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2013-02-26:/blog/2013/02/26/graphing-electricity-usage-with-current-cost-and-munin/</id><summary type="html">&lt;p&gt;Many years ago I bought a &lt;a href="http://www.currentcost.com"&gt;Current Cost&lt;/a&gt; meter. Infact it was so long ago now that they have called my version &lt;a href="http://www.currentcost.com/product-theclassic.html"&gt;The Classic&lt;/a&gt;. I wanted to see how much electrical energy all my servers, home computers and gadgets were&amp;nbsp;using.&lt;/p&gt;
&lt;p&gt;The Current Cost package contains two main parts, a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Many years ago I bought a &lt;a href="http://www.currentcost.com"&gt;Current Cost&lt;/a&gt; meter. Infact it was so long ago now that they have called my version &lt;a href="http://www.currentcost.com/product-theclassic.html"&gt;The Classic&lt;/a&gt;. I wanted to see how much electrical energy all my servers, home computers and gadgets were&amp;nbsp;using.&lt;/p&gt;
&lt;p&gt;The Current Cost package contains two main parts, a &lt;a href="http://www.currentcost.com/product-transmitter.html" title="Current Cost Transmitter"&gt;transmitter&lt;/a&gt; and the display.
The transmitter is hooked around your house/offices main power in &lt;em&gt;&lt;span class="caps"&gt;BEFORE&lt;/span&gt;&lt;/em&gt; the consumer meter. The consumer meter is the big box that is usually under your stairs. The meter constantly sends power usage to the display which shows the watts currently being used, watts over time and, with a little bit of input from the user how much your energy usage is going to cost you over&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;The reason I went with a Current Cost meter is becuase it has a serial connection on the bottom of the display unit. One annoyance is that it uses a &lt;span class="caps"&gt;RJ45&lt;/span&gt; connector so you either need to stump up for a &lt;a href="http://www.currentcost.com/product-datacable.html" title="CurrentCost Data cable"&gt;custom cable&lt;/a&gt; from Current Cost or make your own (google it, there are a number of sites with pinouts and&amp;nbsp;instructions).&lt;/p&gt;
&lt;p&gt;I already monitor pretty much every aspect of my servers using &lt;a href="http://munin-monitoring.org" title="Munin homepage"&gt;Munin&lt;/a&gt; so it seemed like a natural solution for graphing the Current Cost data over&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;Sending data to Munin is fairly easy and it has a simple plugin interface. There are some complexities to it as Munin uses RRDTool to render it&amp;#8217;s graphs and the options for &lt;a href="http://oss.oetiker.ch/rrdtool/" title="RRDTool homepage"&gt;RRDTool&lt;/a&gt; are complex and&amp;nbsp;confusing.&lt;/p&gt;
&lt;p&gt;The results are graphs like&amp;nbsp;this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Watts over the Day" src="https://www.executionunit.com/static/media/uploads/blog/currentcost_watts-day.jpg" title="Watts over the day"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;showing watts used over&amp;nbsp;time&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Temperature over the Day" src="https://www.executionunit.com/static/media/uploads/blog/currentcost_temperature-day.jpg" title="Temperature over the day"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;showing temparature at or near the Current Cost&amp;nbsp;display&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;OK&lt;/span&gt; they are not very pretty but that&amp;#8217;s not the point. I can see that right now as I am typing this my house is consuming about 440 watts. At this rate, per hour I am using &lt;code&gt;440Wh (watt hours)&lt;/code&gt; or &lt;code&gt;0.44 kWh&lt;/code&gt; which is (on average) &lt;code&gt;0.44 * £0.15 ~ £0.06 per hour&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now as you can see, through the day we get massive spikes, they are usually boiling water for coffee or&amp;nbsp;cooking.&lt;/p&gt;
&lt;p&gt;The most interesting thing for me is that having the data before me modifies my behaviour. For example I finally unplugged my Wii today, 4 months after getting my WiiU. It&amp;#8217;s been there quietly sucking up a few kWh per day. It hasn&amp;#8217;t cost me a lot but as they always&amp;nbsp;say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If we all did it we&amp;#8217;d save the&amp;nbsp;planet!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;That is a direct quote from Al&amp;nbsp;Gore!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So here is the python code that you can use as a munin&amp;nbsp;plugin&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;  1&lt;/span&gt;
&lt;span class="normal"&gt;  2&lt;/span&gt;
&lt;span class="normal"&gt;  3&lt;/span&gt;
&lt;span class="normal"&gt;  4&lt;/span&gt;
&lt;span class="normal"&gt;  5&lt;/span&gt;
&lt;span class="normal"&gt;  6&lt;/span&gt;
&lt;span class="normal"&gt;  7&lt;/span&gt;
&lt;span class="normal"&gt;  8&lt;/span&gt;
&lt;span class="normal"&gt;  9&lt;/span&gt;
&lt;span class="normal"&gt; 10&lt;/span&gt;
&lt;span class="normal"&gt; 11&lt;/span&gt;
&lt;span class="normal"&gt; 12&lt;/span&gt;
&lt;span class="normal"&gt; 13&lt;/span&gt;
&lt;span class="normal"&gt; 14&lt;/span&gt;
&lt;span class="normal"&gt; 15&lt;/span&gt;
&lt;span class="normal"&gt; 16&lt;/span&gt;
&lt;span class="normal"&gt; 17&lt;/span&gt;
&lt;span class="normal"&gt; 18&lt;/span&gt;
&lt;span class="normal"&gt; 19&lt;/span&gt;
&lt;span class="normal"&gt; 20&lt;/span&gt;
&lt;span class="normal"&gt; 21&lt;/span&gt;
&lt;span class="normal"&gt; 22&lt;/span&gt;
&lt;span class="normal"&gt; 23&lt;/span&gt;
&lt;span class="normal"&gt; 24&lt;/span&gt;
&lt;span class="normal"&gt; 25&lt;/span&gt;
&lt;span class="normal"&gt; 26&lt;/span&gt;
&lt;span class="normal"&gt; 27&lt;/span&gt;
&lt;span class="normal"&gt; 28&lt;/span&gt;
&lt;span class="normal"&gt; 29&lt;/span&gt;
&lt;span class="normal"&gt; 30&lt;/span&gt;
&lt;span class="normal"&gt; 31&lt;/span&gt;
&lt;span class="normal"&gt; 32&lt;/span&gt;
&lt;span class="normal"&gt; 33&lt;/span&gt;
&lt;span class="normal"&gt; 34&lt;/span&gt;
&lt;span class="normal"&gt; 35&lt;/span&gt;
&lt;span class="normal"&gt; 36&lt;/span&gt;
&lt;span class="normal"&gt; 37&lt;/span&gt;
&lt;span class="normal"&gt; 38&lt;/span&gt;
&lt;span class="normal"&gt; 39&lt;/span&gt;
&lt;span class="normal"&gt; 40&lt;/span&gt;
&lt;span class="normal"&gt; 41&lt;/span&gt;
&lt;span class="normal"&gt; 42&lt;/span&gt;
&lt;span class="normal"&gt; 43&lt;/span&gt;
&lt;span class="normal"&gt; 44&lt;/span&gt;
&lt;span class="normal"&gt; 45&lt;/span&gt;
&lt;span class="normal"&gt; 46&lt;/span&gt;
&lt;span class="normal"&gt; 47&lt;/span&gt;
&lt;span class="normal"&gt; 48&lt;/span&gt;
&lt;span class="normal"&gt; 49&lt;/span&gt;
&lt;span class="normal"&gt; 50&lt;/span&gt;
&lt;span class="normal"&gt; 51&lt;/span&gt;
&lt;span class="normal"&gt; 52&lt;/span&gt;
&lt;span class="normal"&gt; 53&lt;/span&gt;
&lt;span class="normal"&gt; 54&lt;/span&gt;
&lt;span class="normal"&gt; 55&lt;/span&gt;
&lt;span class="normal"&gt; 56&lt;/span&gt;
&lt;span class="normal"&gt; 57&lt;/span&gt;
&lt;span class="normal"&gt; 58&lt;/span&gt;
&lt;span class="normal"&gt; 59&lt;/span&gt;
&lt;span class="normal"&gt; 60&lt;/span&gt;
&lt;span class="normal"&gt; 61&lt;/span&gt;
&lt;span class="normal"&gt; 62&lt;/span&gt;
&lt;span class="normal"&gt; 63&lt;/span&gt;
&lt;span class="normal"&gt; 64&lt;/span&gt;
&lt;span class="normal"&gt; 65&lt;/span&gt;
&lt;span class="normal"&gt; 66&lt;/span&gt;
&lt;span class="normal"&gt; 67&lt;/span&gt;
&lt;span class="normal"&gt; 68&lt;/span&gt;
&lt;span class="normal"&gt; 69&lt;/span&gt;
&lt;span class="normal"&gt; 70&lt;/span&gt;
&lt;span class="normal"&gt; 71&lt;/span&gt;
&lt;span class="normal"&gt; 72&lt;/span&gt;
&lt;span class="normal"&gt; 73&lt;/span&gt;
&lt;span class="normal"&gt; 74&lt;/span&gt;
&lt;span class="normal"&gt; 75&lt;/span&gt;
&lt;span class="normal"&gt; 76&lt;/span&gt;
&lt;span class="normal"&gt; 77&lt;/span&gt;
&lt;span class="normal"&gt; 78&lt;/span&gt;
&lt;span class="normal"&gt; 79&lt;/span&gt;
&lt;span class="normal"&gt; 80&lt;/span&gt;
&lt;span class="normal"&gt; 81&lt;/span&gt;
&lt;span class="normal"&gt; 82&lt;/span&gt;
&lt;span class="normal"&gt; 83&lt;/span&gt;
&lt;span class="normal"&gt; 84&lt;/span&gt;
&lt;span class="normal"&gt; 85&lt;/span&gt;
&lt;span class="normal"&gt; 86&lt;/span&gt;
&lt;span class="normal"&gt; 87&lt;/span&gt;
&lt;span class="normal"&gt; 88&lt;/span&gt;
&lt;span class="normal"&gt; 89&lt;/span&gt;
&lt;span class="normal"&gt; 90&lt;/span&gt;
&lt;span class="normal"&gt; 91&lt;/span&gt;
&lt;span class="normal"&gt; 92&lt;/span&gt;
&lt;span class="normal"&gt; 93&lt;/span&gt;
&lt;span class="normal"&gt; 94&lt;/span&gt;
&lt;span class="normal"&gt; 95&lt;/span&gt;
&lt;span class="normal"&gt; 96&lt;/span&gt;
&lt;span class="normal"&gt; 97&lt;/span&gt;
&lt;span class="normal"&gt; 98&lt;/span&gt;
&lt;span class="normal"&gt; 99&lt;/span&gt;
&lt;span class="normal"&gt;100&lt;/span&gt;
&lt;span class="normal"&gt;101&lt;/span&gt;
&lt;span class="normal"&gt;102&lt;/span&gt;
&lt;span class="normal"&gt;103&lt;/span&gt;
&lt;span class="normal"&gt;104&lt;/span&gt;
&lt;span class="normal"&gt;105&lt;/span&gt;
&lt;span class="normal"&gt;106&lt;/span&gt;
&lt;span class="normal"&gt;107&lt;/span&gt;
&lt;span class="normal"&gt;108&lt;/span&gt;
&lt;span class="normal"&gt;109&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="c1"&gt;# Script to extract data from a CurrentCost meter over the serial line&lt;/span&gt;
&lt;span class="c1"&gt;# tested on FreeBSD 9.0 2013/1/22&lt;/span&gt;
&lt;span class="c1"&gt;# dazza&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;xml.etree.ElementTree&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;et&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;class to encapsulate the inforkation from a blob of data from the&lt;/span&gt;
&lt;span class="sd"&gt;    currentcost box&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;elemtree&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elemtree&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findtext&lt;/span&gt;

        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dsb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;date/dsb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;date/hr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                             &lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;date/min&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                             &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;date/sec&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;src/name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;src/id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;src/type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source_ver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;src/sver&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tmpr&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channelid&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ch&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt;/watts&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;channelid&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;DSB: &lt;/span&gt;&lt;span class="si"&gt;%(dsb)s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;DATE: &lt;/span&gt;&lt;span class="si"&gt;%(date)s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;SRC: &lt;/span&gt;&lt;span class="si"&gt;%(src)s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;SRCID: &lt;/span&gt;&lt;span class="si"&gt;%(src_id)s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;SRC_TYPE: &lt;/span&gt;&lt;span class="si"&gt;%(src_type)s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;SOURCE_VER: &lt;/span&gt;&lt;span class="si"&gt;%(source_ver)s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;TEMP: &lt;/span&gt;&lt;span class="si"&gt;%(temp)s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;CH: &lt;/span&gt;&lt;span class="si"&gt;%(watts)s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_readvalues&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;read a blob of data from the serial connection to the CurrentCost&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dev/cuaU0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;msgstr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;msg&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;msgstr&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;/msg&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;msgstr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msgstr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msgstr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;msg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;msgstr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;/msg&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;elemtree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;XML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elemtree&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
                &lt;span class="n"&gt;msgstr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msgstr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;msgstr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;/msg&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Exception: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;msgstr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
                &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_config_watts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;set the configuration for the watts graph&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_title Energy Usage (watts)&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_vlabel Watts&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts_1.label Watts Ch. 1&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts_2.label Watts Ch. 2&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts_3.label Watts Ch. 3&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_args -l 0&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_scale no&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_category Home&amp;quot;&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_config_temp&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;set the config for the temperature graph&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_title Temperature (C)&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_vlabel C&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;temp.label Temp&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_args -l 0&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_scale no&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;graph_category Home&amp;quot;&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_watts&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;emit the values fo the watts graph&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_readvalues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts_1.value&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts_2.value&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts_3.value&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;watts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_temp&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;emit the values for the temperature graph&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_readvalues&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;temp.value&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;

&lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;graphtype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graphtype&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_config_watts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;graphtype&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;temperature&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_config_temp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unknown graph type &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;graphtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graphtype&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;watts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_watts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;graphtype&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;temperature&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;_temp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unknown graph type &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;graphtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is a lot going on here so I&amp;#8217;ll summerise the&amp;nbsp;code:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Munin plugins are usually symbolic links to scripts. This script gathers either the watts being used or the room temperature &lt;em&gt;depending on the name of the symbolic link&lt;/em&gt;. So if the link is called currentcost_watts it will return information about watts, if it&amp;#8217;s currentcost_temperature it will return temperature information. This is normal Munin pratice. &lt;em&gt;(see line&amp;nbsp;88)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Munin passes in the argument &amp;#8220;config&amp;#8221; if it wants the plugin to output the RRDGraph config for the data. &lt;em&gt;(see line&amp;nbsp;87)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;_readvalues()&lt;/code&gt; function is hardcoded to read from FreeBSD&amp;#8217;s serial device &lt;code&gt;/dev/cuaU0&lt;/code&gt; your Current Cost meter might appear somewhere&amp;nbsp;else.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;_readvalues()&lt;/code&gt; function returns a DataBlock class. Reading from serial means you get partial data at times so the code iterates over the serial stream until it&amp;#8217;s get all the data needed for &lt;span class="caps"&gt;ONE&lt;/span&gt; DataBlock. Because the munin script is being called once every 5 minutes it doesn&amp;#8217;t matter too&amp;nbsp;much.&lt;/li&gt;
&lt;li&gt;Where there is a lot of power being used I seem to get values appearing on Channel 2. The Current Cost meter I have can read from three meters. I only have one meter so I don&amp;#8217;t know how this is happening. I assume it&amp;#8217;s a bug in the Current Cost meter but it could be in my&amp;nbsp;code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hope this helps someone, good luck getting your energy bills down. I wish there was a similar bit of hardware to measure natural gas&amp;nbsp;usage.&lt;/p&gt;
&lt;p&gt;be seeing&amp;nbsp;you.&lt;/p&gt;</content><category term="misc"></category><category term="Python"></category><category term="FreeBSD"></category></entry><entry><title>Using Python and Tkinter to capture script output</title><link href="https://www.executionunit.com/blog/2012/10/26/using-python-and-tkinter-to-capture-script-output/" rel="alternate"></link><published>2012-10-26T00:00:00+01:00</published><updated>2012-10-26T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2012-10-26:/blog/2012/10/26/using-python-and-tkinter-to-capture-script-output/</id><summary type="html">&lt;p&gt;In order to build the assets for my games I have a series of python scripts that know how to take files TexturePacker, Tiled, and Blender and build them for use within the engine. My main platform is &lt;span class="caps"&gt;OS&lt;/span&gt; X and it has good terminal support and more importantly I …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In order to build the assets for my games I have a series of python scripts that know how to take files TexturePacker, Tiled, and Blender and build them for use within the engine. My main platform is &lt;span class="caps"&gt;OS&lt;/span&gt; X and it has good terminal support and more importantly I am comfortable working with the terminal. The  artist I work with is not so comfortable and he works on Windows where cmd.exe is painfully outdated and basically&amp;nbsp;useless.&lt;/p&gt;
&lt;p&gt;To counter this I wrote a small Python Tkinter script do display a window, text area, some checkboxes and a build button to make it a bit easier for him to work. Crucially it makes it easier to notice build errors and send me bug&amp;nbsp;reports.&lt;/p&gt;
&lt;p&gt;There is some tricky code in there to spawn a process and read it&amp;#8217;s stdout and stderr in&amp;nbsp;python.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmdlist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STDOUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;universal_newlines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;#this triggers an update of the text area, otherwise it doesn&amp;#39;t update&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_idletasks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The key here is to spawn the process, redirect both it&amp;#8217;s stdout to the pipe between this process and the child process. set it&amp;#8217;s stderr to be the same as it&amp;#8217;s stdout (so errors appear in the pipe) and then repeatedly read the stdout pipe one line at a time refreshing the textarea when a new line is&amp;nbsp;added.&lt;/p&gt;
&lt;p&gt;While this is going on the app is unfortunately unresponsive to the user (as Tk.mainloop() isn&amp;#8217;t being called) but it&amp;#8217;s still better than cmd.exe especially since the text widget has colored text and an infinite (as in &lt;span class="caps"&gt;65KB&lt;/span&gt;)&amp;nbsp;buffer.&lt;/p&gt;
&lt;p&gt;Colorizing the text turned out to be incredibly easy with Tkinter. When adding a line to a text widget you pass tags to the widget. These tags represent traints that should be applied to the&amp;nbsp;text.&lt;/p&gt;
&lt;p&gt;Before using tags they need to be&amp;nbsp;setup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;errorstring&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foreground&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#CC0000&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;infostring&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foreground&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#008800&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now&amp;nbsp;calling &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textarea&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INSERT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ERROR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;errorstring&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;inserts text with the errorstring tag resulting in red text appearing. Note that the tags parameter needs to be a tuple (thus the trailing comma after the tag name) and specifically &lt;span class="caps"&gt;NOT&lt;/span&gt; a list (which is a little&amp;nbsp;annoying).&lt;/p&gt;
&lt;p&gt;The code is available as a &lt;a href="https://gist.github.com/executionunit/5a3464c710276157f82d2507db905d30"&gt;github gist here&lt;/a&gt;:  It incudes a sample script that randomly prints messages, pauses and then returns after printing n&amp;nbsp;messages.&lt;/p&gt;
&lt;p&gt;Here are some screenshots so you can see what it is. They are all basically the same but showing it running on FreeBSD, &lt;span class="caps"&gt;OS&lt;/span&gt; X,&amp;nbsp;Windows.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Running on FreeBSD" src="https://www.executionunit.com/static/media/uploads/blog/tkbuilder-freebsd.jpg"&gt; 
&lt;img alt="Running on OSX" src="https://www.executionunit.com/static/media/uploads/blog/tkbuilder-osx.jpg"&gt; 
&lt;img alt="Running on Windows XP" src="https://www.executionunit.com/static/media/uploads/blog/tkbuilder-win32.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Hope this helps someone out&amp;nbsp;there.&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="Python"></category></entry><entry><title>Generating Anagrams in Lua</title><link href="https://www.executionunit.com/blog/2012/10/22/generating-anagrams-in-lua/" rel="alternate"></link><published>2012-10-22T00:00:00+01:00</published><updated>2012-10-22T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2012-10-22:/blog/2012/10/22/generating-anagrams-in-lua/</id><summary type="html">&lt;p&gt;I&amp;#8217;m working on a game where I need to generate anagrams of words. My new game engine, which is Max Astro&amp;#8217;s engine but with a few tweeks, integrates Lua and all the game logic is in&amp;nbsp;Lua.&lt;/p&gt;
&lt;p&gt;So given a string like &amp;#8220;chicken&amp;#8221; I want &amp;#8220;kcehcine&amp;#8221; or some …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;m working on a game where I need to generate anagrams of words. My new game engine, which is Max Astro&amp;#8217;s engine but with a few tweeks, integrates Lua and all the game logic is in&amp;nbsp;Lua.&lt;/p&gt;
&lt;p&gt;So given a string like &amp;#8220;chicken&amp;#8221; I want &amp;#8220;kcehcine&amp;#8221; or some other random reorganisation of the letters in&amp;nbsp;chicken.&lt;/p&gt;
&lt;p&gt;Firstly, accessing the individual letters in a Lua string is not that easy, there is no subscript access so I needed to turn the string in to a&amp;nbsp;table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;chicken&amp;quot;&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;letters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="kr"&gt;for&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="kr"&gt;in&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gmatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;table.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Now the table letters has all the letters in the word chicken in order. Now I shuffle the table using my table_shuffle function&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kr"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;table_shuffle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
    &lt;span class="kr"&gt;while&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="kr"&gt;do&lt;/span&gt;
        &lt;span class="c1"&gt;-- n is now the last pertinent index&lt;/span&gt;
        &lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;math.random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;-- Quick swap&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="kr"&gt;end&lt;/span&gt;
    &lt;span class="kr"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can turn the table back in to a string using&amp;nbsp;table.concat.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not sure how efficient this is but it suits my needs, I don&amp;#8217;t call it&amp;nbsp;often.&lt;/p&gt;
&lt;p&gt;The table shuffle function came from here which is an implementation of the Fischer-Yates shuffle&amp;nbsp;algorithm.&lt;/p&gt;</content><category term="misc"></category><category term="Lua"></category></entry><entry><title>Starter Blender Exporter</title><link href="https://www.executionunit.com/blog/2012/07/26/starter-blender-exporter/" rel="alternate"></link><published>2012-07-26T00:00:00+01:00</published><updated>2012-07-26T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2012-07-26:/blog/2012/07/26/starter-blender-exporter/</id><summary type="html">&lt;p&gt;I&amp;#8217;ve settled on using Blender 2.6  both as a level editor and modeller for my next game (code name &lt;span class="caps"&gt;BBM&lt;/span&gt;). &lt;span class="caps"&gt;BBM&lt;/span&gt; is a 2D game but modelling the characters and rendering the sprites will save a lot of time. Blender isn&amp;#8217;t the best level editor but it …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve settled on using Blender 2.6  both as a level editor and modeller for my next game (code name &lt;span class="caps"&gt;BBM&lt;/span&gt;). &lt;span class="caps"&gt;BBM&lt;/span&gt; is a 2D game but modelling the characters and rendering the sprites will save a lot of time. Blender isn&amp;#8217;t the best level editor but it&amp;#8217;s pretty close and suits my&amp;nbsp;needs.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Test Level in Blender" src="https://www.executionunit.com/static/media/uploads/blog/blender.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The ability to add arbitrary properties to an object in Blender 2.6 makes Blender a &amp;#8220;good enough&amp;#8221; fit for me. Certainly it&amp;#8217;s flexible enough that it&amp;#8217;s usable and will save a lot of time over writing my own stand alone or in game&amp;nbsp;editor.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Editting properties in blender" src="https://www.executionunit.com/static/media/uploads/blog/customprops.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I had written an export plugin for Blender &amp;lt; 2.6 (many years ago) but the whole python interface has changed so I needed to write a new one. I decided to just export the scene to an &lt;span class="caps"&gt;XML&lt;/span&gt; file which I can post process in to a binary file for loading in to the engine. While this adds a step between the editor and the game it does make the process of writing the exporter and understanding the data a lot more simple. Blender doesn&amp;#8217;t offer the perfect environment for writing python plugins so keeping them simple is a good&amp;nbsp;idea.&lt;/p&gt;
&lt;p&gt;The exporter is pretty simple. I&amp;#8217;m releasing the code under a &lt;span class="caps"&gt;BSD&lt;/span&gt; license. It comes in two parts, export26.py which exports an xml file of the scene and load.py which loads the &lt;span class="caps"&gt;XML&lt;/span&gt; file creating a dictionary of the &amp;#8216;types&amp;#8217; that the exporter&amp;nbsp;exports.&lt;/p&gt;
&lt;p&gt;The loader and exporter are a great starting point to a custom exporter of your own. They are pretty generic at the moment and pretty&amp;nbsp;untested!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.executionunit.com/static/media/uploads/blog/export26.py"&gt;export26.py&lt;/a&gt;
&lt;a href="https://www.executionunit.com/static/media/uploads/blog/load.py"&gt;load.py&lt;/a&gt;&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="Python"></category></entry><entry><title>Logical Bit Operators in Lua When Using Floats</title><link href="https://www.executionunit.com/blog/2012/02/27/logical-bit-operators-in-lua-when-using-floats/" rel="alternate"></link><published>2012-02-27T00:00:00+00:00</published><updated>2012-02-27T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2012-02-27:/blog/2012/02/27/logical-bit-operators-in-lua-when-using-floats/</id><summary type="html">&lt;p&gt;I&amp;#8217;m making some changes to the codebase that drives Max Astro before making my next game. The biggest change is that the engine is going to be controlled by Lua. Lua will run the main logic loop and lua will be the configuration&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;One of the oddities of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;m making some changes to the codebase that drives Max Astro before making my next game. The biggest change is that the engine is going to be controlled by Lua. Lua will run the main logic loop and lua will be the configuration&amp;nbsp;language.&lt;/p&gt;
&lt;p&gt;One of the oddities of Lua, at least from a game makers perspective, is that there are no bit logical operators (&lt;span class="caps"&gt;AND&lt;/span&gt;, &lt;span class="caps"&gt;OR&lt;/span&gt;, &lt;span class="caps"&gt;XOR&lt;/span&gt;). The reason for this is that Lua doesn&amp;#8217;t have an internal representation of an Integer. Lua, by default uses doubles for all numbers. There are of course a number of add on libraries to get around&amp;nbsp;this.&lt;/p&gt;
&lt;p&gt;In luaconf.h there is an option to define LUA_NUMBER as a float and I imagine most game makes do this at least on mobile platforms&amp;#8230; and this breaks most bitop libraries for Lua. I say most because it broke the few I tried before just modifying one and moving&amp;nbsp;on.&lt;/p&gt;
&lt;h2 id="making-it-work"&gt;Making it&amp;nbsp;Work&lt;/h2&gt;
&lt;p&gt;My library of choice is BitLib which works with Lua 5.0/5.1. Like all the libraries it&amp;#8217;s small and easy to embed in your engine&amp;nbsp;code. &lt;/p&gt;
&lt;p&gt;Download the source code unpack it and copy bit_limits.h and lbitlib.c to your&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;Open up bit_limits.h and change it to&amp;nbsp;this&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#if defined(LUA_NUMBER_FLOAT)&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_BITS 24&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_MAX  0x7FFFFF&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_MIN  (-0x800000L)&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_UMAX 0xffffff&lt;/span&gt;
&lt;span class="cp"&gt;#elif defined(LUA_NUMBER_DOUBLE)&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_BITS 53&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_MAX  0xfffffffffffffL&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_MIN  (-0x10000000000000L)&lt;/span&gt;
&lt;span class="cp"&gt;#   define BITLIB_FLOAT_UMAX 0x1fffffffffffffUL&lt;/span&gt;
&lt;span class="cp"&gt;#else&lt;/span&gt;
&lt;span class="cp"&gt;#   error(&amp;quot;Need to define float or double for numbers&amp;quot;)&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you understand how floats are represented then all I&amp;#8217;ve done is twiddle some bits in a calculator to work out the limits of the significand (mantissa to old people like&amp;nbsp;me).&lt;/p&gt;
&lt;h2 id="lua-coders-know-your-limits"&gt;Lua Coders Know Your&amp;nbsp;Limits&lt;/h2&gt;
&lt;p&gt;The downside of using floats in this case is that for each number you have, you only have 24 bits to toggle on and off. This is the number of bits in the significand&amp;nbsp;(mantissa).&lt;/p&gt;
&lt;p&gt;Now you can&amp;nbsp;do&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;COLLISION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;WALL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;PLAYER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;CRATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;--annoyingly we can&amp;#39;t test with truth values here&lt;/span&gt;
&lt;span class="kd"&gt;local&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COLLISION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COLLISION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CRATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;COLLISION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CRATE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;~=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;band&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PLAYER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Much thanks has to go out to Reuben Thomas for releasing this library under a &lt;span class="caps"&gt;BSD&lt;/span&gt; license allowing me to embed this code without having to read a tome of&amp;nbsp;legalese.&lt;/p&gt;
&lt;p&gt;Hope this helps someone out there twiddle their&amp;nbsp;bits.&lt;/p&gt;
&lt;p&gt;be seeing&amp;nbsp;you&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;</content><category term="gamedev"></category><category term="Lua"></category></entry><entry><title>iPhone App Version Information In XCode</title><link href="https://www.executionunit.com/blog/2011/01/17/iphone-app-version-information-in-xcode/" rel="alternate"></link><published>2011-01-17T00:00:00+00:00</published><updated>2010-09-05T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2011-01-17:/blog/2011/01/17/iphone-app-version-information-in-xcode/</id><summary type="html">&lt;p&gt;When you create an iOS Application in XCode by default the version of the application is stored in-Info.plist. It would be really handy to get this in to code for compile time checks and&amp;nbsp;#defines.&lt;/p&gt;
&lt;p&gt;PList files are actually &lt;span class="caps"&gt;XML&lt;/span&gt; files which makes them easy to read in a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;When you create an iOS Application in XCode by default the version of the application is stored in-Info.plist. It would be really handy to get this in to code for compile time checks and&amp;nbsp;#defines.&lt;/p&gt;
&lt;p&gt;PList files are actually &lt;span class="caps"&gt;XML&lt;/span&gt; files which makes them easy to read in a shell script but complex to manipulate in bash. Luckily there is a utility called PListBuddy installed in /usr/libexec (not the usual path for command line utilities in &lt;span class="caps"&gt;OS&lt;/span&gt; X) which can manipulate PList files in various ways. For&amp;nbsp;example: &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/usr/libexec/PlistBuddy&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Print :CFBundleVersion&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Stranded/Stranded-Info.plist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;outputs&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="m"&gt;0&lt;/span&gt;.28
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;showing that the current development version of stranded is 0.28 (long way to go to get to&amp;nbsp;1.0)&lt;/p&gt;
&lt;p&gt;I wanted to output a header file called version.h from my various targets based upon the value of CFBundleVersion in Stranded-Info.plist. To accomplish this I added a small build step to each target which ran the following&amp;nbsp;script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;PLISTBUDDY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/usr/libexec/PlistBuddy&amp;#39;&lt;/span&gt;
&lt;span class="nv"&gt;PFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Stranded-Info.plist&amp;#39;&lt;/span&gt;
&lt;span class="nv"&gt;VERSIONFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Classes/version.h&amp;#39;&lt;/span&gt;
&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$PLISTBUDDY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Print :CFBundleVersion&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PFILE&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#ifndef VERSION_H&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VERSIONFILE&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#define VERSION_H&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VERSIONFILE&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#define MAJOR_VERSION &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VERSIONFILE&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#define MINOR_VERSION &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[1]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VERSIONFILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;#endif&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VERSIONFILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$VERSIONFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This should be placed as a &amp;#8216;New Run Script Build Phase&amp;#8217; with your info.plist file as input and your output file as the version.h file you want to&amp;nbsp;generate.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Run Script Phase" src="https://www.executionunit.com/static/media/uploads/blog/xcode-script-phase.jpg"&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s important that this build script is the first script to run so that version.h is updated &lt;span class="caps"&gt;BEFORE&lt;/span&gt; the application code is&amp;nbsp;built.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Target View" src="https://www.executionunit.com/static/media/uploads/blog/xcode-target-order.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve renamed the build script to &amp;#8220;Update Version&amp;#8221; so I remember what it&amp;nbsp;is.&lt;/p&gt;
&lt;p&gt;Now in code you can&amp;nbsp;write:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;quot;version.h&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;HUD&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;SetLabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;versionlabel&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StrFormat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;v%d.%d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MAJOR_VERSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MINOR_VERSION&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;</content><category term="misc"></category><category term="C++"></category></entry><entry><title>Metalify - A Spotify Clone</title><link href="https://www.executionunit.com/blog/2010/09/05/metalify-spotify-clone/" rel="alternate"></link><published>2010-09-05T00:00:00+01:00</published><updated>2010-09-05T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2010-09-05:/blog/2010/09/05/metalify-spotify-clone/</id><summary type="html">&lt;p&gt;For a few months I&amp;#8217;ve wanted to make a clone of Spotify but I haven&amp;#8217;t been able to justify the time. Last week I decided to take a week off and give it a go. The justification for this is that I wanted to deploy a Django website …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For a few months I&amp;#8217;ve wanted to make a clone of Spotify but I haven&amp;#8217;t been able to justify the time. Last week I decided to take a week off and give it a go. The justification for this is that I wanted to deploy a Django website and learn Qt. I named my project&amp;nbsp;Metalify.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Metalify Icon" src="https://www.executionunit.com/static/media/uploads/blog/icon_256x2561.jpg"&gt;&lt;/p&gt;
&lt;h2 id="server-side"&gt;Server&amp;nbsp;Side&lt;/h2&gt;
&lt;p&gt;Most of the content that you see in the spotify client is actually presented via webpages. So in Metalify I deployed a Django server to server album listings, individual albums with thier track listing and a little blurb. I didn&amp;#8217;t get a chance to implement the search features that Spotify has but tbh they are just more&amp;nbsp;webpages.&lt;/p&gt;
&lt;h2 id="client-side"&gt;Client&amp;nbsp;Side&lt;/h2&gt;
&lt;p&gt;I had a hunch that Spotify was written in Qt (statically linked). I&amp;#8217;ve used many many frameworks for apps (&lt;span class="caps"&gt;MFC&lt;/span&gt;, WxWidgets, Fox, Cocoa) but never Qt. Qt suits my needs as I wanted a single code base that compiles for MacOS X and Windows but looks&amp;nbsp;native.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Metalify OSX" src="https://www.executionunit.com/static/media/uploads/blog/metalify-osx1.jpg"&gt;
&lt;img alt="Metalify Windows" src="https://www.executionunit.com/static/media/uploads/blog/metalify-win321.jpg"&gt;&lt;/p&gt;
&lt;p&gt;As you can see they look pretty native on each&amp;nbsp;platform.&lt;/p&gt;
&lt;p&gt;Having never used Qt before I was surprised at how easy it was to get stuck in. Qt comes with a Qt Designer an interface builder application allowing you to build an interface and test it within the designer. Despite a few oddities it&amp;#8217;s pretty easy to use and saves out a .&lt;span class="caps"&gt;UI&lt;/span&gt; file that you can load into you mainwindow&amp;nbsp;class.&lt;/p&gt;
&lt;p&gt;&lt;img alt="QtDesigner" src="https://www.executionunit.com/static/media/uploads/blog/qtdesigner1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Within Qt Designer you can edit style sheets to style your interface.&amp;nbsp;Use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;231&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;QFrame&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#939393&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;QPushButton&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is a really good idea. I actually &lt;span class="caps"&gt;LOVE&lt;/span&gt; this feature. It makes so much sense. The downside is that it carries all the baggage of &lt;span class="caps"&gt;CSS&lt;/span&gt;, your &lt;span class="caps"&gt;CSS&lt;/span&gt; file can quickly become a complete&amp;nbsp;mess!&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;CSS&lt;/span&gt; allowed me to style the play/skip buttons and make them&amp;nbsp;round&lt;/p&gt;
&lt;p&gt;&lt;img alt="CSS Buttons" src="https://www.executionunit.com/static/media/uploads/blog/client-buttons1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;playButton&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sx"&gt;:/resources/play.png&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;playButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sx"&gt;:/resources/play_hover.png&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;playButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nd"&gt;pressed&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sx"&gt;:/resources/play_depressed.png&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;By setting the border-radius for a button you can make it round, change for mouse over and being clicked. I&amp;#8217;ve never made a cool looking button in a application framework this easily&amp;nbsp;before.&lt;/p&gt;
&lt;p&gt;The downside of the style sheet system is that not all widgets support it. This meant that I couldn&amp;#8217;t style the volume (Phonon::VolumeSlider) or scrub widget (Phonon::SeekSlider). As far as I could work out the only way to customize the look of these widets was to subclass and override Widget::paint which seemed like overkill for a week long&amp;nbsp;experiment.&lt;/p&gt;
&lt;h2 id="audio"&gt;Audio&lt;/h2&gt;
&lt;p&gt;Qt comes with a audio framework called Phonon. It&amp;#8217;s not very mature but is workable. Combined with the network code it actually made playing MP3s on the mac &lt;span class="caps"&gt;VERY&lt;/span&gt; easy. Infact, taking some sample code I was downloading and playing MP3s within an&amp;nbsp;hour.&lt;/p&gt;
&lt;p&gt;Spotify has a caching mechanism so you can play tunes offline (if you pay) and to limit their bandwidth costs. I implemented a simple cache system which stored the downloaded MP3s in a platform specific cache folder. The logic is thus: If the file isn&amp;#8217;t in the cache start playing the file streamed from the server (so it starts to play within a few seconds) and also download it from the server. This isn&amp;#8217;t ideal as the file is downloaded twice. It was however quick to implement and allowed me to use the high level Qt&amp;nbsp;classes.&lt;/p&gt;
&lt;p&gt;On Win32 audio playback wasn&amp;#8217;t so easy. For some reason certain MP3s just didn&amp;#8217;t playback on Win32. Phonon on Win32 wraps DirectShow and DirectShow wraps various decoders. Despite the Qt Capabilities program saying it should be able to decode &lt;span class="caps"&gt;MP3&lt;/span&gt; it kept failing for specific MP3s. I re-encoded them using Lame (default settings) and then they were able to play. This unnerved me a little and was my first hint that maybe Phonon isn&amp;#8217;t as mature as I had&amp;nbsp;hoped.&lt;/p&gt;
&lt;h2 id="integration-of-the-website-and-client"&gt;Integration of the Website and&amp;nbsp;Client&lt;/h2&gt;
&lt;p&gt;As I said before Spotify displays most of it&amp;#8217;s information via webpages. Similarly the right hand pane of Metalify is a QWebView. Integrating the website and the client was really&amp;nbsp;easy.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mainFrame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;evaluateJavaScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jQuery&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mainFrame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addToJavaScriptWindowObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;player&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;evaluateJavaScript allows me to inject any javascript I wished into the &lt;span class="caps"&gt;HTML&lt;/span&gt; page downloaded from the server. addToJavaScriptWindowObject allowed me to expose a carefully crafted C++ object to the Javascript running in the&amp;nbsp;page.&lt;/p&gt;
&lt;p&gt;Using these two access routes I was able to work out the currently selected track, see what tracks to start downloading and update the currently playing track. This was all a lot easier than I had&amp;nbsp;expected.&lt;/p&gt;
&lt;h2 id="cross-platform-dev"&gt;Cross Platform&amp;nbsp;Dev&lt;/h2&gt;
&lt;p&gt;The primary reason for choosing Qt was cross platform development. Qt actually helped (as opposed to a lot of tools that claim to help but actually get in the way). I read a few pages of the extensive Qt docs and I was&amp;nbsp;away.&lt;/p&gt;
&lt;p&gt;Qt uses a .pro file which is a make file for it&amp;#8217;s qmake utility. I used qmake to create an XCode project and then XCode to compile/debug. Moving to WinXP I used QTCreator as an &lt;span class="caps"&gt;IDE&lt;/span&gt; which builds using Ming-w32 (a windows port of gcc). QTCreator is a fairly complete &lt;span class="caps"&gt;IDE&lt;/span&gt; that comes with &lt;span class="caps"&gt;QT&lt;/span&gt; and was fine for my needs. I don&amp;#8217;t know if I could use it day in day out as I basically used it to call qmake! I could have chosen to build with Visual Studio but since my main aim was to get the code and build (not write or debug) on Windows it didn&amp;#8217;t make sense to complicate the build process too much on Win32. Most of the time Qt hid the differences between Win32 and &lt;span class="caps"&gt;OS&lt;/span&gt; X from me and everything just worked. Very&amp;nbsp;impressive.&lt;/p&gt;
&lt;h2 id="client-installer"&gt;Client&amp;nbsp;Installer&lt;/h2&gt;
&lt;p&gt;As I was making a fake consumer application I needed to make an installer. As I had used Nullsoft Installer System (&lt;span class="caps"&gt;NSIS&lt;/span&gt;) before I quickly created an install/uninstall script and found myself on the usual &lt;span class="caps"&gt;DLL&lt;/span&gt; nightmare of Win32. Qt recommend the use ofDependency Walker which analyses an exe and lists all the DLLs required to run it. Turns out I needed a lot of&amp;nbsp;them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;File &amp;quot;c:\Qt\2010.04\mingw\bin\mingwm10.dll&amp;quot;
File &amp;quot;c:\Qt\2010.04\mingw\bin\libgcc_s_dw2-1.dll&amp;quot;
File &amp;quot;c:\Qt\2010.04\qt\bin\phonon4.dll&amp;quot;
File &amp;quot;c:\Qt\2010.04\qt\bin\QtCore4.dll&amp;quot;
File &amp;quot;c:\Qt\2010.04\qt\bin\QtGui4.dll&amp;quot;
File &amp;quot;c:\Qt\2010.04\qt\bin\QtNetwork4.dll&amp;quot;
File &amp;quot;c:\Qt\2010.04\qt\bin\QtWebKit4.dll&amp;quot;
File &amp;quot;c:\Qt\2010.04\qt\bin\QtXmlPatterns4.dll&amp;quot;
This pushed the installer size to ~10MB.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Making an installer on MacOS was a little bit easier. Qt ships with a tool to look at an app and build a &lt;span class="caps"&gt;DMG&lt;/span&gt; (Disk Image) which the end user can mount and then copy the .App to their Applications folder. The one App contains all the Shared Libraries (DLLs) that the App needs to&amp;nbsp;run.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;macdeployqt&lt;span class="w"&gt; &lt;/span&gt;client.app&lt;span class="w"&gt; &lt;/span&gt;-dmg&lt;span class="w"&gt; &lt;/span&gt;-no-plugins
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To my horror this made an app that was &lt;span class="caps"&gt;96MB&lt;/span&gt; and the &lt;span class="caps"&gt;DMG&lt;/span&gt; file was 32 &lt;span class="caps"&gt;MB&lt;/span&gt;. To be fair this is a Universal app so the App and Shared libraries were in x86 and &lt;span class="caps"&gt;PPC&lt;/span&gt; formats but that still over twice the size of the Win32&amp;nbsp;installer!&lt;/p&gt;
&lt;h2 id="lessons-learned"&gt;Lessons&amp;nbsp;Learned&lt;/h2&gt;
&lt;p&gt;I really enjoyed writing working on this project and I think I learned and achieved a&amp;nbsp;lot.&lt;/p&gt;
&lt;p&gt;Qt &lt;span class="caps"&gt;REALLY&lt;/span&gt; is a great library. The fact that it comes under the free &lt;span class="caps"&gt;LGPL&lt;/span&gt; license or a proprietary license is very generous of Nokia. While I&amp;#8217;d rather not see the &lt;span class="caps"&gt;GPL&lt;/span&gt;, I favour more liberal &lt;span class="caps"&gt;BSD&lt;/span&gt;/&lt;span class="caps"&gt;MIT&lt;/span&gt; licenses, I do understand that they want any good changes to Qt to come back to them. After all they are giving you the source to a &lt;span class="caps"&gt;VERY&lt;/span&gt; good library to play with so it&amp;#8217;s good to give&amp;nbsp;back.&lt;/p&gt;
&lt;p&gt;If Spotify is built using Qt then they must be statically linking with &lt;span class="caps"&gt;QT&lt;/span&gt;. My app is massive compared to theirs. &lt;span class="caps"&gt;IF&lt;/span&gt; they are not useing Qt then I&amp;#8217;d love to know why not as it really is ideally suited to this kind of task. It&amp;#8217;s easily skinnable, robust, complete and well&amp;nbsp;documented.&lt;/p&gt;
&lt;p&gt;Django is very simple to use if a little tedious to set up and deploy behind apache. It&amp;#8217;s not that different from TurboGears. It&amp;#8217;s well documented and heavily indexed by google. Django Snippets is a great resource for niggly questions like &amp;#8220;how to I efficiently sever a multi &lt;span class="caps"&gt;MB&lt;/span&gt;&amp;nbsp;file&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Qt&amp;#8217;s community seems to be a bit lacking. I found few useful resources of creating custom Widgets. This seemed a shame to&amp;nbsp;me.&lt;/p&gt;
&lt;h2 id="issues"&gt;Issues&lt;/h2&gt;
&lt;p&gt;The code is most definitely alpha quality. Firstly the download is far too big. I&amp;#8217;m pretty sure static linking Qt into the client would make it bigger but not needing the Qt DLLs/Shared Libraries would be a&amp;nbsp;win.&lt;/p&gt;
&lt;p&gt;On Mac &lt;span class="caps"&gt;OSX&lt;/span&gt; the client takes 100% &lt;span class="caps"&gt;CPU&lt;/span&gt; time while playing an &lt;span class="caps"&gt;MP3&lt;/span&gt;. I only noticed this after finishing the code (I&amp;#8217;ve got 4 CPUs so I didn&amp;#8217;t notice loosing one of them). I&amp;#8217;m pretty sure this is a Phonon bug/issue as All I do is ask Phonon to play the &lt;span class="caps"&gt;MP3&lt;/span&gt; and then wait for events to&amp;nbsp;fire.&lt;/p&gt;
&lt;p&gt;The code to cache MP3s doesn&amp;#8217;t condsider the size of the cache so it will grow for ever. Spotify sets a limit to downloaded content defaulting to &lt;span class="caps"&gt;10GB&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;If you play an album and then navigate to another album the player get confused. This would be trivial to fix but I&amp;#8217;ve left it as an exercise for the reader&amp;nbsp;;)&lt;/p&gt;
&lt;p&gt;The left hand pane of the client has links to What&amp;#8217;s New, Radio etc these are all placeholders and do nothing. They would be easy to hook up to urls in the web view&amp;nbsp;though.&lt;/p&gt;
&lt;p&gt;The test website has three albums on it (quite a lot less than spotify but it&amp;#8217;s close). I haven&amp;#8217;t got permission to distribute these releases but they are all freely available from the bands for free as downloads. Please remember this is just sample code and a sample&amp;nbsp;website.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I &lt;span class="caps"&gt;REALLY&lt;/span&gt; enjoyed this project. Cloning someone elses work is a great way to focus on the code and it&amp;#8217;s easy to make progress and judge the quality of what you create. I think what is there is a good jumping off point for creating a competing product to&amp;nbsp;spotify.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re interested in taking the code and running with it please do. Execution Unit Ltd is placing this code into the public&amp;nbsp;domain.&lt;/p&gt;
&lt;h2 id="source-code"&gt;Source&amp;nbsp;Code&lt;/h2&gt;
&lt;p&gt;You can get the source code for the project on &lt;a href="https://bitbucket.org/executionunit/metalify"&gt;BitBucket&lt;/a&gt;.&lt;/p&gt;</content><category term="misc"></category><category term="C++"></category><category term="Qt"></category></entry><entry><title>Apple TnC Changes and Lua</title><link href="https://www.executionunit.com/blog/2010/08/11/apple-tnc-changes-and-lua/" rel="alternate"></link><published>2010-08-11T00:00:00+01:00</published><updated>2010-08-11T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2010-08-11:/blog/2010/08/11/apple-tnc-changes-and-lua/</id><summary type="html">&lt;p&gt;With the &lt;a href="http://en.wikipedia.org/wiki/Beta_software#Beta"&gt;beta&lt;/a&gt; release of iPhone &lt;span class="caps"&gt;OS&lt;/span&gt; 4.0 Apple has changed the terms and conditions for developers who want to target the iPhone platform (note that includes the iPod Touch and&amp;nbsp;iPad).&lt;/p&gt;
&lt;p&gt;There has been a of discussion about changes to clause 3.3.1 most notably by Gruber …&lt;/p&gt;</summary><content type="html">&lt;p&gt;With the &lt;a href="http://en.wikipedia.org/wiki/Beta_software#Beta"&gt;beta&lt;/a&gt; release of iPhone &lt;span class="caps"&gt;OS&lt;/span&gt; 4.0 Apple has changed the terms and conditions for developers who want to target the iPhone platform (note that includes the iPod Touch and&amp;nbsp;iPad).&lt;/p&gt;
&lt;p&gt;There has been a of discussion about changes to clause 3.3.1 most notably by Gruber on Daring Fireball &lt;a href="http://daringfireball.net/2010/04/iphone_agreement_bans_flash_compiler"&gt;here&lt;/a&gt; and &lt;a href="http://daringfireball.net/2010/04/why_apple_changed_section_331"&gt;here&lt;/a&gt;. Steve Jobs references the second article in a reply &lt;a href="http://www.taoeffect.com/blog/2010/04/steve-jobs-response-on-section-3-3-1/"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;3.3.1 — Applications may only use Documented APIs in the manner
prescribed by Apple and must not use
or call any private APIs. Applications
must be &lt;strong&gt;originally written&lt;/strong&gt; in
Objective-C, C, C++, or JavaScript as
executed by the iPhone &lt;span class="caps"&gt;OS&lt;/span&gt; WebKit
engine, and only code written in C,
C++, and Objective-C may &lt;strong&gt;compile and
directly link against&lt;/strong&gt; the Documented
APIs (e.g., Applications that link to
Documented APIs through an
intermediary translation or
compatibility layer or tool are&amp;nbsp;prohibited).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;my emphasis&amp;nbsp;added&lt;/p&gt;
&lt;p&gt;Gruber basically makes the point that Apple is trying to keep substandard abstraction layers out of the iPhone eco system so that they can control the quality more easily. This is a fair point. The strength of the iPhone eco system is that there is a certain degree of uniformity of the interfaces and styles of interfaces. It should be noted that Apple has always reserved the right to reject apps at submission time for being substandard or not following their interface&amp;nbsp;guidelines.&lt;/p&gt;
&lt;p&gt;So why am I writing about this? Well a few weeks ago I finished my Lua abstraction layer and there is a lot of chatter about whether Lua breaks the new TnC. Lua itself is written in C which is good and you embed it in &lt;span class="caps"&gt;YOUR&lt;/span&gt; code and it largely only interfaces with your code bar system calls for malloc, fopen, etc. So Lua (the runtime) compiles and links against the documented &lt;span class="caps"&gt;API&lt;/span&gt; and it&amp;#8217;s written in C, no problem there. The other side of the equation is the runtime scripts that my engine runs to perform &lt;span class="caps"&gt;AI&lt;/span&gt;. Now they are compiled but do &lt;span class="caps"&gt;NOT&lt;/span&gt; link directly against Apple &lt;span class="caps"&gt;API&lt;/span&gt;&amp;#8217;s. The compiled Lua, in it&amp;#8217;s bytecode form only interfaces with the Lua runtime and the runtime (which meets the new TnC) makes the system&amp;nbsp;calls.&lt;/p&gt;
&lt;p&gt;So my reading of this is that Lua doesn&amp;#8217;t break the&amp;nbsp;TnC.&lt;/p&gt;
&lt;p&gt;But I might be wrong and that&amp;#8217;s fine, I&amp;#8217;ll develop my game using Lua and port across to C++ if the app is rejected. I don&amp;#8217;t think it will be but if it is I will just bite the bullet. I&amp;#8217;m not saying I will like it, but I will do&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Having worked in the Video Games industry for 15 years I am not surprised by seemingly draconian Terms and Conditions from hardware manufacturers. Anyone who has ever worked with Sony, Nintendo or Microsoft is accustomed to arcane submission protocols, arbitrary enforcement of rules and seemingly arbitrary rejections upon&amp;nbsp;submission.&lt;/p&gt;
&lt;p&gt;The deal we all strike with the platform providers is that they keep the eco system alive and well, they keep up standards and we try our best to comply with those standards. In return we get access to their customers. With Apple this is even more real as there are millions of units in the hands of people who are willing to pay money for a wide variety of games and apps. Apple provides an App Store, International Billing and Distribution network all for a fixed cost per sale. It&amp;#8217;s an amazing deal for an indie developer. The reason I think a lot of people are complaining is because they think that the App Store is or should be a democracy. Well if that is what the market place wants then I am sure apple will deliver that but at the moment we&amp;#8217;ll just get used to playing by Apple&amp;#8217;s rules and getting access to 50,000,000+ users&amp;nbsp;worldwide!&lt;/p&gt;
&lt;p&gt;s&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category></entry><entry><title>NvStrip and Blender – Stripifying Models for the iPhone/iPad.</title><link href="https://www.executionunit.com/blog/2010/06/14/nvstrip-and-blender-stripifying-models-for-the-iphoneipad/" rel="alternate"></link><published>2010-06-14T00:00:00+01:00</published><updated>2010-06-14T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2010-06-14:/blog/2010/06/14/nvstrip-and-blender-stripifying-models-for-the-iphoneipad/</id><summary type="html">&lt;h2 id="what-is-stripification"&gt;What Is&amp;nbsp;Stripification?&lt;/h2&gt;
&lt;p&gt;Stripification is the process of turning lists of triangles in an arbitrary order into as many lists of triangles that contain adjacent edges. There is a great explanation of a triangle strip of&amp;nbsp;wikipedia.&lt;/p&gt;
&lt;h2 id="why-would-you-stripify"&gt;Why would you&amp;nbsp;stripify?&lt;/h2&gt;
&lt;p&gt;On most platforms Triangle Strips render more quickly. The …&lt;/p&gt;</summary><content type="html">&lt;h2 id="what-is-stripification"&gt;What Is&amp;nbsp;Stripification?&lt;/h2&gt;
&lt;p&gt;Stripification is the process of turning lists of triangles in an arbitrary order into as many lists of triangles that contain adjacent edges. There is a great explanation of a triangle strip of&amp;nbsp;wikipedia.&lt;/p&gt;
&lt;h2 id="why-would-you-stripify"&gt;Why would you&amp;nbsp;stripify?&lt;/h2&gt;
&lt;p&gt;On most platforms Triangle Strips render more quickly. The iPhone and iPad are generally fill bound (meaning the slowest part of the pipleline is plotting pixels) so, for most cases, there doesn&amp;#8217;t seem to be a speed&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;Triangle strips do however take up less memory because a triangle strip index takes up less&amp;nbsp;memory.&lt;/p&gt;
&lt;p&gt;NVTriStripLib&lt;/p&gt;
&lt;p&gt;A long time ago NVidia released source code for striping called the &lt;a href="http://developer.nvidia.com/object/nvtristrip_library.html"&gt;NvTriStrip Library&lt;/a&gt;. It has a very simple interface, can generate multiple strips or one long strip with distinct strips joined by degenerate triangles (stitching). It can also limit the length of a strip to maximise caching on the NVidia platform (something I don&amp;#8217;t really care&amp;nbsp;about).&lt;/p&gt;
&lt;p&gt;One small problem with NvTriStrip Lib is that it doesn&amp;#8217;t compile on XCode because of a few small C++ scope issues. These are easy to solve with a few gotchas to look out&amp;nbsp;for.&lt;/p&gt;
&lt;h2 id="blender-integration"&gt;Blender&amp;nbsp;Integration&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;ve read my previous blogs you&amp;#8217;ll know that I am using blender and a level editor, animation package and basic modeller. My exporter is written in Python so I needed to integrate python and C++. I could have written a python module and imported it into the exporter code but I decided to write a command line&amp;nbsp;utility.&lt;/p&gt;
&lt;p&gt;Writing a python module is a little bit more complicated then I wanted. I needed a small wrapper around the NVTriStrip code which took the triangle vertex indices and returned the strip data I needed. Piping the data too and from a command line app seemed the easiest&amp;nbsp;route.&lt;/p&gt;
&lt;h2 id="calling-a-command-line-utility-from-python"&gt;Calling A Command Line Utility From&amp;nbsp;Python&lt;/h2&gt;
&lt;p&gt;In the new(ish) world of python you use the subprocess module to call a command line up from python and open it&amp;#8217;s stdin and stdout pipes (or&amp;nbsp;files).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;blender_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abspath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;STRIPY_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blender_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Stripy&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;STRIPY_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;close_fds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;subprocess.Popen is passed a list of arguments (the first being the path to the executable application), the -s tells the app to stitch disparate strips together. subprocess.&lt;span class="caps"&gt;PIPE&lt;/span&gt; tells Popen that we would like the application&amp;#8217;s stdin and stdout to be&amp;nbsp;pipes.&lt;/p&gt;
&lt;p&gt;Once the app is open we can access it&amp;#8217;s stdin and stdout via p.stdin and p.stdout. So to send it the triangles vertex indices we do something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;indices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%d&lt;/span&gt;&lt;span class="s2"&gt; &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; -1&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The -1 at the end is an an invalid index for a triangle index and we use it to mark the end of the input stream. We could close the p.stdin but I decided to do this for some&amp;nbsp;reason.&lt;/p&gt;
&lt;p&gt;As soon as stripy get a -1 it starts to process the indices that you have passed it printing the results to it&amp;#8217;s stdout, so we can read the data via&amp;nbsp;p.stdout.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;numstrips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;numstrips&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;ExUnitException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Expected at least one strip to be returned&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sidx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numstrips&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;striptype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;numindices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;indices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2 id="stripy"&gt;Stripy&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;ve put up the code for Stripy including the (slightly) modified version of the NVTriStrip code which is owned by NVidia and all credit needs to go to them for putting it out there for us to play&amp;nbsp;with.&lt;/p&gt;
&lt;p&gt;You can &lt;a href="https://bitbucket.org/executionunit/exunit_public"&gt;download it here&lt;/a&gt;. The application takes two command line arguments -cs n allowing you to set the hardware cache size (you can ignore this) and -s to stitch disparate strips&amp;nbsp;together.&lt;/p&gt;
&lt;p&gt;Have&amp;nbsp;fun,&lt;/p&gt;
&lt;p&gt;dazza.&lt;/p&gt;</content><category term="gamedev"></category><category term="C++"></category><category term="GameDev"></category><category term="Python"></category><category term="Blender"></category></entry><entry><title>A Pythonic “Center New” in Blender</title><link href="https://www.executionunit.com/blog/2010/04/28/a-pythonic-center-new-in-blender/" rel="alternate"></link><published>2010-04-28T00:00:00+01:00</published><updated>2010-04-28T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2010-04-28:/blog/2010/04/28/a-pythonic-center-new-in-blender/</id><summary type="html">&lt;p&gt;Part of my Art pipeline for Tentacles is to import a directory of &lt;span class="caps"&gt;3DS&lt;/span&gt; files. Each of these files is a map piece and the map pieces are instanced to create a map. That way I can store the geometry for a shack once but instance it across the level …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Part of my Art pipeline for Tentacles is to import a directory of &lt;span class="caps"&gt;3DS&lt;/span&gt; files. Each of these files is a map piece and the map pieces are instanced to create a map. That way I can store the geometry for a shack once but instance it across the level many times with a unique transform (scale, translation and&amp;nbsp;rotation).&lt;/p&gt;
&lt;p&gt;&lt;img alt="alt text" src="https://www.executionunit.com/static/media/uploads/blog/mappieces1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Here you can see two map pieces and the big white box is the collision mesh that will be used for the map&amp;nbsp;pieces&lt;/p&gt;
&lt;p&gt;Upon importing the &lt;span class="caps"&gt;3DS&lt;/span&gt; file I join the separate meshes together into one mesh and then reset the center of the model in the &lt;span class="caps"&gt;XY&lt;/span&gt; (ground) plane so that the map pieces can be snapped together and tiled&amp;nbsp;easily.&lt;/p&gt;
&lt;h2 id="center-new"&gt;Center&amp;nbsp;New&lt;/h2&gt;
&lt;p&gt;To move the center of an object to the center of the mesh Blender has a button calledCenter New (Editing Pane, Mesh Subpanel). Unfortunately there isn&amp;#8217;t an easy way to invoke this from within&amp;nbsp;python.&lt;/p&gt;
&lt;p&gt;I found this code on the internet quite quickly but I found that for some models it just wasn&amp;#8217;t working. Infact for some models if I called the function twice the center changed&amp;nbsp;twice!&lt;/p&gt;
&lt;p&gt;I rejigged the code a little to get it to work every time on Blender 2.49. Other then renaming the variables to make it a little easier to read I get the objects bounding box before manipulating the object and it&amp;#8217;s meshes matrix.&amp;nbsp;Use&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;center_new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bobject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xfactor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yfactor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zfactor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;bbbox&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bobject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getBoundBox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;bmesh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bobject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bobject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMatrix&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;bmesh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bmesh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Blender&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mathutils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;bobject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setMatrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bboxcenter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bbbox&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;bbbox&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bbbox&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bobject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getMatrix&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Blender&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mathutils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][:],&lt;/span&gt;
                         &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][:],&lt;/span&gt;
                         &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][:],&lt;/span&gt;
                         &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bboxcenter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;xfactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bboxcenter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;yfactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bboxcenter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;zfactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;bmesh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;bmesh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Blender&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mathutils&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][:],&lt;/span&gt;
                     &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][:],&lt;/span&gt;
                     &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][:],&lt;/span&gt;
                     &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bboxcenter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;xfactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bboxcenter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;yfactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                      &lt;span class="n"&gt;bboxcenter&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;zfactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;bobject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setMatrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="Python"></category><category term="Blender"></category></entry><entry><title>Implementing glAlphaFunc in OpenGL ES2.0</title><link href="https://www.executionunit.com/blog/2010/04/12/implementing-glalphafunc-in-opengl-es20/" rel="alternate"></link><published>2010-04-12T00:00:00+01:00</published><updated>2010-04-12T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2010-04-12:/blog/2010/04/12/implementing-glalphafunc-in-opengl-es20/</id><summary type="html">&lt;p&gt;In OpenGL &lt;span class="caps"&gt;ES&lt;/span&gt; 2.0 glAlphaFunc isn&amp;#8217;t available, you have to implement it in a fragment shader. There isn&amp;#8217;t a lot of reference out there for this (not that I could find anyway) so I thought I&amp;#8217;d write this&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s actually quite simple to implement …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In OpenGL &lt;span class="caps"&gt;ES&lt;/span&gt; 2.0 glAlphaFunc isn&amp;#8217;t available, you have to implement it in a fragment shader. There isn&amp;#8217;t a lot of reference out there for this (not that I could find anyway) so I thought I&amp;#8217;d write this&amp;nbsp;up.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s actually quite simple to implement a quick alpha test. I needed to be able to cookie cut out sprites and fonts so I simply needed to reject fragments where the alpha value was zero. Here are the guts of a shader to do&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;#ifdef GL_ES &lt;/span&gt;
&lt;span class="k"&gt;precision&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;highp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cp"&gt;#endif &lt;/span&gt;
&lt;span class="k"&gt;uniform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;sampler2D&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u_tex0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="k"&gt;uniform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u_alphatestenable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="k"&gt;varying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;vec2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v_texCoord&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;varying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;vec4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v_color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;//calculate the fragment color based on the texture and the vertex colour&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;vec4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;basecolor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;texture2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;u_tex0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v_texCoord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v_color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;//if testing is enabled, check the alpha component and discard if zero      &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u_alphatestenable&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basecolor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;//throw this fragment away&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;discard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;gl_FragColor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;basecolor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You need to set up a uniform variable u_alphatestenable which enables the alpha test. If you want to support different test types ( less than, greater than etc) then you will need two more uniform variables: one for the test type and one for the value to test&amp;nbsp;against.&lt;/p&gt;
&lt;p&gt;To enable the test you need to set uni_alphatest_enable to&amp;nbsp;true:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uni_alphatest_enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;glGetUniformLocation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mProgram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;u_alphatestenable&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alphateston&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;glUniform1i&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uni_alphatest_enable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alphateston&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;note that you shouldn&amp;#8217;t call glGetUniformLocation every frame, it should be cached somewhere.
It&amp;#8217;s quite simple and while you may be thinking oh that is so slow it not that bad. It&amp;#8217;s faster then the fixed function pipeline which is doing tests for alpha, lights, blend modes etc. If you get paranoid then you can create multiple shaders that support different subsets of features. All you need to be careful of is the cost of calling glSetProgram (to switch shaders) which can be expensive and cause bubbles in the vertex pipeline in the&amp;nbsp;hardware.&lt;/p&gt;
&lt;p&gt;Hope it&amp;nbsp;helps.&lt;/p&gt;
&lt;p&gt;dazza&lt;/p&gt;</content><category term="gamedev"></category><category term="C++"></category><category term="Gamedev"></category><category term="OpenGL"></category></entry><entry><title>Integrating Bullet Physics</title><link href="https://www.executionunit.com/blog/2010/03/20/integrating-bullet-physics/" rel="alternate"></link><published>2010-03-20T00:00:00+00:00</published><updated>2010-03-20T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2010-03-20:/blog/2010/03/20/integrating-bullet-physics/</id><summary type="html">&lt;p&gt;&lt;a href="http://bulletphysics.org/wordpress/"&gt;Bullet&lt;/a&gt; is an open source collision and physics simulation library written by Erwin Coumans who I believe worked or maybe still does work at &lt;span class="caps"&gt;SCEA&lt;/span&gt; (Sony Computer Entertainment America). Bullet provides a C++ &lt;span class="caps"&gt;API&lt;/span&gt; to a very robust Collision, Rigid Body and Soft body simulation system. At its core Bullet …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://bulletphysics.org/wordpress/"&gt;Bullet&lt;/a&gt; is an open source collision and physics simulation library written by Erwin Coumans who I believe worked or maybe still does work at &lt;span class="caps"&gt;SCEA&lt;/span&gt; (Sony Computer Entertainment America). Bullet provides a C++ &lt;span class="caps"&gt;API&lt;/span&gt; to a very robust Collision, Rigid Body and Soft body simulation system. At its core Bullet is comparable to commercial systems such as Havok but lacks the art pipeline integration, extensive documentation and support contracts that its commercial rivals offer. For an indie developer it’s an amazing leg up though. Collision is hard to do well. Physics is also hard to do well. Bullet does both very&amp;nbsp;well.&lt;/p&gt;
&lt;h2 id="gradual-integration"&gt;Gradual&amp;nbsp;Integration&lt;/h2&gt;
&lt;p&gt;Bullet has a layered compartmentalised design. So my plan was to first integrate collision and later Rigid body simulation. The documentation that Bullet offers is a little sparse but the source package includes a lot of demo code ranging from helloworld to a forkliftdemo to the classic how many boxes can I stack before the physics explodes. While it’s intimidating at first, collision and physics are so core to your game engine it’s important to spend the time integrating exactly what you need, where you need&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Blender has Bullet integrated as well. Unfortunately not everything is exposed to the python export script. Rigid Body parameters to do with damping and most Soft body parameters are not available. The next version of Blender, which is a complete rewrite, should fix this. Unfortunately your export script will have to be rewritten as&amp;nbsp;well.&lt;/p&gt;
&lt;h2 id="building-the-bullet-codebase"&gt;Building the Bullet&amp;nbsp;Codebase&lt;/h2&gt;
&lt;p&gt;The first thing I would recommend doing is building the bullet source package. Just follow the instructions in &lt;span class="caps"&gt;INSTALL&lt;/span&gt;. It&amp;#8217;s worth installing CMake (as they suggest) as without it not &lt;span class="caps"&gt;ALL&lt;/span&gt; the demos will&amp;nbsp;compile.&lt;/p&gt;
&lt;p&gt;After compilation an executable called AllBulletDemos will be in in BulletSrc/Demos/AllBulletDemos unfortunately it doesn&amp;#8217;t have all the demos in it but it does have a lot of them. Playing around with these demos will give you an idea of what Bullet is capable of and more importantly where to look for sample code. Bullet&amp;#8217;s lacks hand holding documentation and you are expected to dig around in demos and find code that is useful to&amp;nbsp;you.&lt;/p&gt;
&lt;p&gt;&lt;img alt="alt text" src="https://www.executionunit.com/static/media/uploads/blog/bulletdemos1.jpg"&gt;&lt;/p&gt;
&lt;h2 id="getting-data-from-blender-into-collision"&gt;Getting Data From Blender Into&amp;nbsp;Collision&lt;/h2&gt;
&lt;p&gt;It’s well worth thinking about this quite carefully. Bullet recommends that you merge all static meshes into one big mesh. It also recommends that you don’t&amp;nbsp;submit&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;large triangles (&amp;gt;10&amp;nbsp;units)&lt;/li&gt;
&lt;li&gt;very small&amp;nbsp;triangles&lt;/li&gt;
&lt;li&gt;very long thin&amp;nbsp;triangles.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general the same routines you used in you blender geometry exporter will suffice for exporting the collision mesh. You should consider optimising the collision mesh to reduce the amount of data while remembering not to include degenerate (or near degenerate) triangles or overly large&amp;nbsp;triangles.&lt;/p&gt;
&lt;p&gt;&lt;img alt="alt text" src="https://www.executionunit.com/static/media/uploads/blog/staticmesh1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;In blender objects marked as Actors with Static selected are static collision meshes. To test for this is your python&amp;nbsp;exporter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rbFlags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RBFlags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ACTOR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rbFlags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RBFlags&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;RIGIDBODY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; 
    &lt;span class="c1"&gt;#export the static mesh data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Bullet uses an OpenGL-ish method for submitting a large number of triangles for a mesh. This allows you to create an Index Vertex Array and from that build a Triangle Mesh Shape. One niggle is that the iPad uses 8 or 16 bit index values (GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT) whereas Bullet uses int (32 bit) indexes. This means you can’t submit your render index list to the collision system. In the long run you wouldn’t do this anyway but it would be nice to be able to use different index&amp;nbsp;sizes.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;mIndexVertexArray&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btTriangleIndexVertexArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mNumIndices&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mIndices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mNumVertex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;btScalar&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;mVertex&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ColVertex&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;btVector3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;aabbMin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;-10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;-10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;-10000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;aabbMax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;useQuantizedAabbCompression&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;mTriMeshShape&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btBvhTriangleMeshShape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mIndexVertexArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;useQuantizedAabbCompression&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;aabbMin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aabbMax&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h2 id="adding-meshes-to-your-collision-world"&gt;Adding Meshes To Your Collision&amp;nbsp;World&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;//Generic way to build and configure a Bullet Collision World with Dynamics &lt;/span&gt;
&lt;span class="n"&gt;mColConfiguration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btDefaultCollisionConfiguration&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;mColDispatcher&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btCollisionDispatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mColConfiguration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mColOverlappingPairCache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btDbvtBroadphase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;mColSolver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btSequentialImpulseConstraintSolver&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;mColDynamicsWorld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btDiscreteDynamicsWorld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mColDispatcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mColOverlappingPairCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mColSolver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;mColConfiguration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mColDynamicsWorld&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;setGravity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;btVector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;-10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Once you have created a world you need to populate it with you meshes. Bullet advises instancing meshes if possible and merging non instanced meshes into super meshes. When you instance a mesh you have an opportunity to use btScaledBvhTriangleMeshShape to scale the instance. You can&amp;#8217;t scale&amp;nbsp;btBvhTriangleMeshShape.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;btVector3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;localInertia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;btTransform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bttransform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MatrixToBTTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;btDefaultMotionState&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;motionState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btDefaultMotionState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bttransform&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;btRigidBody&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;btRigidBodyConstructionInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;rbInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;motionState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;trimesh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localInertia&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;btRigidBody&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;btRigidBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rbInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mColDynamicsWorld&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;addRigidBody&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Since we are adding static meshes there is no local inertia and mass is set to zero (massless entities in Bullet are considered to have an infinite mass and are immovable). We construct a rigid body from the trimesh and the add the rigid body to the&amp;nbsp;world.&lt;/p&gt;
&lt;h2 id="casting-a-ray-from-the-camera"&gt;Casting A Ray From The&amp;nbsp;Camera&lt;/h2&gt;
&lt;p&gt;&lt;span class="caps"&gt;CML&lt;/span&gt; has a handy function called make_pick_ray which helps in the process of making a camera space ray which can be projected into world space using the camera’s&amp;nbsp;transform.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;make_pick_ray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scalar_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pick_x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;scalar_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pick_y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matrix4x4_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matrix4x4_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;projection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;matrix4x4_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;viewport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vector_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vector_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;[&lt;span class="caps"&gt;IN&lt;/span&gt;] pick_x and pick_y is the x position of the touch on the&amp;nbsp;iPad&lt;/li&gt;
&lt;li&gt;[&lt;span class="caps"&gt;IN&lt;/span&gt;] view is the view transform. I store the rotation of the scene in this matrix depending on the orientation of the&amp;nbsp;iPad&lt;/li&gt;
&lt;li&gt;[&lt;span class="caps"&gt;IN&lt;/span&gt;] projection is the projection matrix you have used to project from world to screen space. I make this using&amp;nbsp;cml::matrix_perspective_xfov_RH&lt;/li&gt;
&lt;li&gt;[&lt;span class="caps"&gt;IN&lt;/span&gt;] viewport is the matrix that describes how to move from normalised or device independant screen space to actual screen space. I make it using&amp;nbsp;cml::matrix_viewport&lt;/li&gt;
&lt;li&gt;[&lt;span class="caps"&gt;OUT&lt;/span&gt;] origin is where the ray is starts in camera&amp;nbsp;space&lt;/li&gt;
&lt;li&gt;[&lt;span class="caps"&gt;OUT&lt;/span&gt;] direction is the direction of the ray, it has unit length if you set normalized to true else it&amp;#8217;s the length of the ray to the far clip plain set in your projection matrix. Once again it&amp;#8217;s in camera space.
In order to get the ray into worldspace you need to multiply both origin and direction by your camera matrix (note not the inverse one you use for projection by the matrix that describes the position of the camera in world&amp;nbsp;space).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cast-the-ray-into-the-collision-world"&gt;Cast The Ray Into the Collision&amp;nbsp;World&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;btCollisionWorld&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ClosestRayResultCallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;rayCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;campos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rayto&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="n"&gt;mWorld&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetColWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;rayTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;raystart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rayto&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rayCallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rayCallback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasHit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;btVector3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colpoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rayCallback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_hitPointWorld&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;btVector3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;colNormal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rayCallback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m_hitNormalWorld&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This really only covered the most basic form of hit testing. Adding capsules, spheres, cylinders, cubes, convex hulls and compound objects are all supported. I suggest you look at the demos&amp;nbsp;:)&lt;/p&gt;
&lt;h2 id="summary"&gt;Summary&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;ve only really covered the basics here. Bullet is a massive piece of code and if you haven&amp;#8217;t played with a physics system before I really think you will struggle. The forum is a help but tbh both collision and physics are hard so you shouldn&amp;#8217;t expect it to be a walk in the park. If your time isn&amp;#8217;t cheap it may well be worth paying for a&amp;nbsp;solution.&lt;/p&gt;</content><category term="gamedev"></category><category term="C++"></category><category term="GameDev"></category></entry><entry><title>Starting Out On The iPad</title><link href="https://www.executionunit.com/blog/2010/03/09/starting-out-on-the-ipad/" rel="alternate"></link><published>2010-03-09T00:00:00+00:00</published><updated>2010-03-09T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2010-03-09:/blog/2010/03/09/starting-out-on-the-ipad/</id><summary type="html">&lt;h2 id="why-the-ipad"&gt;Why the&amp;nbsp;iPad?&lt;/h2&gt;
&lt;p&gt;When the iPad was announced I decided it was time to take the plunge and develop a game for it. Although the iPhone is a powerful piece of hardware I just find the screen too limiting. Every game leaves you wishing you had transparent fingers. The iPad …&lt;/p&gt;</summary><content type="html">&lt;h2 id="why-the-ipad"&gt;Why the&amp;nbsp;iPad?&lt;/h2&gt;
&lt;p&gt;When the iPad was announced I decided it was time to take the plunge and develop a game for it. Although the iPhone is a powerful piece of hardware I just find the screen too limiting. Every game leaves you wishing you had transparent fingers. The iPad seems luxurious with it’s 1024x768 A4 sized&amp;nbsp;screen!&lt;/p&gt;
&lt;p&gt;Having written many game engines over the years, both commercially and for fun I’ve run out of love for writing game engines. They are large and difficult to debug and I wanted to spend my time writing a&amp;nbsp;game.&lt;/p&gt;
&lt;h2 id="starting-out"&gt;Starting&amp;nbsp;Out&lt;/h2&gt;
&lt;p&gt;I looked for engines that I could buy in and I briefly evaluated &lt;span class="caps"&gt;SIO2&lt;/span&gt;, Oolong and Unity by going through the specs and reading this blog. I don’t really have any great technical insights beyond those in the blog and I plumped initially for &lt;span class="caps"&gt;SIO2&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Initially I was quite happy with &lt;span class="caps"&gt;SIO2&lt;/span&gt;. The tutorial videos are great and very instructive on both the use of Blender and the &lt;span class="caps"&gt;SIO2&lt;/span&gt; codebase. After about two weeks I grew weary of the C code that makes up &lt;span class="caps"&gt;SIO2&lt;/span&gt;. It’s hard to move from C++ to C and the code felt very messy (it’s good C code but that doesn’t make it&amp;nbsp;C++).&lt;/p&gt;
&lt;p&gt;Facing the unhappy truth that I will needed to assemble my own engine I started to draw up a plan. The good news was that a large part of the work was assembly and plumbing. My intentions were to use Blender as a level editor, Bullet as a collision/physics system,OpenAL as an audio system and &lt;span class="caps"&gt;CML&lt;/span&gt; for maths. That’s a large amount of work imported from credible stable&amp;nbsp;sources.&lt;/p&gt;
&lt;h2 id="week-one-rolling-my-own"&gt;Week One Rolling My&amp;nbsp;Own&lt;/h2&gt;
&lt;p&gt;The first thing I needed to write was an exporter for Blender and get the data into XCode and Rendered in OpenGL &lt;span class="caps"&gt;ES&lt;/span&gt;. Blender has a Python &lt;span class="caps"&gt;API&lt;/span&gt; and it covers most of what I&amp;nbsp;needed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Blender&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetCurrent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt; 
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Mesh&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;#do some exporting of the mesh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For each mesh it’s just a matter of matching faces to materials and generating index, vertex, uv and color arrays for submission to&amp;nbsp;OpenGL.&lt;/p&gt;
&lt;p&gt;All in all it took about 4 days to get it all&amp;nbsp;working.&lt;/p&gt;
&lt;p&gt;&lt;img alt="First running app on iPad" src="https://www.executionunit.com/static/media/uploads/blog/ipad1_1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;The Red/Green/Blue axis you can see in the top right are tests to see that rotated instances are exported, imported and submitted to OpenGL&amp;nbsp;correctly.&lt;/p&gt;
&lt;p&gt;For four days work I was pretty impressed. It was all going really well :) So next thing to get working is transparency. Semi transparent objects need to be rendered &lt;span class="caps"&gt;AFTER&lt;/span&gt; the solid geometry and from back to front in camera&amp;nbsp;space.&lt;/p&gt;
&lt;p&gt;In practice this means that as the geometry for the scene is submitted to be be rendered any material with a transparent texture or alpha value is added to a list. After all the solid geometry has been rendered these ‘deferred’ strips are projected into camera space (their position relative to the camera is worked out), they are sorted from back to front and rendered in that&amp;nbsp;order.&lt;/p&gt;
&lt;p&gt;&lt;img alt="working transparency" src="https://www.executionunit.com/static/media/uploads/blog/trans1.png"&gt;&lt;/p&gt;
&lt;p&gt;Each of the faces in each box is treated as a separate object to be sorted. Rendering from back to font makes sure that the correct geometry appears through the transparent&amp;nbsp;material.&lt;/p&gt;
&lt;p&gt;Next I moved on to collision and pyhsics&amp;#8230;. Bullet to the&amp;nbsp;rescue.&lt;/p&gt;</content><category term="gamedev"></category><category term="GameDev"></category><category term="C++"></category></entry><entry><title>Replaying an Apache Logfile with Python</title><link href="https://www.executionunit.com/blog/2008/10/01/replaying-an-apache-logfile-with-python/" rel="alternate"></link><published>2008-10-01T00:00:00+01:00</published><updated>2008-10-01T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2008-10-01:/blog/2008/10/01/replaying-an-apache-logfile-with-python/</id><summary type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in October 2008, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;In order to test for a memory leak in &lt;a href="http://www.newmetalarmy.com" title="New Metal Army Homepage"&gt;New Metal Army&lt;/a&gt; I needed to replay my apache log …&lt;/p&gt;</summary><content type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in October 2008, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;In order to test for a memory leak in &lt;a href="http://www.newmetalarmy.com" title="New Metal Army Homepage"&gt;New Metal Army&lt;/a&gt; I needed to replay my apache log files against my test server. Using &lt;a href="http://twill.idyll.org" title="Twill Homepage"&gt;Twill&lt;/a&gt; this was a&amp;nbsp;doddle.&lt;/p&gt;
&lt;p&gt;The only slightly icky thing about the script is the regular expression to parse a line from the apache log file (in &lt;a href="http://httpd.apache.org/docs/2.2/logs.html"&gt;Combined Log Format&lt;/a&gt;). I got this from &lt;a href="http://www.regexbuddy.com/"&gt;RegExp Buddy&lt;/a&gt; (pretty much the only reason I run Windows nowadays) but I am sure you can get similar expressions from other &lt;a href="http://www.google.co.uk/search?q=regular+expression+libraries"&gt;regular expression libraries&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#8217;m just chucking this out there incase someone else finds it&amp;nbsp;useful.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="c1"&gt;#Script to replay a file called apache.log against a server.&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;twill&lt;/span&gt;

&lt;span class="n"&gt;test_server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;my.test.server.com&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;reobj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;^(?P&amp;lt;client&amp;gt;\S+)\s+(?P&amp;lt;auth&amp;gt;\S+\s+\S+)\s+\[(?P&amp;lt;datetime&amp;gt;[^]]+)\]\s+&amp;quot;(?:GET|POST|HEAD) (?P&amp;lt;file&amp;gt;[^ ?&amp;quot;]+)\??(?P&amp;lt;parameters&amp;gt;[^ ?&amp;quot;]+)? HTTP/[0-9.]+&amp;quot;\s+(?P&amp;lt;status&amp;gt;[0-9]+)\s+(?P&amp;lt;size&amp;gt;[-0-9]+)\s+&amp;quot;(?P&amp;lt;referrer&amp;gt;[^&amp;quot;]*)&amp;quot;\s+&amp;quot;(?P&amp;lt;useragent&amp;gt;[^&amp;quot;]*)&amp;quot;$&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MULTILINE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;twill&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_browser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filter_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;


&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;apache.log&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reobj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;parameters&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;datetime&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;?&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test_server&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
        &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;#this comes from twill parsing the HTML and it being malformed.&lt;/span&gt;
        &lt;span class="c1"&gt;#I don&amp;#39;t really care about that, as long as I get the page.&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hope that helps&amp;nbsp;someone.&lt;/p&gt;</content><category term="misc"></category><category term="Dev"></category><category term="Python"></category></entry><entry><title>Python Style Plugins Made Easy</title><link href="https://www.executionunit.com/blog/2008/01/28/python-style-plugins-made-easy/" rel="alternate"></link><published>2008-01-28T00:00:00+00:00</published><updated>2008-01-28T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2008-01-28:/blog/2008/01/28/python-style-plugins-made-easy/</id><summary type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2008, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;Sometimes you need to write code that loads python at runtime. Plugin architectures are a good example of this …&lt;/p&gt;</summary><content type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2008, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;Sometimes you need to write code that loads python at runtime. Plugin architectures are a good example of this. Plugins allow extensibility but more importantly (for me at least) they enforce a strict &lt;span class="caps"&gt;API&lt;/span&gt;. Anyway, I&amp;#8217;ve written this code a few times so I thought I&amp;#8217;d modularize&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;The specific bit of code I am going to post is the python code to look for and load a series of python plugins. Plugins (in this case) are just classes that are subclasses of the Plugin base class. This plugin base class dictates the &lt;span class="caps"&gt;API&lt;/span&gt; that all plugins must implement. Here is an example plugin abstract base&amp;nbsp;class&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;called before the plugin is asked to do anything&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;teardown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;called to allow the plugin to free anything&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;domagic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;do whatever it is the plugin does&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here the is code to look for and return a list of classes that can be&amp;nbsp;instantiated:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;
&lt;span class="normal"&gt;50&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_subclasses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    Find all subclass of cls in py files located below path&lt;/span&gt;
&lt;span class="sd"&gt;    (does look in sub directories)&lt;/span&gt;

&lt;span class="sd"&gt;    @param path: the path to the top level folder to walk&lt;/span&gt;
&lt;span class="sd"&gt;    @type path: str&lt;/span&gt;
&lt;span class="sd"&gt;    @param cls: the base class that all subclasses should inherit from&lt;/span&gt;
&lt;span class="sd"&gt;    @type cls: class&lt;/span&gt;
&lt;span class="sd"&gt;    @rtype: list&lt;/span&gt;
&lt;span class="sd"&gt;    @return: a list if classes that are subclasses of cls&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;subclasses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;look_for_subclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulename&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;searching &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulename&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;__import__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;#walk the dictionaries to get to the last one&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;modulename&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
            &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__dict__&lt;/span&gt;

        &lt;span class="c1"&gt;#look through this dictionary for things&lt;/span&gt;
        &lt;span class="c1"&gt;#that are subclass of Job&lt;/span&gt;
        &lt;span class="c1"&gt;#but are not Job itself&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;issubclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Found subclass: &amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;subclasses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;#this happens when a non-type is passed in to issubclass. We&lt;/span&gt;
                &lt;span class="c1"&gt;#don&amp;#39;t care as it can&amp;#39;t be a subclass of Job if it isn&amp;#39;t a&lt;/span&gt;
                &lt;span class="c1"&gt;#type&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;


    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;walk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;__&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;modulename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rsplit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;look_for_subclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modulename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;subclasses&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;and here is how you would call&amp;nbsp;it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_subclasses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;./pluginsfolder/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;#lets create an instance of the first class&lt;/span&gt;
&lt;span class="n"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;So there you go, create folder of python files with classes in them that subclass the Plugin class and you are&amp;nbsp;away.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The original article had a number of insightful comments, I&amp;#8217;ve included all their corrections but unfortunately not the original comments. Thanks to all those who contributed to make this a better article&lt;/em&gt;.&lt;/p&gt;</content><category term="misc"></category><category term="PostgreSQL"></category><category term="Python"></category></entry><entry><title>PostgreSQL, SQLAlchemy, Dropping All Tables and Sequences</title><link href="https://www.executionunit.com/blog/2007/11/23/postgresql-sqlalchemy-dropping-all-tables-and-sequences/" rel="alternate"></link><published>2007-11-23T00:00:00+00:00</published><updated>2007-11-23T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2007-11-23:/blog/2007/11/23/postgresql-sqlalchemy-dropping-all-tables-and-sequences/</id><summary type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2007, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p class="lead text-info"&gt;
There were a number of insightful comments in the original article that I have not copied across. They ended …&lt;/p&gt;</summary><content type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2007, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p class="lead text-info"&gt;
There were a number of insightful comments in the original article that I have not copied across. They ended with &lt;em&gt;The Ultimate DropEverything&lt;/em&gt; script from Mike Bayer that is now in the &lt;a href="http://www.sqlalchemy.org/trac/wiki/UsageRecipes/DropEverything"&gt;SqlAlchemy&amp;nbsp;wiki&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been working in deployment scripts for my current project and sometimes I need to drop all the tables and sequences from the database so I can create everything from scratch. I had been doing&amp;nbsp;a&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SCHEMA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SCHEMA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AUTHORIZATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SCHEMA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This was great but a little destructive and over the top. It removes stored procedures and triggers as well which isn&amp;#8217;t what I want. So I looked at the SQLAlchemy docs and there is a metadata command&amp;nbsp;drop_all()&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drop_tables&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop_tables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately this doesn&amp;#8217;t &lt;span class="caps"&gt;CASCADE&lt;/span&gt; so this isn&amp;#8217;t going to work in cases where tables have foreign keys (which is most of the time). It also leaves sequences in&amp;nbsp;place.&lt;/p&gt;
&lt;p&gt;So I looked at dropping each table in turn with a cascade. So how do you get a list of tables and sequences in the database? I could hard code the names of the tables and sequences but that seemed a little&amp;nbsp;poor.&lt;/p&gt;
&lt;p&gt;It turns out that PostgreSQL has a set of views that expose the inner workings of your database and a few queries can give you all the information you&amp;nbsp;need.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_table_list_from_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="sd"&gt;    return a list of table names from the current&lt;/span&gt;
&lt;span class="sd"&gt;    databases public schema&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;select table_name from information_schema.tables&amp;quot;&lt;/span&gt;\
        &lt;span class="s2"&gt;&amp;quot;where table_schema=&amp;#39;public&amp;#39;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_seq_list_from_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;return a list of the sequence names from the current&lt;/span&gt;
&lt;span class="sd"&gt;       databases public schema&lt;/span&gt;
&lt;span class="sd"&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;select sequence_name from information_schema.sequences&amp;quot;&lt;/span&gt;\
        &lt;span class="s2"&gt;&amp;quot;where sequence_schema=&amp;#39;public&amp;#39;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drop_all_tables_and_sequences&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;get_table_list_from_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DROP TABLE &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; CASCADE&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;SQLError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;get_seq_list_from_db&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DROP SEQUENCE &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; CASCADE&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;SQLError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The information_schema is full of interesting information. It&amp;#8217;s actually a &amp;#8216;view&amp;#8217; of lower level database tables. You can find all sorts of performance and configuration information in there. Quite handy  &lt;a href="http://www.postgresql.org/docs/8.2/interactive/information-schema.html"&gt;Here are some docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Good&amp;nbsp;luck.&lt;/p&gt;</content><category term="misc"></category><category term="PostgreSQL"></category><category term="Python"></category></entry><entry><title>FreeBSD Centralised Logging</title><link href="https://www.executionunit.com/blog/2007/01/28/freebsd-centralised-logging/" rel="alternate"></link><published>2007-01-28T00:00:00+00:00</published><updated>2007-01-28T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2007-01-28:/blog/2007/01/28/freebsd-centralised-logging/</id><summary type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2007, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;I wanted to log everything from my servers and router to a singer server to make it easier to …&lt;/p&gt;</summary><content type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2007, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;I wanted to log everything from my servers and router to a singer server to make it easier to keep up. Here are the steps I went&amp;nbsp;through.&lt;/p&gt;
&lt;h3 id="edit-syslogconf"&gt;Edit&amp;nbsp;syslog.conf&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m using bonobo.local as my syslog server. Start by editting /etc/syslog.conf. At the first line that isn&amp;#8217;t a comment (first line that doesn&amp;#8217;t start with a #) insert +&lt;servername&gt;&lt;return&gt; so for me I added &lt;code&gt;+bonobo.local&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;#$FreeBSD: src/etc/syslog.conf&lt;/span&gt;
+bonobo.local
*.err&lt;span class="p"&gt;;&lt;/span&gt;kern.debug&lt;span class="p"&gt;;&lt;/span&gt;auth.notice&lt;span class="p"&gt;;&lt;/span&gt;mail.crit&lt;span class="w"&gt;          &lt;/span&gt;/dev/console
*.notice&lt;span class="p"&gt;;&lt;/span&gt;authpriv.none&lt;span class="p"&gt;;&lt;/span&gt;kern.debug&lt;span class="p"&gt;;&lt;/span&gt;lpr.info&lt;span class="p"&gt;;&lt;/span&gt;mail.crit&lt;span class="p"&gt;;&lt;/span&gt;news.err&lt;span class="w"&gt;   &lt;/span&gt;/var/log/messages
security.*&lt;span class="w"&gt;                                      &lt;/span&gt;/var/log/security
auth.info&lt;span class="p"&gt;;&lt;/span&gt;authpriv.info&lt;span class="w"&gt;                         &lt;/span&gt;/var/log/auth.log
mail.info&lt;span class="w"&gt;                                       &lt;/span&gt;/var/log/maillog
...&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;snip&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;...
!ppp
*.*&lt;span class="w"&gt;                                             &lt;/span&gt;/var/log/ppp.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;then at the bottom of the file add the name of the client machine, for me this was&amp;nbsp;hypnotoad.local:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;!*&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;hypnotoad&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;
&lt;span class="o"&gt;*.*&lt;/span&gt;&lt;span class="w"&gt;                                             &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;hypnotoad&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;there are some funny characters in here that complicate&amp;nbsp;matters.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;!*&lt;/code&gt; resets the target. A few lines up the default syslog.conf has the line !ppp this tells the syslog daemon that all the following rules only apply to ppp messages. Putting &lt;code&gt;!*&lt;/code&gt; tells the syslog daemon that all the following rules match all&amp;nbsp;messages.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;+hypnotoad.local&lt;/code&gt; tells the syslog daemon that the following rules relate to the machine&amp;nbsp;mentioned.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;*.* &amp;lt;tab&amp;gt; &amp;lt;filename&amp;gt;&lt;/code&gt; tells the syslog daemon to log anything from the afore mentioned machine to the logfile&amp;nbsp;&amp;#8216;filename&amp;#8217;&lt;/p&gt;
&lt;p&gt;For security reasons the syslog daemon won&amp;#8217;t start appending (logging) to a file that &lt;span class="caps"&gt;DOESN&lt;/span&gt;&amp;#8217;T exist when it starts so you must create the files before restarting the syslog&amp;nbsp;daemon.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;/etc/log/hypnotoad.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h3 id="edit-etcrcconf"&gt;Edit&amp;nbsp;/etc/rc.conf&lt;/h3&gt;
&lt;p&gt;edit /etc/rc.conf and append the&amp;nbsp;line&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;syslogd_flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This looks odd. Why deliberately pass in empty flags? Because /etc/defaults/rc.conf&amp;nbsp;has&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;syslogd_flags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-s&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; option stops syslog from listening for external logging messages. This caught me out first time I tried to do&amp;nbsp;this&lt;/p&gt;
&lt;p&gt;Now restart&amp;nbsp;syslog&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;/etc/rc.d/syslogd&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;you should see a few lines about syslog stopping and starting&amp;nbsp;again.&lt;/p&gt;
&lt;h3 id="setting-up-the-clients"&gt;Setting up the&amp;nbsp;clients&lt;/h3&gt;
&lt;p&gt;On each client make a backup of the original /etc/syslog.conf file and edit the original to include a single&amp;nbsp;line&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;#$FreeBSD: src/etc/syslog.conf&lt;/span&gt;
*.*&lt;span class="w"&gt;     &lt;/span&gt;@bonobo.local
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;replacing bonobo.local with the name / ip address of your logging server. restart your syslog&amp;nbsp;server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;/etc/rc.d/syslogd&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;try out the logging&amp;nbsp;with&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;logger&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;hello from my syslog client&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;the message &amp;#8220;hello from my syslog client&amp;#8221; should appear in the syslog servers log file for the machine you are&amp;nbsp;changing.&lt;/p&gt;</content><category term="freebsd"></category><category term="FreeBSD"></category></entry><entry><title>Subversion and Apple Filemerge Integrtaion</title><link href="https://www.executionunit.com/blog/2007/01/20/subversion-and-apple-filemerge-integrtaion/" rel="alternate"></link><published>2007-01-20T00:00:00+00:00</published><updated>2007-01-20T00:00:00+00:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2007-01-20:/blog/2007/01/20/subversion-and-apple-filemerge-integrtaion/</id><summary type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2007, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;If you want visual diff&amp;#8217;s while developing on &lt;span class="caps"&gt;OSX&lt;/span&gt; using subversion then &lt;a href="http://ssel.vub.ac.be/ssel/internal:fmdiff"&gt;this page&lt;/a&gt; has a good description …&lt;/p&gt;</summary><content type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in January 2007, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;If you want visual diff&amp;#8217;s while developing on &lt;span class="caps"&gt;OSX&lt;/span&gt; using subversion then &lt;a href="http://ssel.vub.ac.be/ssel/internal:fmdiff"&gt;this page&lt;/a&gt; has a good description of how to set it up and some scripts to wrap Apple&amp;#8217;s FileMerge application to give to nice visual&amp;nbsp;merges/diffs.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image of Filemerge" src="https://www.executionunit.com/static/media/uploads/blog/fetch-1.gif"&gt;&lt;/p&gt;
&lt;p&gt;The author doesn&amp;#8217;t mention it but rather then pass the path to the scripts to svn via the &amp;#8212;diff-cmd option to can edit ~/.subversion/config and enter the full path to the scripts in the diff-cmd variable. Note it needs to be the full path as shell variables wont be expanded (so ~/bin/fmdiff will fail with error&amp;nbsp;255)&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;PS&lt;/span&gt;: I have nothing against the text based diffing tools so please don&amp;#8217;t flame me. After all I&amp;#8217;m a Mac user so what do I know of such&amp;nbsp;magic.&lt;/p&gt;</content><category term="misc"></category><category term="C++"></category><category term="GameDev"></category></entry><entry><title>FreeBSD: Slurm… the IPTraf alike for FreeBSD</title><link href="https://www.executionunit.com/blog/2006/10/28/freebsd-slurm-the-iptraf-alike-for-freebsd/" rel="alternate"></link><published>2006-10-28T00:00:00+01:00</published><updated>2006-10-28T00:00:00+01:00</updated><author><name>dazza</name></author><id>tag:www.executionunit.com,2006-10-28:/blog/2006/10/28/freebsd-slurm-the-iptraf-alike-for-freebsd/</id><summary type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in December 2006, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;For many moons I have wanted an application like &lt;a href="http://iptraf.seul.org/"&gt;IPTraf&lt;/a&gt; for FreeBSD. Well through lack of trying and a …&lt;/p&gt;</summary><content type="html">&lt;p class="lead text-info"&gt;&lt;span class="label label-info"&gt;&lt;span class="caps"&gt;NOTE&lt;/span&gt;:&lt;/span&gt; This is an old article I wrote in December 2006, it&amp;#8217;s still relevant today. It was originally posted on luckydonkey.com which I am in the process of&amp;nbsp;retiring.&lt;/p&gt;

&lt;p&gt;For many moons I have wanted an application like &lt;a href="http://iptraf.seul.org/"&gt;IPTraf&lt;/a&gt; for FreeBSD. Well through lack of trying and a certain amount of stupidity I couldn&amp;#8217;t find one. All good things come to those who wait&amp;#8230; to stumble across things late at night. I was watching an rsync backup happen across the network while reading &lt;a href="http://forums.freebsd.org"&gt;FreeBSD Forums&lt;/a&gt; and I stumbled across &lt;a href="https://en.wikipedia.org/wiki/Simple_Linux_Utility_for_Resource_Management"&gt;Slurm&lt;/a&gt;. It&amp;#8217;s not quite the same as IPTraf but its close enough&amp;#8230; in fact in some ways it&amp;#8217;s easier to&amp;nbsp;use.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s missing the per port break down and the connection list that IPTraf has. But to be honest all I really want is ascii graphs  . It is easier to use in my opinion because it just does what I want.. draws a cool graph and lets me know something is happening when I worried that I fucked something up again&amp;nbsp;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Picture of Slurm in Action" src="https://www.executionunit.com/static/media/uploads/blog/slurm.jpg" title="Picture of Slurm in Action"&gt;&lt;/p&gt;
&lt;p&gt;And you though this was going to be a late night rant about a &lt;a href="http://en.wikipedia.org/wiki/Slurm"&gt;fictional soft&amp;nbsp;drink&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The original article had a number of insightful comments, I&amp;#8217;ve included all their corrections but unfortunately not the original comments. Thanks to all those who contributed to make this a better article&lt;/em&gt;.&lt;/p&gt;</content><category term="freebsd"></category><category term="FreeBSD"></category></entry></feed>