<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0cMRX85fCp7ImA9WhVUE08.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723</id><updated>2012-05-18T02:11:24.124-05:00</updated><category term="linux" /><category term="web workers" /><category term="snowballz" /><category term="packaging" /><category term="py2exe" /><category term="javascript" /><category term="html5" /><category term="gameplay" /><category term="implementation details" /><category term="gondola" /><category term="pyweek" /><category term="C++" /><category term="Number Drill" /><category term="AI" /><category term="python" /><category term="Voronoi" /><category term="markdown" /><category term="user interface" /><category term="WebGL" /><category term="optimization" /><category term="flocking" /><category term="windows" /><category term="pygame" /><category term="canvas" /><category term="OpenGL" /><category term="PyOpenGL" /><title>Arctic Paint weblog</title><subtitle type="html">The official weblog of Joseph Marshall</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://weblog.arcticpaint.com/" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ArcticPaint" /><feedburner:info uri="arcticpaint" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CEAHR389eSp7ImA9WhVVFUQ.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-6051821964483200245</id><published>2012-05-09T14:45:00.000-05:00</published><updated>2012-05-09T14:45:36.161-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-09T14:45:36.161-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Voronoi" /><category scheme="http://www.blogger.com/atom/ns#" term="C++" /><title>Voronoi diagrams in C++</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://bitbucket.org/jlm/voronoi-c/" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-CcMlQLhFPWk/T6mVwqm4L_I/AAAAAAAAAGU/K2Z_KStM1kw/s1600/voronoi.png" /&gt;&lt;/a&gt;&lt;/div&gt;
Why? I can't tell you... or wont? Anyways, I was looking for an implementation that was C++ friendly, didn't leak memory and let me easily build triangles from the resulting computation (for use in OpenGL).&lt;br /&gt;
&lt;br /&gt;
I found an implementation that did none of those. But it was fast, and close-ish to C++ friendly... ish.&lt;br /&gt;
&lt;br /&gt;
It was open source so I encapsilated it all, converted all those pesky malloc and frees to... not &amp;nbsp;malloc and frees (which indirectly fixed the memory issues) and changed it to output the result to something a little more useful.&lt;br /&gt;
&lt;br /&gt;
And now I'm sharing the result with you.&amp;nbsp;&lt;a href="https://bitbucket.org/jlm/voronoi-c/"&gt;https://bitbucket.org/jlm/voronoi-c/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-6051821964483200245?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/tr_FJh-L3mU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/6051821964483200245/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2012/05/voronoi-diagrams-in-c.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/6051821964483200245?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/6051821964483200245?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/tr_FJh-L3mU/voronoi-diagrams-in-c.html" title="Voronoi diagrams in C++" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-CcMlQLhFPWk/T6mVwqm4L_I/AAAAAAAAAGU/K2Z_KStM1kw/s72-c/voronoi.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2012/05/voronoi-diagrams-in-c.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ACSHs4cCp7ImA9WhVVE08.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-1271351607155545166</id><published>2012-05-06T12:27:00.000-05:00</published><updated>2012-05-06T12:36:09.538-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-06T12:36:09.538-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WebGL" /><category scheme="http://www.blogger.com/atom/ns#" term="optimization" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenGL" /><category scheme="http://www.blogger.com/atom/ns#" term="web workers" /><title>Why minecraft's terrain loading is slow</title><content type="html">&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;a href="https://bitbucket.org/jlm/fuzzycraft"&gt;&lt;img border="0" height="180" src="http://2.bp.blogspot.com/-BZYBiSa6SeE/T6aczyC-O-I/AAAAAAAAAF4/hjYTmlQuDwg/s320/fuzzycraft.png" width="320" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Fuzzycraft&amp;nbsp;- not minecraft!&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Oh I don't know, it's in Java? (Sorry, just getting the flame-bait out of the way.)&lt;br /&gt;
&lt;br /&gt;
It's an interesting problem; sure it's just a bunch of cubes - but who wants to stop at a few thousand of them? You want a massive world where you can potentially see tens of thousands of theses blocks at a time. And due to its nature you're left without many of the techniques often used to optimize terrain rendering.&lt;br /&gt;
&lt;br /&gt;
Sounds like a good&amp;nbsp;opportunity to get a little more comfortable with OpengGL.&amp;nbsp;Enter &lt;a href="https://bitbucket.org/jlm/fuzzycraft-webgl"&gt;fuzzycraft-webgl&lt;/a&gt;; poorly textured terrain in all it's blocky glory! This ended up being horribly slow. More on that in a bit.&lt;br /&gt;
&lt;br /&gt;
Trying out minecraft; the terrain seems to load very slowly. With my fairly high-end GPU I'm pretty sure OpenGL isn't the bottleneck here. Generating what blocks go where isn't slow either. (Test it by toggling the graphics options between fancy and fast; you can still see the chunks appearing one by one, oh so slowly) The only thing left is the process of building the geometry to send to the GPU.&lt;br /&gt;
&lt;br /&gt;
I wanted to see if I could do better. Coffeescript was something I was wanting to try out and I always like to see how far WebGL can go. Turns out, getting good FPS was next to impossible with larger worlds. Generating the blocks of geometry to send to the GPU wasn't too bad; although to be fair, I had 8 cores chewing through it via web-workers.&lt;br /&gt;
&lt;br /&gt;
Really, using OpenGL just works best in C. I was confident that it was possible to get it fast; both generating and rendering it. So I &lt;a href="https://bitbucket.org/jlm/fuzzycraft"&gt;re-wrote it all in C++&lt;/a&gt;. There's really not a whole lot to say other than yes, it is very possible. There are still a few&amp;nbsp;optimization&amp;nbsp;I could do to make it run even faster. I may do them someday; but for now I've satisfied my curiosity.&lt;br /&gt;
&lt;br /&gt;
So why does minecraft take so long to get those chunks of vertices to the GPU? I don't really know. Part of me wants to decompile minecraft's bytecode and find out. But I work with way to much Java as it is at my day job; and honestly, it's not a language I adore.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-1271351607155545166?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/6vu_spUYqKc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/1271351607155545166/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2012/05/why-minecrafts-terrain-loading-is-slow.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1271351607155545166?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1271351607155545166?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/6vu_spUYqKc/why-minecrafts-terrain-loading-is-slow.html" title="Why minecraft's terrain loading is slow" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-BZYBiSa6SeE/T6aczyC-O-I/AAAAAAAAAF4/hjYTmlQuDwg/s72-c/fuzzycraft.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2012/05/why-minecrafts-terrain-loading-is-slow.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcHRHs9cSp7ImA9WhdRFUo.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-6198551356118652497</id><published>2011-08-05T15:27:00.000-05:00</published><updated>2011-08-05T15:27:15.569-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-05T15:27:15.569-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="AI" /><category scheme="http://www.blogger.com/atom/ns#" term="html5" /><category scheme="http://www.blogger.com/atom/ns#" term="canvas" /><category scheme="http://www.blogger.com/atom/ns#" term="flocking" /><title>Flocking in javascript</title><content type="html">&lt;a href="http://files.arcticpaint.com/flock/" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-03xwUWge-2E/TjxRLhv2u2I/AAAAAAAAAEg/QFT3pppM-ls/s1600/flockjs.png" /&gt;&lt;/a&gt;Flocking is one of those things I've been meaning to play with for a while. So here is my crude result; &lt;a href="http://files.arcticpaint.com/flock/"&gt;flocking in javascript&lt;/a&gt;. I'm not quite sure what &lt;i&gt;type&lt;/i&gt; of flock it's simulating...&amp;nbsp;definitely&amp;nbsp;not birds though. I'm calling them noids.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-6198551356118652497?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/0WM_D3CAwRU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/6198551356118652497/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2011/08/flocking-in-javascript.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/6198551356118652497?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/6198551356118652497?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/0WM_D3CAwRU/flocking-in-javascript.html" title="Flocking in javascript" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-03xwUWge-2E/TjxRLhv2u2I/AAAAAAAAAEg/QFT3pppM-ls/s72-c/flockjs.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2011/08/flocking-in-javascript.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEEDQn47eip7ImA9WhdSGEU.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-273725502809213511</id><published>2011-07-28T14:50:00.001-05:00</published><updated>2011-07-28T14:51:13.002-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-28T14:51:13.002-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="markdown" /><title>Python markdown</title><content type="html">&lt;pre&gt;$ easy_install mark3
$ python -m mark3 &amp;lt; myfile.text&lt;/pre&gt;Or used as a python module:    &lt;br /&gt;
&lt;pre class="prettyprint"&gt;from mark3.markdown import markdown
html_output = markdown(raw_text)&lt;/pre&gt;I wanted a markdown to html converter for python3 that was lightweight and fast. So I created mark3.&lt;br /&gt;
Much to my&amp;nbsp;surprise I was able to get mark3 quite a lot faster than existing libraries (~7x faster).&lt;br /&gt;
&lt;pre&gt;$ hg clone&amp;nbsp;https://bitbucket.org/jlm/mark3
$ cd mark3
$ python tests/speed_test.py&lt;/pre&gt;See the &lt;a href="https://bitbucket.org/jlm/mark3/src/80298200558b/README"&gt;README&lt;/a&gt; for details on how mark3 differs from the official markdown implementation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-273725502809213511?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/uXt3ByZnWp0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/273725502809213511/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2011/07/python-markdown.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/273725502809213511?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/273725502809213511?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/uXt3ByZnWp0/python-markdown.html" title="Python markdown" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2011/07/python-markdown.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUNQX0_fyp7ImA9WhdRFUo.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-1204520905190735827</id><published>2011-07-09T13:17:00.001-05:00</published><updated>2011-08-05T15:31:30.347-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-05T15:31:30.347-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="html5" /><category scheme="http://www.blogger.com/atom/ns#" term="optimization" /><category scheme="http://www.blogger.com/atom/ns#" term="canvas" /><title>Things I learned about html5 canvas</title><content type="html">&lt;a href="http://games.arcticpaint.com/platformer/play.html" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="266" src="http://4.bp.blogspot.com/-nvues39-15w/ThZ6jREyaZI/AAAAAAAAAEI/GFnRMDgkuQ8/s400/platformer.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;
WebGL is awesome and all, but it's far less portable. For example, my &lt;a href="http://code.google.com/p/chromium/issues/detail?id=71996&amp;amp;q=Blacklist%20GPU%20acceleration&amp;amp;colspec=ID%20Stars%20Pri%20Area%20Feature%20Type%20Status%20Summary%20Modified%20Owner%20Mstone%20OS"&gt;AMD card has been blacklisted&lt;/a&gt; on linux. So I figured I'd revisit trying to make a real-time game with 2D canvas.&lt;br /&gt;
Check out the &lt;a href="http://games.arcticpaint.com/platformer/play.html"&gt;game so far&lt;/a&gt;.&lt;br /&gt;
&lt;h4&gt;Off-Screen Rendering&lt;/h4&gt;&lt;a href="http://weblog.arcticpaint.com/2011/07/canvas-off-screen-rendering.html"&gt;Off-screen rendering&lt;/a&gt; is both cheep and easy to use. Here I'm using it to render &lt;a href="http://games.arcticpaint.com/platformer/lib/tilemap.js"&gt;map tiles to a single image&lt;/a&gt;. Since the tiles are (mostly) static I don't need to be redrawing them individually each frame.&lt;br /&gt;
&lt;h4&gt;setInterval is not guaranteed to call at an exact interval&lt;/h4&gt;So I already knew this, but I forget how much accurate timing matters for real-time games. To the point, calculate time-past yourself with the &lt;a href="http://www.w3schools.com/jsref/jsref_gettime.asp"&gt;getTime&lt;/a&gt; function:&lt;br /&gt;
&lt;pre class="prettyprint lang-js"&gt;var dt = new Date().getTime() - last_time;&lt;/pre&gt;Still use setInterval for scheduling logic and render functions, just don't expect the timeout values to be consistent with actual times.&lt;br /&gt;
&lt;h4&gt;Keep an eye on object allocation/deallocation&lt;/h4&gt;You don't normally have to think about allocating memory in javascript like you would in C. The problem comes when you're creating a real-time game and you notice it periodically skipping a beat, resulting in jerky rendering. This is caused by javascript's garbage collector, basically, blocking your program as it cleans up unused memory.&lt;br /&gt;
The way to avoid this problem is to limit the number objects you create and then discard.&amp;nbsp;Or an easy solution; just&amp;nbsp;use Chrome. It's significantly better about it.&lt;br /&gt;
&lt;h4&gt;It's better on Google Chrome&lt;/h4&gt;Simply put, Google Chrome is better for canvas based games. Dramatically better in some situations (or rather, Firefox is dramatically worse in some situations).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-1204520905190735827?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/D9lWNtl9Mns" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/1204520905190735827/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2011/07/things-i-learned-about-html5-canvas.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1204520905190735827?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1204520905190735827?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/D9lWNtl9Mns/things-i-learned-about-html5-canvas.html" title="Things I learned about html5 canvas" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-nvues39-15w/ThZ6jREyaZI/AAAAAAAAAEI/GFnRMDgkuQ8/s72-c/platformer.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2011/07/things-i-learned-about-html5-canvas.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQGRXo-eyp7ImA9WhdRFUo.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-3784121218962381829</id><published>2011-07-07T10:01:00.017-05:00</published><updated>2011-08-05T15:32:04.453-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-05T15:32:04.453-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="html5" /><category scheme="http://www.blogger.com/atom/ns#" term="optimization" /><category scheme="http://www.blogger.com/atom/ns#" term="canvas" /><category scheme="http://www.blogger.com/atom/ns#" term="web workers" /><title>Canvas off-screen rendering</title><content type="html">Rendering to an off-screen buffer can be a great way to cache expensive drawing operations or preform post processing effects. html5's canvas element lets us do it easily.&lt;br /&gt;
&lt;pre class="prettyprint lang-js"&gt;var buffer = document.createElement('canvas');
var buffer_ctx = buffer.getContext('2d');
// ... draw to buffer_ctx ...&lt;/pre&gt;Then simply use our new buffer &lt;a href="https://developer.mozilla.org/en/Canvas_tutorial/Using_images#section_6"&gt;as an image&lt;/a&gt;:&lt;br /&gt;
&lt;pre class="prettyprint lang-js"&gt;main_ctx.drawImage(buffer, 0, 0);&lt;/pre&gt;For example, I can use an off-screen buffer to apply an &lt;a href="http://files.arcticpaint.com/bloom/"&gt;expensive bloom effect&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://files.arcticpaint.com/bloom/" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5626655275045750258" src="http://3.bp.blogspot.com/-I75VcZ3C2xo/ThXlKU6uBfI/AAAAAAAAAC0/GiNHkpFSjY4/s400/bloom.png" style="cursor: hand; cursor: pointer; display: block; height: 380px; margin: 0px auto 10px; text-align: center; width: 400px;" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-3784121218962381829?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/XRpjZI3FRpI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/3784121218962381829/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2011/07/canvas-off-screen-rendering.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/3784121218962381829?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/3784121218962381829?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/XRpjZI3FRpI/canvas-off-screen-rendering.html" title="Canvas off-screen rendering" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-I75VcZ3C2xo/ThXlKU6uBfI/AAAAAAAAAC0/GiNHkpFSjY4/s72-c/bloom.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2011/07/canvas-off-screen-rendering.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEQCQ388cSp7ImA9WhdRFUo.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-8456723284659720870</id><published>2011-06-02T08:13:00.010-05:00</published><updated>2011-08-05T15:32:42.179-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-05T15:32:42.179-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="WebGL" /><category scheme="http://www.blogger.com/atom/ns#" term="html5" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenGL" /><category scheme="http://www.blogger.com/atom/ns#" term="canvas" /><title>Playing with WebGL</title><content type="html">&lt;div style="text-align: left;"&gt;OpenGL is one of those things I like to play with from time to time. So naturally I wanted to check out WebGL now that Chrome and Firefox support it.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="text-align: left;"&gt;It's fun being able to use javascript and web technology in conjunction with OpenGL. Building GUIs using raw SDL/OpenGL was always rather a pain for me. I don't even like how standard toolkits work (GTK+, Qt etc). So being able to use HTML widgets and jQuery on top of my 3D scene is really awesome.&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;a href="http://arcticpaint.com/planes/"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5613616621032325874" src="http://1.bp.blogspot.com/-ZjBe3cvpfBI/TeeSkxncQvI/AAAAAAAAACQ/QIFiRnTh-6A/s400/Screenshot.png" style="cursor: hand; cursor: pointer; float: left; height: 219px; margin: 0 10px 10px 0; width: 400px;" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div&gt;Unfortunately it's noticeably slower than an equivalent program running natively. When profiling, the GL calls seemed to be the bottleneck. A bit less so on Windows than Linux, although that may have been due to better driver support on the former.&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;So like usual, optimizing comes down to reducing the number of GL calls you make per frame.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The javascript logic and matrix transformations ran very fast. This was the case for both Firefox and Chrome and was a very pleasant surprise.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;You can try out what I made at &lt;a href="http://arcticpaint.com/planes/"&gt;http://arcticpaint.com/planes/&lt;/a&gt;, play with the source or what ever. It's all under public domain (with the exception of the glmatrix library which has a BSD license).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I had also started toying with the idea of a turn-based game &lt;a href="http://arcticpaint.com/islands/"&gt;http://arcticpaint.com/islands/&lt;/a&gt; (very, very far from completion)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;If you want to check out more webgl stuff &lt;a href="http://learningwebgl.com/"&gt;http://learningwebgl.com&lt;/a&gt; is a great resource. They also have some decent tutorials that are easy to follow along if you're new to OpenGL.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-8456723284659720870?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/FoPtxJLuQ3w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/8456723284659720870/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2011/06/playing-with-webgl.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8456723284659720870?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8456723284659720870?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/FoPtxJLuQ3w/playing-with-webgl.html" title="Playing with WebGL" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-ZjBe3cvpfBI/TeeSkxncQvI/AAAAAAAAACQ/QIFiRnTh-6A/s72-c/Screenshot.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2011/06/playing-with-webgl.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8HQHg6fip7ImA9Wx5bGEQ.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-1756489719589620210</id><published>2010-11-04T13:16:00.002-05:00</published><updated>2010-11-04T13:20:31.616-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-04T13:20:31.616-05:00</app:edited><title>A casual game service</title><content type="html">&lt;div&gt;I recently started a new project called &lt;a href="http://gervice.appspot.com/"&gt;Gervice&lt;/a&gt;. My goal is to allow you to easily plug your standard "game" features into a web based games. With a single function call you can load and save state, log scores and move count and integrate with an online community.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-1756489719589620210?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/sak7Yu4oPtA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/1756489719589620210/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2010/11/casual-game-service.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1756489719589620210?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1756489719589620210?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/sak7Yu4oPtA/casual-game-service.html" title="A casual game service" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2010/11/casual-game-service.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DU4DRHoycCp7ImA9WxJbFk4.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-651357855795606450</id><published>2009-07-26T14:13:00.005-05:00</published><updated>2009-07-26T14:52:55.498-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-26T14:52:55.498-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Number Drill" /><category scheme="http://www.blogger.com/atom/ns#" term="packaging" /><category scheme="http://www.blogger.com/atom/ns#" term="linux" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><title>Pure Python to deb and rpm</title><content type="html">&lt;p&gt;I recently started supporting Number Drill, my &lt;a href="http://numberdrill.com/"&gt;math drill&lt;/a&gt; software, for Linux a few days ago. Number Drill is a pure python program with the external dependencies of pygame, rabbyt, PyOpenGL and a few others. All of which were in the Debian and Fedora repositories.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I originally tried using cx_Freeze to make a binary to distribute. But I kept on running into major problems with this method. And as it ended up I would have to include a plethora of .so files (such as all of pygame and everything that it depends on, libssl and everything it depends on etc) just to avoid version conflicts that resulted in segfaults. Not to mention the resulting package ending up far larger than it should be.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;That was about the time Matthew suggested just distributing the pyc files (gasp! I know, it's not open source) and letting package systems like deb and rpm handle dependencies. This method has ended up working almost perfectly. Both Ubuntu 9.04 and Fedora 11 have all the dependencies I require available. The resulting packages are very small (no binaries included, just the python byte code).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The only disadvantage is that it requires the latest versions of Ubuntu or Fedora (as of today) as they are the only releases that have new enough versions of my dependencies.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;We wrote a bash script that automatically packages up a pure python program into both a deb and rpm. If you are interested in here it is: &lt;a href="http://arcticpaint.com/static/blog/python_to_deb_rpm.sh"&gt;http://arcticpaint.com/static/blog/python_to_deb_rpm.sh&lt;/a&gt;&lt;/p&gt;&lt;p&gt;I believe that this method of packaging is even more effective in the open source world. It essentially just makes getting your program to run from source as easy as possible.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-651357855795606450?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/4TTCuHF7b5s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/651357855795606450/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2009/07/pure-python-to-deb-and-rpm.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/651357855795606450?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/651357855795606450?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/4TTCuHF7b5s/pure-python-to-deb-and-rpm.html" title="Pure Python to deb and rpm" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2009/07/pure-python-to-deb-and-rpm.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMFSHw-eCp7ImA9WxJRFEU.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-759806406637397967</id><published>2009-05-16T09:54:00.004-05:00</published><updated>2009-05-16T10:06:59.250-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-16T10:06:59.250-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PyOpenGL" /><category scheme="http://www.blogger.com/atom/ns#" term="windows" /><category scheme="http://www.blogger.com/atom/ns#" term="py2exe" /><title>PyOpenGL 3.0 with py2exe</title><content type="html">&lt;p&gt;One of the major hindrances  to using PyOpenGL before 3.0 was released (not python 3.0) was that packaging it with py2exe was next to impossible. Thankfully with the release of PyOpenGL 3.0 it is easy. Just include these two imports in one of your project files:&lt;/p&gt;&lt;pre class="prettyprint lang-py"&gt;from ctypes import util&lt;br /&gt;try:&lt;br /&gt;    from OpenGL.platform import win32&lt;br /&gt;except AttributeError:&lt;br /&gt;    pass&lt;/pre&gt;&lt;p&gt;That will tell py2exe which part of PyOpenGL to include. Otherwise you have to copy them over manually. Be sure to have the try and except around all win32 imports so your program remains cross platform.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-759806406637397967?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/VZEDXGUSzUg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/759806406637397967/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2009/05/pyopengl-30-with-py2exe.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/759806406637397967?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/759806406637397967?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/VZEDXGUSzUg/pyopengl-30-with-py2exe.html" title="PyOpenGL 3.0 with py2exe" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2009/05/pyopengl-30-with-py2exe.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQHRHk7fSp7ImA9WhZUEE4.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-1668491597028552066</id><published>2009-05-07T13:23:00.010-05:00</published><updated>2011-06-02T10:58:55.705-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-02T10:58:55.705-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="pygame" /><category scheme="http://www.blogger.com/atom/ns#" term="python" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenGL" /><title>Better pygame and rabbyt texture loading</title><content type="html">&lt;p&gt;&lt;span class="Apple-style-span" style=" ;font-family:'Times New Roman';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;div style="margin-top: 8px; margin-right: 8px; margin-bottom: 8px; margin-left: 8px; font: normal normal normal small/normal arial; "&gt;&lt;span class="Apple-style-span" style="  ;font-family:Georgia;font-size:16px;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;span&gt;&lt;span&gt;For one of my current projects I'm using rabbyt in conjunction with pygame. With the default texture loading, if your image dimensions are not powers of two your resulting sprite will be blurry. Pyglet fixes this by creating a new texture with correct dimensions, blitting your image onto the texture and then setting the texture coordinates. That way OpenGL doesn't do its blurry scaling job on your image.&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Well, pygame's texture loading doesn't do that. So you either go to great pains to make sure all your textures are powers of two (which can be annoying when you don't want your sprites to be those sizes) or do the coordinate mapping manually.&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;Here is a custom texture loading hook that does this on all textures when you load them:&lt;/span&gt;&lt;/span&gt;&lt;div style="margin-top: 8px; margin-right: 8px; margin-bottom: 8px; margin-left: 8px; font: normal normal normal small/normal arial; "&gt;&lt;span class="Apple-style-span" style="font-family:Georgia;font-size:130%;"&gt;&lt;span class="Apple-style-span" style="font-size:16px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre class="prettyprint lang-py"&gt;from __future__ import division&lt;br /&gt;import pygame, rabbyt, sys, os&lt;br /&gt;from rabbyt._rabbyt import load_texture&lt;br /&gt;&lt;br /&gt;def next_pow2( n ):&lt;br /&gt; """&lt;br /&gt; Find the next power of two.&lt;br /&gt; """&lt;br /&gt; n -= 1&lt;br /&gt; n = n | (n &amp;gt;&amp;gt; 1)&lt;br /&gt; n = n | (n &amp;gt;&amp;gt; 2)&lt;br /&gt; n = n | (n &amp;gt;&amp;gt; 4)&lt;br /&gt; n = n | (n &amp;gt;&amp;gt; 8)&lt;br /&gt; n = n | (n &amp;gt;&amp;gt; 16) &lt;br /&gt; n += 1&lt;br /&gt; return n&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Tex:&lt;br /&gt; def __init__(self):&lt;br /&gt;     self.id = 0&lt;br /&gt;     self.width = 0&lt;br /&gt;     self.height = 0&lt;br /&gt;     self.tex_coords = (0,0,0,0)&lt;br /&gt;&lt;br /&gt;_texture_cache = {}&lt;br /&gt;def load_and_size(filename, filter=True, mipmap=True):&lt;br /&gt; if filename not in _texture_cache:&lt;br /&gt;     pygame = __import__("pygame", {},{},[])&lt;br /&gt;     if os.path.exists(filename):&lt;br /&gt;         img = pygame.image.load(filename)&lt;br /&gt;     else:&lt;br /&gt;         img = pygame.image.load(os.path.join(data_directory, filename))&lt;br /&gt;  &lt;br /&gt;     t = Tex()&lt;br /&gt;     t.width,t.height = size = list(img.get_size())&lt;br /&gt;     size[0] = next_pow2(size[0])&lt;br /&gt;     size[1] = next_pow2(size[1])&lt;br /&gt;     t.tex_coords = (0,t.height/size[1],t.width/size[0],0)&lt;br /&gt;      &lt;br /&gt;     n = pygame.Surface(size, pygame.SRCALPHA|pygame.HWSURFACE, img)&lt;br /&gt;     n.blit(img, (0,size[1]-t.height))&lt;br /&gt;  &lt;br /&gt;     data = pygame.image.tostring(n, 'RGBA', True)&lt;br /&gt;     t.id = load_texture(data, size, "RGBA", filter, mipmap)&lt;br /&gt;     _texture_cache[filename] = t&lt;br /&gt; return _texture_cache[filename]&lt;br /&gt;&lt;br /&gt;rabbyt.set_load_texture_file_hook(load_and_size)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-1668491597028552066?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/gC7APHPov40" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/1668491597028552066/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2009/05/better-pygame-and-rabbyt-texture.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1668491597028552066?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/1668491597028552066?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/gC7APHPov40/better-pygame-and-rabbyt-texture.html" title="Better pygame and rabbyt texture loading" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2009/05/better-pygame-and-rabbyt-texture.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CE4GRno7fyp7ImA9WxVbFU8.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-7994197144424588080</id><published>2009-03-31T12:05:00.003-05:00</published><updated>2009-03-31T13:08:47.407-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-31T13:08:47.407-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gondola" /><category scheme="http://www.blogger.com/atom/ns#" term="pyweek" /><title>Gondola and 4 types of players</title><content type="html">Gondola was our pyweek 7 entry. Based on &lt;a href="http://pyweek.org/e/yat/ratings/"&gt;feedback there&lt;/a&gt; and elsewhere I have concluded that, at least when it comes to Gondola, there are four types of players.&lt;br /&gt;&lt;br /&gt;1. Those that wanted to optimize their networks. A player from this group can spend hours playing on just one map, trying to make things run better. The ideal group to be in to enjoy Gondola.&lt;br /&gt;&lt;br /&gt;2. Those that wanted to solve a puzzle. They lay out their networks and then they're done. Either they don't realize it or it just doesn't appeal to them to go back and optimize their routs. Keeping these players going takes a lot of large and complex maps. Maps also require some sort of goal; something to work towards and be able to fail at doing. Which is something Gondola's current selection of maps does not provide.&lt;br /&gt;&lt;br /&gt;3. Those that just want explosions. Gondola is similar to simcity in the sense that it is a simulation and a toy. There is no real goal other than to do better that you have before. But one thing that Gondola doesn't have that simcity does is explosions. There are no futureistic robots that come and wipe out your infrustructor. No fires, tordadoes or anything else destructive.&lt;br /&gt;&lt;br /&gt;4. Those that just didn't get it. I guess the game, for some people, isn't explained well enough. I don't blame them at all because the tutorial really isn't that comprehensive. I wish I knew in what way they didn't get it though, so I could address the confusing aspects. A game, idealy, should not require any explination or even a tutorial in order to start playing; Something I am still trying to figure out how to do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-7994197144424588080?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/wLOmspfEw3o" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/7994197144424588080/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2009/03/gondola-and-4-types-of-players.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/7994197144424588080?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/7994197144424588080?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/wLOmspfEw3o/gondola-and-4-types-of-players.html" title="Gondola and 4 types of players" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2009/03/gondola-and-4-types-of-players.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIAQX0_fip7ImA9WxVVFEs.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-8148805738305263198</id><published>2009-03-07T11:14:00.010-06:00</published><updated>2009-03-07T17:29:00.346-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-07T17:29:00.346-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="implementation details" /><category scheme="http://www.blogger.com/atom/ns#" term="snowballz" /><category scheme="http://www.blogger.com/atom/ns#" term="optimization" /><title>Zooming and performance</title><content type="html">One problem I was continually having with SnowballZ was zooming. The further you zoomed out the slower it went (as, obviously, it had to draw everything). To the point where zoomed all the way in would give me 120fps and all the way out 30fps. Unacceptable.&lt;br /&gt;&lt;br /&gt;I started working on making it fade into a paper-looking map when zooming out; So I could strip out the trees and terrain. But on the fly cartography that looks even half way decent is a lot of work. That's when Matthew suggested rendering the entire map to a texture. Bingo.&lt;br /&gt;&lt;br /&gt;I created a function that set the viewport to cover the entire map and rendered just the terrain, trees and other decor to an off-screen buffer; Which I then saved to a texture. Now when the player zooms out to a certain point it switches to drawing that &lt;span style="font-style: italic;"&gt;one&lt;/span&gt; texture which, compared to a 80,000+ vertex terrain and a couple hundred trees, is much faster.&lt;br /&gt;&lt;br /&gt;The one drawback of this method is that it isn't perfectly seamless. But you wouldn't notice the difference unless you were looking for it. I rendered to a 1024x1024 texture so it is a little blurry when you use it too close up. This could be solved by rendering it to a larger texture but my concern comes when you have a map that is bigger than my 150x150 tiles (odd number, I know).&lt;br /&gt;&lt;br /&gt;If there is any interest in seeing how I did it here it is:&lt;br /&gt;(slightly modified for clarity out of context, my thanks to Richard Jones for showing how to do this on the pyglet mailing list)&lt;br /&gt;&lt;pre class="prettyprint lang-py"&gt;&lt;span class="pln"&gt;&lt;/span&gt;&lt;span class="com"&gt;# create our frame buffer&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;fbo &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="typ"&gt;GLuint&lt;/span&gt;&lt;span class="pun"&gt;()&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;glGenFramebuffersEXT&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="lit"&gt;1&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; ctypes&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;byref&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;fbo&lt;/span&gt;&lt;span class="pun"&gt;))&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;glBindFramebufferEXT&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_FRAMEBUFFER_EXT&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; fbo&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="com"&gt;# allocate a texture and add to the frame buffer&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;tex &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; image&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="typ"&gt;Texture&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;create_for_size&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt; 1024&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt; 1024&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_RGB&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;glBindTexture&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; tex&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;id&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;glFramebufferTexture2DEXT&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_FRAMEBUFFER_EXT&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_COLOR_ATTACHMENT0_EXT&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; tex&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;id&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;status &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; glCheckFramebufferStatusEXT&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_FRAMEBUFFER_EXT&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="kwd"&gt;assert&lt;/span&gt;&lt;span class="pln"&gt; status &lt;/span&gt;&lt;span class="pun"&gt;==&lt;/span&gt;&lt;span class="pln"&gt; GL_FRAMEBUFFER_COMPLETE_EXT&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="com"&gt;# now render&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;glBindFramebufferEXT&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_FRAMEBUFFER_EXT&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; fbo&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="com"&gt;# Snipped. This is where I render my map. See lib/map/display.py for full code.&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="com"&gt;# clean up&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;glDeleteFramebuffersEXT&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="lit"&gt;1&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; ctypes&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;byref&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;fbo&lt;/span&gt;&lt;span class="pun"&gt;))&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="kwd"&gt;self&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;offscreen_map &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; rabbyt&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="typ"&gt;Sprite&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;tex&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; shape&lt;/span&gt;&lt;span class="pun"&gt;=(&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;map_w&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;map_h&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;),&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;tex_shape&lt;/span&gt;&lt;span class="pun"&gt;=(&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;1&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;1&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;))&lt;/span&gt;&lt;/pre&gt;Using this method requires a certain OpenGL extension that older hardware might not have. You are also limited to a max texture resolution. Which could be an issue when it comes to large maps, even on newer hardware.&lt;br /&gt;&lt;br /&gt;A method that avoids both of these problems is to split up your prerendering of the terrain into sections of 512x512 textures. That avoids the sharpness problem. As long as your section resolutions are smaller than your screen size you can render them to the backbuffer and copy that to a texture, which avoids GL extention problems.&lt;br /&gt;&lt;br /&gt;This is how I'm doing it:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint lang-py"&gt;&lt;span class="pln"&gt;chunk_res &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;2048&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;chunk_tex_res &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;512&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;num_chunks &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;map_w&lt;/span&gt;&lt;span class="pun"&gt;//&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;/span&gt;&lt;span class="pun"&gt;+&lt;/span&gt;&lt;span class="lit"&gt;1&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; map_h&lt;/span&gt;&lt;span class="pun"&gt;//&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;/span&gt;&lt;span class="pun"&gt;+&lt;/span&gt;&lt;span class="lit"&gt;1&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;glClearColor&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="kwd"&gt;for&lt;/span&gt;&lt;span class="pln"&gt; x &lt;/span&gt;&lt;span class="kwd"&gt;in&lt;/span&gt;&lt;span class="pln"&gt; range&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;num_chunks&lt;/span&gt;&lt;span class="pun"&gt;[&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;]):&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;   &lt;/span&gt;&lt;span class="kwd"&gt;for&lt;/span&gt;&lt;span class="pln"&gt; y &lt;/span&gt;&lt;span class="kwd"&gt;in&lt;/span&gt;&lt;span class="pln"&gt; range&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;num_chunks&lt;/span&gt;&lt;span class="pun"&gt;[&lt;/span&gt;&lt;span class="lit"&gt;1&lt;/span&gt;&lt;span class="pun"&gt;]):&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       tex &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; image&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="typ"&gt;Texture&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;create_for_size&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;               chunk_tex_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; chunk_tex_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_RGB&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;       l &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; x&lt;/span&gt;&lt;span class="pun"&gt;*&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;br /&gt;       t &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; y&lt;/span&gt;&lt;span class="pun"&gt;*&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;/span&gt;&lt;span class="pun"&gt;+&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;br /&gt;       r &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; x&lt;/span&gt;&lt;span class="pun"&gt;*&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;/span&gt;&lt;span class="pun"&gt;+&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;br /&gt;       b &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; y&lt;/span&gt;&lt;span class="pun"&gt;*&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;br /&gt;       glMatrixMode&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_PROJECTION&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glLoadIdentity&lt;/span&gt;&lt;span class="pun"&gt;()&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glViewport&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;chunk_tex_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;chunk_tex_res&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glOrtho&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;l&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; r&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; b&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; t&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="pun"&gt;-&lt;/span&gt;&lt;span class="lit"&gt;1000&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;1000&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glMatrixMode&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_MODELVIEW&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glLoadIdentity&lt;/span&gt;&lt;span class="pun"&gt;()&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glClear&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_COLOR_BUFFER_BIT&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span class="com"&gt;# (Snipped) Render your map here.&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;       glBindTexture&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; tex&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;id&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glTexParameteri&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_TEXTURE_WRAP_S&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_CLAMP_TO_EDGE&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glTexParameteri&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_TEXTURE_WRAP_T&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_CLAMP_TO_EDGE&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;       glCopyTexImage2D&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;GL_TEXTURE_2D&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; GL_RGB&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;               chunk_tex_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; chunk_tex_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span class="kwd"&gt;self&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;offscreen_chunks&lt;/span&gt;&lt;span class="pun"&gt;[(&lt;/span&gt;&lt;span class="pln"&gt;x&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;y&lt;/span&gt;&lt;span class="pun"&gt;)]&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt; rabbyt&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="typ"&gt;Sprite&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;tex&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;               x&lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt;x&lt;/span&gt;&lt;span class="pun"&gt;*&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; y&lt;/span&gt;&lt;span class="pun"&gt;=&lt;/span&gt;&lt;span class="pln"&gt;y&lt;/span&gt;&lt;span class="pun"&gt;*&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;               shape&lt;/span&gt;&lt;span class="pun"&gt;=(&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;chunk_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; chunk_res&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt; &lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;))&lt;/span&gt;&lt;span class="pln"&gt;&lt;br /&gt;&lt;br /&gt;glViewport&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="kwd"&gt;self&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;scene&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;view&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;width&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="kwd"&gt;self&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;scene&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;view&lt;/span&gt;&lt;span class="pun"&gt;.&lt;/span&gt;&lt;span class="pln"&gt;height&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-8148805738305263198?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/dKh2NE7c92Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/8148805738305263198/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2009/03/zooming-and-performance.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8148805738305263198?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8148805738305263198?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/dKh2NE7c92Y/zooming-and-performance.html" title="Zooming and performance" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2009/03/zooming-and-performance.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0AERXs4eCp7ImA9WxVWFE8.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-8335063413782482374</id><published>2009-02-23T14:17:00.006-06:00</published><updated>2009-02-23T16:55:04.530-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-23T16:55:04.530-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="AI" /><category scheme="http://www.blogger.com/atom/ns#" term="gameplay" /><category scheme="http://www.blogger.com/atom/ns#" term="snowballz" /><title>Penguins with emotions</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_rxNCU1LuKD0/SaMEmsTdbNI/AAAAAAAAAAk/sd36VKS1z_4/s1600-h/screen3.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 313px; height: 372px;" src="http://1.bp.blogspot.com/_rxNCU1LuKD0/SaMEmsTdbNI/AAAAAAAAAAk/sd36VKS1z_4/s400/screen3.png" alt="" id="BLOGGER_PHOTO_ID_5306089848746896594" border="0" /&gt;&lt;/a&gt;Having the penguins share your emotions is a great way to connect with the player. When your little posse is outnumbered 4 to 1 your penguins don't like it any more than you do!&lt;br /&gt;&lt;br /&gt;In fact, as they aren't exactly the most mature little creatures, they'll get down right angry. To the point where they will throw their snowballs faster, harder and further.&lt;br /&gt;&lt;br /&gt;When your on the wrong end of the deal you might find it a little annoying how these little guys don't even take time to aim. Normally that would be a good thing but each snowball, even when thrown just in your general direction, will hit at least one of your penguins.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-8335063413782482374?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/0tOCSE9YduA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/8335063413782482374/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2009/02/penguins-with-emotions.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8335063413782482374?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8335063413782482374?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/0tOCSE9YduA/penguins-with-emotions.html" title="Penguins with emotions" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_rxNCU1LuKD0/SaMEmsTdbNI/AAAAAAAAAAk/sd36VKS1z_4/s72-c/screen3.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2009/02/penguins-with-emotions.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4CSH87fSp7ImA9WxVWE0k.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-545956138814773970</id><published>2009-02-22T17:22:00.008-06:00</published><updated>2009-02-22T17:56:09.105-06:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-22T17:56:09.105-06:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="snowballz" /><category scheme="http://www.blogger.com/atom/ns#" term="user interface" /><title>Run my little penguins, run!</title><content type="html">For the next release of snowballz I'm trying to simplify the user interface for two reasons; So it's easier for players to learn and secondly (and most importantly at this point) it's easier for me.&lt;br /&gt;&lt;br /&gt;One issue I've always had with controlling the penguins is the run mode. In versions 0.9.x, by middle clicking you tell your penguins to run without stop, regardless of enemies, to where you send them. A great way to get your snowballers behind enemy lines. Apposed to if you were to just right click, in which case they would stop and throw snowballs at enemies.&lt;br /&gt;&lt;br /&gt;The one problem I've had with this method is that it isn't obvious. No-one would ever discover it, which could be frustrating.&lt;br /&gt;&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_rxNCU1LuKD0/SaHlsdj82QI/AAAAAAAAAAc/Q0Yohu9kgfM/s800/run.png" alt="" id="BLOGGER_PHOTO_ID_5305774388031576322" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;That's when I remembered hearing about an article talking about networking RTS games. One interesting thing that the article mentioned was to filter out rapid clicking; As players tend to repeatedly tell their units to go to one spot as if it made them get there faster. Thus saving network bandwidth (it was an old article written when most people had dialup).&lt;br /&gt;&lt;br /&gt;So why not use this behavior to do what the player expects? So I got rid of the confusing middle click and set it so that when a player rapidly tells their penguins to move it adds a double arrow to the move icon (which specifies run mode). And their penguins will run through the middle of a snowball fight without stopping until they get to where you sent them.&lt;br /&gt;&lt;br /&gt;And there we go. The run feature will be discovered just by playing. It doesn't have to be in a tutorial or tips &amp;amp; tricks. Now let's see if I can get the rest of the interface like that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-545956138814773970?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/zL0fS66N3As" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/545956138814773970/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2009/02/run-my-little-penguins-run.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/545956138814773970?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/545956138814773970?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/zL0fS66N3As/run-my-little-penguins-run.html" title="Run my little penguins, run!" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_rxNCU1LuKD0/SaHlsdj82QI/AAAAAAAAAAc/Q0Yohu9kgfM/s72-c/run.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2009/02/run-my-little-penguins-run.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkAHSHs5cCp7ImA9WxVVF0Q.&quot;"><id>tag:blogger.com,1999:blog-8413630985167522723.post-8274147585623752526</id><published>2008-09-02T14:09:00.000-05:00</published><updated>2009-03-11T14:12:19.528-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-11T14:12:19.528-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="gondola" /><category scheme="http://www.blogger.com/atom/ns#" term="pyweek" /><title>Our entry in pyweek 7</title><content type="html">This past pyweek (#7) was the first that Matthew and I got to compete in. It was a lot of fun and it resulted in &lt;a href="http://arcticpaint.com/games/gondola/"&gt;Gondola&lt;/a&gt;. Gondola has turned out to be a very fun game; especially if you are the type that likes laid back games such as simcity or transport tycoon … or have an odd passion for optimizing distribution networks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8413630985167522723-8274147585623752526?l=weblog.arcticpaint.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/ArcticPaint/~4/rV6V5TJc2Cw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://weblog.arcticpaint.com/feeds/8274147585623752526/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://weblog.arcticpaint.com/2008/09/our-entry-in-pyweek-7.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8274147585623752526?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8413630985167522723/posts/default/8274147585623752526?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ArcticPaint/~3/rV6V5TJc2Cw/our-entry-in-pyweek-7.html" title="Our entry in pyweek 7" /><author><name>Joseph Marshall</name><uri>https://profiles.google.com/110413588905467859811</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-wLzbVnpZSr8/AAAAAAAAAAI/AAAAAAAAAEk/GQckSShB1KE/s512-c/photo.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://weblog.arcticpaint.com/2008/09/our-entry-in-pyweek-7.html</feedburner:origLink></entry></feed>

