<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-21382508</id><updated>2012-02-15T23:35:05.649-08:00</updated><category term='Open Scene Graph'/><title type='text'>Shiny Dynamics</title><subtitle type='html'>Lisp. 3D graphics. Compilers. Operating systems. Mobile devices.

Cool stuff.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-21382508.post-128467121201323346</id><published>2010-09-01T07:42:00.000-07:00</published><updated>2010-09-02T01:28:57.956-07:00</updated><title type='text'>The Seamless Engine Goes Global</title><content type='html'>I've been doing more work on the terrain engine I described in my &lt;a href="http://shiny-dynamics.blogspot.com/2010/08/terrain-engine-for-osgearth.html"&gt;last post&lt;/a&gt;, which I'm now calling "seamless." It now works pretty well on a global scale.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_jaEJ-2dqK4U/TH51Rga4fwI/AAAAAAAAACo/jLjJZ0YmXow/s1600/globe.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_jaEJ-2dqK4U/TH51Rga4fwI/AAAAAAAAACo/jLjJZ0YmXow/s320/globe.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5511971937568980738" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jaEJ-2dqK4U/TH51fMdrbQI/AAAAAAAAACw/e7WsFWF3Hvk/s1600/poly.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 194px;" src="http://4.bp.blogspot.com/_jaEJ-2dqK4U/TH51fMdrbQI/AAAAAAAAACw/e7WsFWF3Hvk/s320/poly.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5511972172730166530" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_jaEJ-2dqK4U/TH51mGSaAvI/AAAAAAAAAC4/cNdFk22CEn0/s1600/wire.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 194px;" src="http://3.bp.blogspot.com/_jaEJ-2dqK4U/TH51mGSaAvI/AAAAAAAAAC4/cNdFk22CEn0/s320/wire.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5511972291331359474" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There's still lots of work to do, especially on optimization at the OpenGL level, but I'm quite pleased, especially with how easy it is to get the height and image data out of osgEarth.&lt;br /&gt;&lt;br /&gt;I encountered an interesting issue with the &lt;a href="http://www.progonos.com/furuti/MapProj/Normal/ProjPoly/projPoly2.html#CubQSC"&gt;Quadrilateralized Spherical Cube&lt;/a&gt; that I was planning to use. I did find a good formal reference to the math behind the projection at &lt;a href="http://www.atnf.csiro.au/people/mcalabre/WCS/"&gt;this site&lt;/a&gt;. It turns out that the COBE satellite didn't use the QSC projection, but a slightly simpler one. Anyway, the seamless terrain algorithm requires a good estimate of the edge length of a patch on the grid and also a calculation of the minimum distance from the eye point to the edge. These are both difficult to calculate with the QSC projection, in part because the projection is not differentiable on the diagonals of the cube faces. I came up with another projection in which the grid lines are all great circles on the sphere:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jaEJ-2dqK4U/TH5yLTvQl5I/AAAAAAAAACg/3_wHuyzrNb8/s1600/euler.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 215px;" src="http://2.bp.blogspot.com/_jaEJ-2dqK4U/TH5yLTvQl5I/AAAAAAAAACg/3_wHuyzrNb8/s320/euler.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5511968532550686610" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I'm calling this projection an "Euler projection" by analogy to one class of Euler angles in which a rotation is measured with respect to fixed axes. For the equatorial cube faces, the vertical grid lines are the same as meridians of longitude, but the "latitude" is measured perpendicular to the horizontal axis, not in the longitudinal plane. The fact that the grid lines are now all segments of great circles makes the math almost trivially easy.&lt;br /&gt;&lt;br /&gt;Now, we're not displaying a sphere (unlike some programs :) but an ellipsoid, so this measure will break down as we get close to the earth, but I'm prepared to hack that problem away.&lt;br /&gt;&lt;br /&gt;The source to the seamless engine is available from &lt;a href="http://gitorious.org/seamless"&gt; this Git repository&lt;/a&gt;. Compilation requires osgEarth and Open Scene Graph from SVN and the whole thing is still a bit raw.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-128467121201323346?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/128467121201323346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=128467121201323346' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/128467121201323346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/128467121201323346'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/09/seamless-engine-goes-global.html' title='The Seamless Engine Goes Global'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_jaEJ-2dqK4U/TH51Rga4fwI/AAAAAAAAACo/jLjJZ0YmXow/s72-c/globe.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-8766401524269372970</id><published>2010-08-15T14:53:00.000-07:00</published><updated>2010-08-15T15:26:31.031-07:00</updated><title type='text'>a terrain engine for osgEarth</title><content type='html'>Lately I've been working on an experimental terrain engine for &lt;a href="http://www.osgearth.org/"&gt;osgEarth&lt;/a&gt; on behalf of the folks at &lt;a href="http://pelicanmapping.com/"&gt;Pelican Mapping&lt;/a&gt;. osgEarth is a cool project that imports a variety of geographic raster and vector data into Open Scene Graph without requiring a lengthy pre-processing step. I've implemented the algorithm described in &lt;a href ="http://wscg.zcu.cz/wscg2007/Papers_2007/full/C43-full.pdf"&gt;Seamless Patches for GPU-Based Terrain Rendering&lt;/a&gt;. The main feature of this technique is that LOD is determined at the patch edges, so that the polygons on either side of an edge always line up. The four triangles of a square patch may have different resolutions and are stitched together by a small number of strips. Here's a scene with Mt. Fuji: &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jaEJ-2dqK4U/TGhlgqcoDAI/AAAAAAAAACA/FVSH3uWa8WQ/s1600/fuji.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 182px;" src="http://1.bp.blogspot.com/_jaEJ-2dqK4U/TGhlgqcoDAI/AAAAAAAAACA/FVSH3uWa8WQ/s320/fuji.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5505762156285004802" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;And the wire frame view:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_jaEJ-2dqK4U/TGhlySV_FjI/AAAAAAAAACI/Q7mVJuNQXGc/s1600/wirefuji.jpg."&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 182px;" src="http://3.bp.blogspot.com/_jaEJ-2dqK4U/TGhlySV_FjI/AAAAAAAAACI/Q7mVJuNQXGc/s320/wirefuji.jpg." border="0" alt=""id="BLOGGER_PHOTO_ID_5505762459052348978" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Of course, the objective is to get to a whole-earth scheme. I'm going with a projected cube approach, where the basic seamless algorithm is run on the six sides of the cube. I like the &lt;a href="http://www.progonos.com/furuti/MapProj/Normal/ProjPoly/projPoly2.html#CubQSC"&gt;Quadrilateralized Spherical Cube&lt;/a&gt; which was developed for processing the data from the NASA &lt;a href="http://lambda.gsfc.nasa.gov/product/cobe/skymap_info_new.cfm"&gt;Cobe&lt;/a&gt; satellite. A nice property of the projection is that is equal-area, so that a recursive devision in the cube face space should result in 4 equal-area spherical quads on the earth. It looks pretty:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jaEJ-2dqK4U/TGho4uZF9FI/AAAAAAAAACQ/zIczbAlfM7s/s1600/cobe.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 215px;" src="http://2.bp.blogspot.com/_jaEJ-2dqK4U/TGho4uZF9FI/AAAAAAAAACQ/zIczbAlfM7s/s320/cobe.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5505765868195673170" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Here's hoping that the calculation of the projection doesn't become a big bottleneck. Incidently, it was very hard to find the equations describing the projection: I eventually found a nice formulation &lt;a href="http://www.sai.msu.su/~megera/wiki/SphereCube"&gt;here&lt;/a&gt;. But beware: there's a typo in Equation 3-38. "cos(theta)" should be "cos(phi)."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-8766401524269372970?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/8766401524269372970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=8766401524269372970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/8766401524269372970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/8766401524269372970'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/08/terrain-engine-for-osgearth.html' title='a terrain engine for osgEarth'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_jaEJ-2dqK4U/TGhlgqcoDAI/AAAAAAAAACA/FVSH3uWa8WQ/s72-c/fuji.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-4376009974070634858</id><published>2010-06-30T01:56:00.000-07:00</published><updated>2010-06-30T02:41:56.843-07:00</updated><title type='text'>Cool Links</title><content type='html'>Here are some cool blogs I've come across recently. &lt;a href="http://virtualglobeandterrainrendering.blogspot.com/"&gt;Virtual Globe and Terrain Rendering&lt;/a&gt; is devoted to a book-in-progress of the same name and has a nice collection of links to resources and other interesting blogs. &lt;a href="http://rastergrid.com/blog/"&gt;RasterGrid&lt;/a&gt; has good articles on new features of OpenGL; I especially like &lt;a href="http://rastergrid.com/blog/2010/02/instance-culling-using-geometry-shaders/"&gt;Instance Culling Using Geometry Shaders&lt;/a&gt;, about doing culling on the GPU, and &lt;a href="http://rastergrid.com/blog/2010/01/uniform-buffers-vs-texture-buffers/"&gt;Uniform Buffers vs Texture Buffers&lt;/a&gt;. For an old graphics fossil like me, these are great topics in modern 3D graphics programming. Also, the &lt;a href="http://outerra.blogspot.com/"&gt;Outerra&lt;/a&gt; engine guys are doing cool stuff and writing about it too. I've added these to my blog list, and so should you!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-4376009974070634858?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/4376009974070634858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=4376009974070634858' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/4376009974070634858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/4376009974070634858'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/06/cool-links.html' title='Cool Links'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-5472727015912779113</id><published>2010-06-16T14:45:00.000-07:00</published><updated>2010-06-16T14:54:57.504-07:00</updated><title type='text'>Everything You Always Wanted to Know About StateSets (But Were Afraid to Ask)</title><content type='html'>Here's &lt;a href="http://www.bricoworks.com/articles/stategraph/stategraph.html"&gt;part 2&lt;/a&gt; of my articles on Open Scene Graph graphics state management. &lt;a href="http://www.bricoworks.com/articles/stateset/stateset.html"&gt;Part 1&lt;/a&gt; covered the &lt;code&gt;StateSet&lt;/code&gt; class, which OSG programmers should be familiar with. This part looks behind the scenes at how the OSG "backend" optimizes rendering for minimizing graphics state changes. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-5472727015912779113?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/5472727015912779113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=5472727015912779113' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/5472727015912779113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/5472727015912779113'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/06/everything-you-always-wanted-to-know.html' title='Everything You Always Wanted to Know About StateSets (But Were Afraid to Ask)'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-6299543098393734738</id><published>2010-05-13T03:41:00.000-07:00</published><updated>2010-05-13T04:26:09.548-07:00</updated><title type='text'>Paper Models in Blender</title><content type='html'>I just discovered this &lt;a href="http://pixeloz.deviantart.com/art/Free-Paper-Model-Design-E-Book-158441085"&gt;e-book&lt;/a&gt; on using free software, like &lt;a href="http://www.blender.org/"&gt;Blender&lt;/a&gt; and &lt;a href="www.inkscape.org"&gt;Inkscape&lt;/a&gt;, to design paper models. Actually, these &lt;a href="http://www.currell.net/models/gall_titanic.htm"&gt;models&lt;/a&gt; are usually made of thicker card stock than paper. Anyway, this is about as far from real-time simulation as you can get, but the e-book is still a lot of fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-6299543098393734738?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/6299543098393734738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=6299543098393734738' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/6299543098393734738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/6299543098393734738'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/05/paper-models-in-blender.html' title='Paper Models in Blender'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-5817607720232758737</id><published>2010-04-16T02:17:00.000-07:00</published><updated>2010-04-16T02:20:42.268-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Open Scene Graph'/><title type='text'></title><content type='html'>I've written the first part of a series on Open Scene Graph graphics state optimization &lt;a href="http://www.bricoworks.com/articles/stateset/stateset.html"&gt;here&lt;/a&gt;. This goes into some detail about graphics modes, attributes, the &lt;code&gt;StateSet&lt;/code&gt; object, and the low level &lt;code&gt;State&lt;/code&gt; object. Check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-5817607720232758737?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/5817607720232758737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=5817607720232758737' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/5817607720232758737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/5817607720232758737'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/04/ive-written-first-part-of-series-on.html' title=''/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-8215125033817340928</id><published>2010-03-23T08:03:00.001-07:00</published><updated>2010-03-23T08:05:46.577-07:00</updated><title type='text'>Floating Point Depthbuffers in OSG</title><content type='html'>I submitted a new demo to the &lt;a href="http://www.openscenegraph.org"&gt;Open Scene Graph&lt;/a&gt; project that shows how to set up a floating point depth buffer. The standard way to do this is to create a &lt;a href="http://www.gamedev.net/reference/articles/article2331.asp"&gt;Frame Buffer Object&lt;/a&gt; and attach a depth texture with a floating point format. That won't work if you're doing multisampling antialiasing; it that case, you attach a "render buffer" that has the appropriate number of samples to the FBO. Open Scene Graph takes care of many of the details for you.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jaEJ-2dqK4U/S6jYfV5aILI/AAAAAAAAAB4/7RhTh_Omlj0/s1600-h/screen_shot_0_0.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_jaEJ-2dqK4U/S6jYfV5aILI/AAAAAAAAAB4/7RhTh_Omlj0/s320/screen_shot_0_0.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5451845381897461938" /&gt;&lt;/a&gt;&lt;br /&gt;The demo shows how to set up an FBO with a floating point depth buffer, as well as the effects of "inverting" the depth test. Setting 1.0 to correspond to the near plane and 0.0 to the far plane turns out to have &lt;a href="http://www.humus.name/index.php?ID=255"&gt;better behavior than the more usual way.&lt;/a&gt; Also, the demo allows the user to cycle between all the available multisampling modes, as well as between floating point and integer depth buffers, of course. If you can't wait for this to show up in the OSG source tree, &lt;a href="http://article.gmane.org/gmane.comp.graphics.openscenegraph.cvs/7284"&gt;get the patch&lt;/a&gt; yourself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-8215125033817340928?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/8215125033817340928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=8215125033817340928' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/8215125033817340928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/8215125033817340928'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/03/floating-point-depthbuffers-in-osg.html' title='Floating Point Depthbuffers in OSG'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_jaEJ-2dqK4U/S6jYfV5aILI/AAAAAAAAAB4/7RhTh_Omlj0/s72-c/screen_shot_0_0.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-6058372834566161822</id><published>2010-03-01T01:15:00.000-08:00</published><updated>2010-03-01T01:20:45.162-08:00</updated><title type='text'>Vertex Cache Optimization for OSG</title><content type='html'>I implemented Tom Forsyth's &lt;a href="http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html"&gt;Vertex Cache Optimization&lt;/a&gt; algorithm in &lt;a href="www.openscenegraph.org"&gt;Open Scene Graph&lt;/a&gt; (OSG). The quick summary is that indexed lists of triangles in a mesh are more efficient than traditional representations like triangle strips. GPUs keep a cache of the post-transform values for the most recently used vertices in a mesh. This can avoid a whole lot of work, such as rerunning vertex shaders. Tristrips don't make good use of this cache because they introduce a new vertex for every triangle and only reuse the last two vertices. On the other hand, a random mesh order isn't good either; the triangles in a mesh need to be in a good order to take proper advantage of the cache. Tom describes an efficient algorithm for optimizing a mesh for the vertex cache. It produces an order that is "oblivious" to the actual cache size i.e., it will work well on a range of hardware.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jaEJ-2dqK4U/S4uGKvQChbI/AAAAAAAAABM/11OX49YF5g8/s1600-h/screen_shot_0_0.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 200px;" src="http://2.bp.blogspot.com/_jaEJ-2dqK4U/S4uGKvQChbI/AAAAAAAAABM/11OX49YF5g8/s320/screen_shot_0_0.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5443592093647930802" /&gt;&lt;/a&gt;&lt;br /&gt;The algorithm does work as advertised. I tried it on the &lt;a href="http://www.cc.gatech.edu/projects/large_models/happy.html"&gt;Happy Buddha&lt;/a&gt; model, which is a monster-size mesh with over a million triangles. On my machine the optimization reduces the draw time for this mesh by 38 percent, which is enormous. This is a special case because the mesh is so large and regular, and Your Milage May Vary, but it does seem like a worthwhile optimization for large meshes. I've submitted my code to the OSG project.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-6058372834566161822?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/6058372834566161822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=6058372834566161822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/6058372834566161822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/6058372834566161822'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/03/vertex-cache-optimization-for-osg.html' title='Vertex Cache Optimization for OSG'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_jaEJ-2dqK4U/S4uGKvQChbI/AAAAAAAAABM/11OX49YF5g8/s72-c/screen_shot_0_0.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-2772692109123911268</id><published>2010-02-23T06:19:00.000-08:00</published><updated>2010-02-23T06:45:44.836-08:00</updated><title type='text'>more VirtualPlanetBuilder fun</title><content type='html'>Let's add some other imagery to our Mt. Washington terrain. The &lt;a href="http://online.wr.usgs.gov/ngpo/doq/"&gt;digital orthophoto quadrangles&lt;/a&gt; published by the USGS are a decent source of free aerial photographs of the U.S. These images are rectified, which means that any effects from the tilt of the camera and relief of the terrain have been removed; just the thing for draping over a DEM. Unfortunately they are in black-and-white, but the resolution is 1 meter, which isn't bad. The image files are georeferenced, very convenient for building a mosaic with VirtualPlanetBuilder because we don't need to specify any additional projection or position parameters with each image. Generally one topographic map quad is divided into 4 DOQs. This makes for a marathon download session at the USGS &lt;a href="http://edcsns17.cr.usgs.gov/EarthExplorer/"&gt;website&lt;/a&gt;; maybe someone knows a better way?&lt;br /&gt;&lt;br /&gt;It's straightforward to build a new database using an &lt;code&gt;osgdem&lt;/code&gt; command similar to that used to build the map overlay database. One complication is that we now have 24 image files to deal with, instead of 5, and I don't feel like typing all the names on the command line. The downloaded files from the USGS have the form &lt;code&gt;O4407145.NES.837049.tgz&lt;/code&gt;, and their only contents seems to be another tar file. Extracting that, we get the TIFF file and a header file. I arranged these all in directories; for example, the path to one TIFF file is &lt;code&gt;O4407145.NES/O4407145.NES.837049.tif&lt;/code&gt;. We generate the command line with a little Unix magic:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ls  O*.*/*.tif | sed -e's;.*;-t &amp;;' \&lt;br /&gt;| xargs osgdem --TERRAIN --geocentric -d elev-meters.tif \&lt;br /&gt;-l 8 -o wash-photo.ive&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jaEJ-2dqK4U/S4Pldo7U1SI/AAAAAAAAAAs/fEUI3qzxbwo/s1600-h/orthophoto.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 125px;" src="http://4.bp.blogspot.com/_jaEJ-2dqK4U/S4Pldo7U1SI/AAAAAAAAAAs/fEUI3qzxbwo/s200/orthophoto.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5441445072158905634" /&gt;&lt;/a&gt;We have a nice image when we look at the scene with &lt;code&gt;osgviewer&lt;/code&gt;, although the gray imagery would benefit from colors and more contrast. But what would be very cool is display the topographic map tiles and the orthophotos on the same scene and transition between the two. VirtualPlanetBuilder lets you specify that images belong to different layers, and the OSG example program &lt;code&gt;osgmultitexturecontrol&lt;/code&gt; supports transitioning between layers based on elevation above terrain. In order to build the new database, we need to specify a "--layer 1" argument before each orthophoto:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;ls  O*.*/*.tif | sed -e's;.*;--layer 1 -t &amp;;' |\&lt;br /&gt;xargs osgdem --TERRAIN --geocentric -d elev-meters.tif \&lt;br /&gt;-t carter-dome-trim.tif -t crawford-trim.tif -t jackson-trim.tif\&lt;br /&gt; -t stairs-trim.tif -t k44071c3/k44071c3-trim.tif \&lt;br /&gt;-l 8 -o wash-layer.ive&lt;br /&gt;  &lt;/code&gt;&lt;br /&gt;Phew! Unfortunately, we don't see the map layer at all with the &lt;code&gt;osgmultitexturecontrol&lt;/code&gt; program from the OSG distribution. A look at the code reveals the problem: the elevation at which the transition occurs is hard-wired at 1000 kilometers. That's fine for viewing a whole-earth database from space, but doesn't do us any good. I hacked in an elevation transition argument, and got some better results. We start with the map view:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jaEJ-2dqK4U/S4PlxxZwgHI/AAAAAAAAAA0/LsWGD4QKePU/s1600-h/screen_shot_0_0.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 200px;" src="http://1.bp.blogspot.com/_jaEJ-2dqK4U/S4PlxxZwgHI/AAAAAAAAAA0/LsWGD4QKePU/s320/screen_shot_0_0.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5441445418031415410" /&gt;&lt;/a&gt;&lt;br /&gt;and as we zoom in, we transition from this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jaEJ-2dqK4U/S4Pl_cAJJvI/AAAAAAAAAA8/bTYWY1FkhY4/s1600-h/screen_shot_0_1.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 200px;" src="http://4.bp.blogspot.com/_jaEJ-2dqK4U/S4Pl_cAJJvI/AAAAAAAAAA8/bTYWY1FkhY4/s320/screen_shot_0_1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5441445652805002994" /&gt;&lt;/a&gt;&lt;br /&gt;to this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jaEJ-2dqK4U/S4PmMPAHK3I/AAAAAAAAABE/IJo1NHuPLcE/s1600-h/screen_shot_0_2.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 200px;" src="http://1.bp.blogspot.com/_jaEJ-2dqK4U/S4PmMPAHK3I/AAAAAAAAABE/IJo1NHuPLcE/s320/screen_shot_0_2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5441445872653511538" /&gt;&lt;/a&gt;&lt;br /&gt;Pretty cool. It would be nice to spruce the photos up a bit, perhaps by using the approach of &lt;a href="http://web.archive.org/web/20080414041054/http://www.oryx.com/ams/landsat.html"&gt;merging color from lower resolution LANDSAT imagery&lt;/a&gt; with these high resolution DOQs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-2772692109123911268?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/2772692109123911268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=2772692109123911268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/2772692109123911268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/2772692109123911268'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/02/more-virtualplanetbuilder-fun.html' title='more VirtualPlanetBuilder fun'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_jaEJ-2dqK4U/S4Pldo7U1SI/AAAAAAAAAAs/fEUI3qzxbwo/s72-c/orthophoto.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-605512388935050566</id><published>2010-02-02T06:31:00.001-08:00</published><updated>2010-02-02T09:46:06.769-08:00</updated><title type='text'>Fun with VirtualPlanetBuilder</title><content type='html'>I've been playing with the &lt;a href="http://www.openscenegraph.org/projects/VirtualPlanetBuilder"&gt;VirtualPlanetBuilder&lt;/a&gt; tool for &lt;a href="www.openscenegraph.org"&gt;Open Scene Graph&lt;/a&gt; (OSG). This flexible program builds paged terrain databases with automatic level of detail that can be loaded into the standard &lt;code&gt;osgviewer&lt;/code&gt;  program or any other program that uses the standard OSG loaders. It takes heightfield data and imagery as input, and  it accepts a variety of formats because it uses the &lt;a href="www.gdal.org"&gt;GDAL&lt;/a&gt; geospatial data library. If the input data is georeferenced, the excercise of building a terrain database is almost too easy.&lt;br /&gt;&lt;br /&gt;While VirtualPlanetBuilder can be used to build terrabyte-sized whole-earth databases, my own ambitions are so far more modest: build a small patch of terrain, drape some terrain over it, and fly around. Inspired by the &lt;a href="http://www.geomart.com/products/raisedrelief/nationalparks.htm"&gt;vinyl relief maps&lt;/a&gt; that my parents mounted on the wall of our apartment when I was growing up, I decided that it would be fun to drape topographic maps over the terrain. I made a little geocentric database of the Mt. Washington area. I found this &lt;a href="http://www.emrl.byu.edu/gsda/data_dem_obtain.html"&gt; useful set of links&lt;/a&gt; to sources of digital elevation data.&lt;br /&gt;&lt;br /&gt;For the DEM data, I went with &lt;a href="http://www.webgis.com/terr_us75m.html"&gt;webGIS&lt;/a&gt;, which provides DEMs based on USGS quadrangles. This turned out to not be terribly convenient, as there's state and county map interface but nothing that graphically shows the layout of the quadrangles. I flipped back-and-forth to the USGS web site and, armed with my knowledge of the White Mountains, downloaded the DEM data for the Mount Washington, Carter Dome, Crawford Notch, Stairs Mountain, Jackson, and Mount Dartmouth quadrangles. There's probably a more automated way to do this.&lt;br /&gt;&lt;br /&gt;I downloaded the images of the map quadrangles using the &lt;a href="http://www.usgsquads.com/mapfinder.html#MapFinder_for_Google_Earth"&gt; usgsquads.com Goggle Earth interface&lt;/a&gt;, but this was a bit broken too. The map that contains Mt. Washington itself is 7.5 x 15 minutes, and the download link to it was broken. I went to the &lt;a href="http://edcsns17.cr.usgs.gov/EarthExplorer/"&gt;USGS EarthExplorer&lt;/a&gt; to grab that map. I would have been better off getting all the map images there. The maps at usgsquads.com seem to be pretty old and their elevations are in feet, whereas the map from USGS was in meters. Oh well, it still looks nice.&lt;br /&gt;&lt;br /&gt;Because the &lt;code&gt;.dem&lt;/code&gt; height data files and the TIFF map files are geolocated, it is quite straight forward, after a little preparation, to feed them to VirtualPlanetBuilder's &lt;code&gt;osgdem&lt;/code&gt; program and get a data base. But my first effort had a problem; the maps have borders, and they show up on the terrain!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_jaEJ-2dqK4U/S2hcTVoV0ZI/AAAAAAAAAAM/IUWlZ0gtH-o/s1600-h/wash-shot.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 200px;" src="http://1.bp.blogspot.com/_jaEJ-2dqK4U/S2hcTVoV0ZI/AAAAAAAAAAM/IUWlZ0gtH-o/s320/wash-shot.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5433694437716119954" /&gt;&lt;/a&gt;&lt;br /&gt;Whoops. Because the map images are projected in UTM, the latitude and longitude boundaries of the maps are not horizontal and vertical in the image, so it would be awkward to trim the maps in a program like the Gimp.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_jaEJ-2dqK4U/S2hh0W-vY4I/AAAAAAAAAAk/kmvDuHlHEsM/s1600-h/carter-dome.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 151px; height: 200px;" src="http://3.bp.blogspot.com/_jaEJ-2dqK4U/S2hh0W-vY4I/AAAAAAAAAAk/kmvDuHlHEsM/s200/carter-dome.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5433700502572327810" /&gt;&lt;/a&gt;&lt;br /&gt;Fortunately &lt;code&gt;osgdem&lt;/code&gt; needs its data in a geographic coordinate system and reprojects if necessary, so we can do the reprojection ourselves and trim the borders using a GDALutility. &lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_jaEJ-2dqK4U/S2hcvGbD_OI/AAAAAAAAAAU/XBfCiPdgdDY/s1600-h/wash2-shot.jpg"&gt;&lt;img style="float:center; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 200px;" src="http://2.bp.blogspot.com/_jaEJ-2dqK4U/S2hcvGbD_OI/AAAAAAAAAAU/XBfCiPdgdDY/s320/wash2-shot.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5433694914670230754" /&gt;&lt;/a&gt;&lt;br /&gt;That looks better, but the relief of the mountains seems exaggerated, just like those vinyl relief maps. A little snooping with &lt;code&gt;gdalinfo&lt;/code&gt; shows that the elevation data is in feet, but &lt;code&gt;osgdem&lt;/code&gt; builds a geocentric database using meters, and that info got lost somewhere along the way. Fortunately it's easy to fix this up with a GDAL tool.&lt;br /&gt;&lt;br /&gt;Here's the complete recipe. First, many of the .dem files have the same name, so I renamed them in the directories where I unpacked them:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;for i in *.zip; do&lt;br /&gt;  mkdir ${i%.zip}&lt;br /&gt;  mv $i ${i%.zip}&lt;br /&gt;done&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then I combined them into one TIFF and built overviews: &lt;br /&gt;&lt;code&gt;&lt;br /&gt;gdalwarp 16*/*dem elev.tif&lt;br /&gt;gdaladdo -r average elev.tif 2 4 8 16 32&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The overviews are probably not necessary for such a tiny database, but it's recommended anyway. We have to fix the feet / meters problem:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;gdal_translate -scale 0 1.0 0 0.3048 elev.tif elev-meters.tif&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Next, fix up the map borders. The maps are encoded using index color, which doesn't doesn't work well with fancy interpolation methods, so expand them into RGB:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;for i in carter-dome.tif jackson.tif stairs.tif k44071c3/k44071c3.tif ; do&lt;br /&gt; gdal_translate -expand rgb $i ${i%.tif}-rgb.tif&lt;br /&gt; done&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;and then use &lt;code&gt;gdalwarp&lt;/code&gt; to reproject and trim. For example:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;gdalwarp -t_srs "WGS84" -te -71.25 44.25 -71.125 44.375 \&lt;br /&gt; -r cubicspline carter-dome.tif carter-dome-trim.tif&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Build overviews:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;for i in carter-dome-trim.tif crawford-trim.tif jackson-trim.tif \&lt;br /&gt;stairs-trim.tif k44071c3/k44071c3-trim.tif ;do&lt;br /&gt;gdaladdo -r average $i 2 4 8 16 32;&lt;br /&gt;done&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Finally, run &lt;code&gt;osgdem&lt;/code&gt;:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;osgdem --TERRAIN --geocentric -d elev-meters.tif -t carter-dome-trim.tif \&lt;br /&gt;-t crawford-trim.tif -t jackson-trim.tif -t stairs-trim.tif \&lt;br /&gt;-t k44071c3/k44071c3-trim.tif -l 8 -o wash.ive&lt;br /&gt;&lt;code&gt;&lt;br /&gt;and have fun!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_jaEJ-2dqK4U/S2hdE8wS5zI/AAAAAAAAAAc/f4n0mIDEpZ0/s1600-h/wash3-shot.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 200px;" src="http://4.bp.blogspot.com/_jaEJ-2dqK4U/S2hdE8wS5zI/AAAAAAAAAAc/f4n0mIDEpZ0/s320/wash3-shot.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5433695290032056114" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-605512388935050566?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/605512388935050566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=605512388935050566' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/605512388935050566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/605512388935050566'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2010/02/ive-been-playing-with.html' title='Fun with VirtualPlanetBuilder'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_jaEJ-2dqK4U/S2hcTVoV0ZI/AAAAAAAAAAM/IUWlZ0gtH-o/s72-c/wash-shot.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-1160887254829836562</id><published>2007-12-15T01:07:00.000-08:00</published><updated>2007-12-15T01:23:10.245-08:00</updated><title type='text'>Dead blog?</title><content type='html'>I suppose a year-and-a-half without an update qualifies as a dead blog. I've even dropped off the blog roll at &lt;a href="http://planet.lisp.org/"&gt;Planet Lisp&lt;/a&gt; due to inactivity. Sniff.&lt;br /&gt;&lt;br /&gt;Anyway, I've been busy in that time. I've joined &lt;a href="http://redhat.com"&gt;RedHat&lt;/a&gt; where I'm working on the &lt;a href="http://sourceware.org/frysk/"&gt;Frysk&lt;/a&gt; debugger/system profiler tool. It's all written in Java, which is an interesting experience for this old Lisper. We're using compiled Java via gcj, which gives you the worst of both worlds: you're stuck writing in Java, but you don't have the rapid turn-around advantages of a byte-coded language. Oh well. Compilation is getting faster as gcj adapts ecj and other Java compiler technology. Otherwise the project is a lot of fun and has to deal with many thorny, low-level issues. Smart colleagues are a requirement for a good job experience, and RedHat sure has 'em.&lt;br /&gt;&lt;br /&gt;I've been indulging my old passion for real-time computer projects in a big way. I've made some contributions to &lt;a href="http://www.openscenegraph.org"&gt;Open Scene Graph&lt;/a&gt;, and I have become a committer on the &lt;a href="http://flightgear.org"&gt;FlightGear&lt;/a&gt; flight simulator project. Why waste time flying around in Microsoft Flight Simulator when you could be coding?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-1160887254829836562?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/1160887254829836562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=1160887254829836562' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/1160887254829836562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/1160887254829836562'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2007/12/dead-blog.html' title='Dead blog?'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-114665108150315372</id><published>2006-05-03T02:56:00.000-07:00</published><updated>2006-05-03T05:21:52.426-07:00</updated><title type='text'>Macro Madness</title><content type='html'>&lt;p&gt;The macros -- and madness -- I'm referring to today have little to do with Lisp, except as a cautionary tale. No, I'm talking about TeX and LaTeX, the other major language famous for its macros. I format my &lt;a href="http://www.bricoworks.com/moore/res.pdf"&gt;English résumé&lt;/a&gt; and &lt;a href="http://www.bricoworks.com/moore/cv.pdf"&gt;French C.V.&lt;/a&gt; using a motley collection of LaTeX packages that I've found over the years. The English version uses resume.sty, originally by Stephen Gildea, and dates from 1988! The French one uses &lt;a href="http://www.lrde.epita.fr/~didier/"&gt;Didier Varna's&lt;/a&gt; &lt;a href="http://www.lrde.epita.fr/~didier/software.php"&gt;CurVe&lt;/a&gt;package which, I've found, does a good job of outputting a C.V. in a French / European style. His C.V. is a lot sexier than mine, but one has to start somewhere.&lt;br /&gt;&lt;p&gt;The style I adapted (i.e., copied) from Didier puts the years of an activity in the margin of an entry, bold faces the job title and company, puts the city in normal type in parentheses, and starts right in with the description. A consulting company asked me for my C.V. in a different format: months and years of dates (not in the margin), company and city in bold, job title on the next line, followed by the job description in bullet points. For this long-time TeX amateur it seems vastly preferable to conditionalize this somehow rather than keeping two different version of a document around. In terms of CurVe, I need the prologue of each entry to expand differently in each version and do something about establishing a list environment for the consulting version. Given this input from my wrapper macro:&lt;br /&gt;  &lt;code&gt;&lt;br /&gt;  \Entry{août 1999}{août 2001}{Software Design Engineer}{Amazon.com}{Seattle&lt;br /&gt;    WA, États-Unis}{blah blah}  &lt;br /&gt;  &lt;/code&gt;&lt;br /&gt;  I want:&lt;br /&gt;  &lt;code&gt;&lt;br /&gt;  \entry[1999 -- 2001]{\textbf{Software Design Engineer, Amazon.com}&lt;br /&gt;    (Seattle WA, États-Unis)}{blah blah}&lt;br /&gt;  &lt;/code&gt;&lt;br /&gt;  in the regular version and:&lt;br /&gt;  &lt;code&gt;&lt;br /&gt;  \entry{\textbf{août 1999 -- août 2001 Amazon.com, Seattle WA, États-Unis}\par%&lt;br /&gt;    \textbf{Software Design Engineer:} blah blah}&lt;br /&gt;  &lt;/code&gt;&lt;br /&gt;  in the consulting version. This doesn't seem too bad, but there are two big complications:&lt;br /&gt;  &lt;ul&gt;&lt;br /&gt;    &lt;li&gt;If the years of the date are the same, I only want one year in the margin of the regular version;&lt;br /&gt;    &lt;li&gt;I want to be able to write &lt;code&gt;\now&lt;/code&gt; instead of a date and get "présent".&lt;br /&gt;  &lt;/ul&gt;&lt;br /&gt;  Furthermore, I wanted to save some typing and write dates like "août 2001" and not as parameters to a macro like &lt;code&gt;\date{août}{2001}&lt;/code&gt; or, worse, as separate parameters to the &lt;code&gt;\Entry&lt;/code&gt; macro. This is one of those little decisions that, in retrospect, are incredibly stupid and lead to disaster or, at best, a lot more work, but otherwise I wouldn't have anything to write about today.&lt;br /&gt;&lt;p&gt;Like good Lisp programmers we'll attack this in a top-down and bottom-up manner at the same time. Assuming an &lt;code&gt;\ifcvstyle&lt;/code&gt; conditional that chooses between the two styles, the LaTeX code I wrote above suggests these definitions: &lt;br /&gt; &lt;code&gt;&lt;br /&gt;\ifcvstyle%&lt;br /&gt;\newcommand{\Entry}[6]{%&lt;br /&gt;  \entry[\@years{#1}{#2}]{\textbf{#3, #4} (#5) #6}}%&lt;br /&gt;\def\@@cvdate#1 #2\relax{#2}&lt;br /&gt;\else%&lt;br /&gt;\newcommand{\Entry}[6]{\entry{\textbf{#1 -- #2 #4, #5}\par\textbf{#3:} #6}}&lt;br /&gt;\def\@@cvdate#1 #2\relax{#1 #2}&lt;br /&gt;\fi&lt;br /&gt;\newcommand\@years[2]{\ifthenelse{\equal{\cvdate{#1}}{\cvdate{#2}}}{%&lt;br /&gt;  \cvdate{#1}}{%&lt;br /&gt;  \cvdate{#1} -- \cvdate{#2}}}&lt;br /&gt;\newcommand\cvdate[1]{\@cvdate#1\relax}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;\ifthenelse&lt;/code&gt; is LaTeX's all-purpose conditional macro; here we use it to compare two strings because plain TeX can't do that itself. OK, this isn't too bad; we can choose the basic form of the parameters to &lt;code&gt;\entry&lt;/code&gt; and pick apart the parts of the date using TeX's powerful if bizarre macro parsing capabilities. But what about &lt;code&gt;\@date&lt;/code&gt;, which we haven't defined yet? That submacro checks if the date argument is equal to &lt;code&gt;\now&lt;/code&gt; and either returns that or proceeds with the date parsing.&lt;br /&gt;&lt;p&gt;My first try at &lt;code&gt;\@date&lt;/code&gt; was something like:&lt;br /&gt;  &lt;code&gt;&lt;br /&gt;  \newcommand\@cvdate[1]{\ifthenelse{\equal{#1}{\now}}{#1}{\@@cvdate#1}}%&lt;br /&gt;  &lt;/code&gt;&lt;br /&gt;  The intent is to look at the first "token" (basically, character or control sequence beginning with backslash); if it is &lt;code&gt;\now&lt;/code&gt;, just use that, otherwise put the token back and let &lt;code&gt;\@@cvdate&lt;/code&gt; go to town. But this exploded in some cryptic way. We have to enter the shady world of TeX "expandability" to understand why.&lt;br /&gt;&lt;p&gt;It's somewhat obvious that TeX macro definitions are simply templates into which parameters are substituted, although of course these templates can contain arbitrarily complicated code. In the course of this template substitution, called "expansion" (duh), some evaluation can take place; for example, primitive conditionals such as our &lt;code&gt;\ifcvstyle&lt;/code&gt; can be evaluated and expanded. But many, many things in TeX can not be, such as definitions made with &lt;code&gt;\def&lt;/code&gt;, and assignments to registers, things that complex macros invariably do. A macro is said to be expandable if it produces its intended result only through expansion. Many macros require their parameters to be expandable because they pick apart the results through various clever tricks. So, back to &lt;code&gt;\ifthenelse&lt;/code&gt;: it is an extremely complicated macro that is not expandable, but the arguments passed to the predicate in its test part must be! Our &lt;code&gt;\@cvsdate&lt;/code&gt; is used in &lt;code&gt;\@years&lt;/code&gt; in the test of an &lt;code&gt;\ifthenelse&lt;/code&gt; and therefore needs to be expandable. Oh well, can't use &lt;code&gt;\ifthenelse&lt;/code&gt;.&lt;br /&gt;&lt;p&gt;TeX's primitive conditionals are expandable, so let's try again:&lt;br /&gt;  &lt;code&gt;&lt;br /&gt;  \def\@cvdate#1{\ifx#1\now\now\else\@@cvdate#1\fi}  &lt;br /&gt;  &lt;/code&gt;&lt;br /&gt;  &lt;code&gt;\ifx&lt;/code&gt; compares characters or tokens and expands them, so it will work fine. This seems like it should work, but it doesn't. Aargh! After using TeX's &lt;code&gt;\tracingmacros&lt;/code&gt; feature, which, compared to Lisp's &lt;code&gt;macroexpand&lt;/code&gt;, sucks, it becomes clear that the &lt;code&gt;\fi&lt;/code&gt; token that should end the conditional is sucked into &lt;code&gt;\@@cvdate&lt;/code&gt; as part of the parameters. WTF? It turns out that when TeX expands a conditional it doesn't just replace it with the tokens in the appropriate branch and proceed; instead it skips the unsuccessful branch and starts expanding the taken branch, eventually noticing the ending &lt;code&gt;\else&lt;/code&gt; or &lt;code&gt;\fi&lt;/code&gt; token and discarding it. But it can't notice this token at the time it is gathering tokens for the argument of a macro, because it ignores the meaning of most tokens at that time... are we totally screwed?&lt;br /&gt;&lt;p&gt;No, there's a TeX idiom for handling this situation, using the somewhat bizarre &lt;code&gt;\expandafter&lt;/code&gt; primitive. &lt;code&gt;\expandafter&lt;/code&gt; reads one token without expanding it, then reads the next and expands it (which could consume other tokens if it takes arguments), then puts the first token in front of that expansion and carries on. This sounds promising: we want TeX to find the end if the conditional without beginning the expansion of &lt;code&gt;\@@cvdate&lt;/code&gt;. Here's the final version of &lt;code&gt;\@cvdate&lt;/code&gt;:&lt;br /&gt;  &lt;code&gt;&lt;br /&gt;  \def\@cvdate#1{\ifx#1\now\now\else\expandafter\@@cvdate\expandafter#1\fi}&lt;br /&gt;  &lt;/code&gt;&lt;br /&gt;  Note the double use of &lt;code&gt;\expandafter&lt;/code&gt;. We have two tokens to save up and put after the end of the &lt;code&gt;\ifx&lt;/code&gt;; you can chain together uses of &lt;code&gt;\expandafter&lt;/code&gt; to save up multiple tokens like this.&lt;br /&gt;&lt;p&gt;To Lisp hackers this is absolute brain damage. We could just gloat about the superiority of our macro system, but that would miss the point.  The TeX macro language is designed to be usable by authors, not necessarily technical, with a syntax that seems "natural." That's why TeX supports complex parsing of arguments, as in our &lt;code&gt;\@@cvdate&lt;/code&gt; macro. Since most of the world now uses LaTeX that has a much more regular macro syntax by convention this power is now wasted on end users, but at least the thought is there. Furthermore, there is a balance between writing simple substitution abbreviations and macros, which is easy in TeX, and more complicated packages that are likely to be written by motivated hackers that will invest the time to learn all the obscure incantations. And some novice macro writers will inevitably be sucked into the second category... Finally, it must be remembered that TeX was developed 25 years ago on machines that were incredibly puny by today's standards, so perhaps the strict separation between expansion and evaluation made sense. And, the objective is to put glyphs on paper, not write cool programs: yet another design constraint.&lt;br /&gt;&lt;p&gt;I don't know if ultimately I saved any time with all this macrology, but I did learn something about TeX and macros in general. If you were going to write a Lispy typesetting program with an expansion mechanism that didn't suck, what would you do?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-114665108150315372?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/114665108150315372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=114665108150315372' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/114665108150315372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/114665108150315372'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2006/05/macro-madness.html' title='Macro Madness'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-114090656402747169</id><published>2006-02-25T13:08:00.000-08:00</published><updated>2006-02-25T14:29:25.753-08:00</updated><title type='text'>Names Aren't Forever</title><content type='html'>Dan Barlow &lt;a href="http://ww.telent.net/diary/2006/2/#24.2759"&gt;refers&lt;/a&gt; to an &lt;a href="http://cybertiggyr.com/gene/80-closminded/"&gt;article&lt;/a&gt; I wrote once on naming CLOS slot accessors, so I had better respond. Dan notes that choosing the name of a slot accessor or generic function is somewhat commiting because the name is used more globally than in other languages like e.g., Perl where a "slot name" is quite local. Xach &lt;a href="http://xach.livejournal.com/71341.html"&gt;responds&lt;/a&gt; that if you don't like a name, you can always change it later. I basically agree with this, but I want to point out that in large programs it may be difficult with text-based search-and-replace to make sure you're changing all -- and only -- what you need. Here our Java and Smalltalk friends are ahead with all the refactoring bells and whistles that come with &lt;a href="www.eclipse.org"&gt;integrated environments&lt;/a&gt; these days. &lt;a href="http://common-lisp.net/project/slime/"&gt;Slime&lt;/a&gt;, the preferred environment for Lisp programming in GNU Emacs, doesn't even have a notion of all the files in a system. It does do a pretty good job of tracking the home package of symbols in a Lisp source file, based on the &lt;code&gt;in-package&lt;/code&gt; forms in the file. It would be a cool hack to write a &lt;code&gt;rename-symbol-in-system&lt;/code&gt; elisp function that visits all the files in an &lt;a href="http://www.cliki.net/asdf"&gt;ASDF&lt;/a&gt; system, searches for a symbol and renames it if it's the symbol we care about i.e., in the right package. I call on my minions to make it so!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-114090656402747169?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/114090656402747169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=114090656402747169' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/114090656402747169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/114090656402747169'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2006/02/names-arent-forever.html' title='Names Aren&apos;t Forever'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-113879860887282525</id><published>2006-02-01T03:08:00.000-08:00</published><updated>2006-02-01T07:18:17.416-08:00</updated><title type='text'>Dark Teapots</title><content type='html'>Once I had a Common Lisp / OpenGL interface working in &lt;a href="http://common-lisp.net/project/glouton"&gt;glouton&lt;/a&gt;, I of course wanted to render the classic computer graphics model, the &lt;a href="http://www.sjbaker.org/teapot/"&gt;Utah Teapot&lt;/a&gt;. Glut has a glutSolidTeapot function, so I slavishly translated the C code from  &lt;a href="http://www.mesa3d.org/"&gt;Mesa&lt;/a&gt;, which defines a big array of Bezier surfaces and uses OpenGL evaluator functions to render them, into Lisp and let 'er rip.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bricoworks.com/moore/dark.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 378px;" src="http://www.bricoworks.com/moore/dark.png" border="0" alt="" /&gt;&lt;/a&gt;And got this interesting image. You can make out the murky outline of teapot if you squint hard. What's going wrong? With new teapot code, a new &lt;a href="http://common-lisp.net/project/cffi"&gt;foreign function interface&lt;/a&gt; for the OpenGL bindings, running in Lisp, rather a lot could be going wrong. And I spent an embarrassingly long time chasing down various blind alleys until I did what I should have done first: read the man page for &lt;a href="http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/glutSolidTeapot.3.html"&gt;glutSolidTeapot&lt;/a&gt; (in my defense, I was on vacation without a broad-band connection, so googling wasn't my first instinct). Hey look, there's a big "Bugs" section!.&lt;br /&gt;&lt;br /&gt;It turns out that we're looking at the inside surfaces of the teapot. Because their surface normals point away from the light source behind the viewer's head they are very dark. But those surfaces are supposed to be culled, and furthermore, the front surfaces of the teapot should not be! OpenGL can use the order of a polygon's vertices to decide if a polygon is facing away from the eye point and can be discarded. By default the order is assumed to be counterclockwise. If we turn off back-face culling we get a normal image, but that's not a happy state of affairs. In order to display the Glut teapot, according to the man page, you must change the vertex order to clockwise with &lt;code&gt;(glFrontFace GL_CW)&lt;/code&gt; and then everything's happy. Fair enough, but why?&lt;br /&gt;&lt;br /&gt;There's an unfortunate interaction between the OpenGL functions for evaluating Bezier meshes and the "quad strip" primitives that they use to display the approximation of the mesh on the screen. The quad strip looks like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bricoworks.com/moore/quad-strip.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 408px;" src="http://www.bricoworks.com/moore/quad-strip.png" border="0" alt="" /&gt;&lt;/a&gt;That is, the vertices v0, v1, v2, v3, v4, ... are fed to OpenGL using glVertexf and the quads are drawn using the vertex order given by the arrow, which in this image is counterclockwise, making these quads front-facing. Now, the mesh produced by OpenGL for a Bezier surface might look like this (sorry for the lame diagram!):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bricoworks.com/moore/mesh.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 223px;" src="http://www.bricoworks.com/moore/mesh.png" border="0" alt="" /&gt;&lt;/a&gt; u and v are the parameters of the mesh and increase in the directions of the arrows. The glEvalMesh2 function proceeds in the u direction of the mesh creating quad strips. That is, if we start at u = 0 v = 0 (do I need MathML here?), then the first few coordinates of the first quad strip will be (0,0), (0,dv),(du,0),(du, dv),(2du,0),(2du,dv),... and then another strip will be started at (0,dv). But look again at the diagram of quad strips above; this vertex order produces quads that are facing away from the viewer! We can't reorder the points and put the origin of the mesh parameters at another corner of the mesh because the same thing can happen. We could try to swap u and v, but that causes another, worse problem: we're relying on the evaluator to generate surface normals for us, and the normal direction is defined by the cross product of du and dv on the mesh. The right-hand rule rules here; if we swap u and v, the normals will point away from us, which is also not good. Are we doomed to live with this cheesy clockwise order?&lt;br /&gt;&lt;br /&gt;Well, no. Actually we don't have to evaluate the mesh from 0 to 1 in u in v: the glMap2f function takes arguments for the start and end values of u and v. If we evaluate v from 1 to 0: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(loop&lt;br /&gt; with u-order = (u-order patch)&lt;br /&gt; and v-order = (v-order patch)&lt;br /&gt; for patch-list in (patches patch)&lt;br /&gt; do (loop&lt;br /&gt;     for patch in patch-list&lt;br /&gt;     do (glMap2f GL_MAP2_VERTEX_3 0.0 1.0 3 u-order 1.0 0.0 12 v-order&lt;br /&gt;                 patch)&lt;br /&gt;        (glEvalMesh2 type 0 grid 0 grid)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;then the vertices in the quad strips define quads with the proper orientation:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.bricoworks.com/moore/teapot.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 350px;" src="http://www.bricoworks.com/moore/teapot.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Yay! We have our teapot.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-113879860887282525?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/113879860887282525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=113879860887282525' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/113879860887282525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/113879860887282525'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2006/02/dark-teapots.html' title='Dark Teapots'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-21382508.post-113801643882524900</id><published>2006-01-23T03:20:00.000-08:00</published><updated>2006-01-23T05:07:31.283-08:00</updated><title type='text'>Munching on OpenGL in Common Lisp</title><content type='html'>First post! I wonder if those are the most common words in the first post to a blog.  I'm going to skip the introductions and instead describe something I'm working on. Well, more like "hacking on" in the best sense of those words.&lt;br /&gt;&lt;br /&gt;I've written a package called "glouton" (which means "glutton" in French; can't resist including "g" and "l" with a little cross-language action!) to do some OpenGL programming in Common Lisp. Now, if you believe what you read on comp.lang.lisp this is trivial, many bindings already exist, you can write your own bindings in an hour, etc. Whatever. I know about the &lt;a href="http://www.ii.uib.no/%7Eknute/lisp/lisp.html"&gt;"nameless bindings"&lt;/a&gt;&lt;br /&gt;of  Knut Arild Erstad, but they don't have a free license. I looked at SDL, concluded (possibly in error) that the Lisp OpenGL bindings weren't very complete, and moved on. But for me, the deal breaker in existing OpenGL bindings is that they don't work with &lt;a href="http://www.cliki.net/CLX"&gt;CLX &lt;/a&gt;, the defacto X Windows library for Common Lisp. CLX doesn't use the C Xlib library at all; it opens a socket and makes protocol requests directly to the X server. OpenGL and GLX, on the other hand, use a combination of exchanges with the server via Xlib's connection and, in the sexiest implementations, direct manipulation of the graphics hardware, called "direct rendering." I'd really like to support direct rendering while still using CLX event handling and X requests if at all possible.&lt;br /&gt;&lt;br /&gt;It turns out that a hack is possible. The X server returns integer IDs for all interesting resources to its clients; these IDs are valid across different  connections to the X server, or even in different clients. So we can create two connections to the server, one through CLX and one using Xlib, create the window using one or the other, create a GLX context and make in current in Xlib, then set the event mask in CLX and get events for it in the CLX-based event loop. Some synchronization is necessary between the two connections, particularly after a &lt;span style="font-family:courier new;"&gt;:configure-notify&lt;/span&gt; event; it seems like you need to call XPending() or something on the Xlib connection in order to notify the GLX client side of a reconfiguration of the frame buffer size. This was all more-or-less working on a Macintosh PowerBook, in my first try, currently &lt;a href="http://common-lisp.net/project/glouton/"&gt;here.&lt;/a&gt;&lt;br /&gt;And then I bought a laptop with an Nvidia graphics card, and things stopped working...&lt;br /&gt;&lt;br /&gt;I was creating the window in CLX, which was quite easy, but the results I was now seeing were very flakey: sometimes an image would appear, sometimes it wouldn't sometimes it appear only after a few mouse clicks or resizes. I googled around to no great effect, finally finding a clue that all GLX objects have to exist in the same address space. Well, that doesn't really apply here, but I changed things around to create the window in Xlib (more involved), then look up the window in CLX and set an event mask for it to get events. TaDa! There'll be some pretty pictures up here in a later post.&lt;br /&gt;&lt;br /&gt;At some point I'd like to dig into the sources for GLX and the drivers to see what's going on for real, but that's a project for another day. I hope this hack is portable and will continue to work!&lt;br /&gt;&lt;br /&gt;Incidently, I first saw the two connection trick in code Gilbert Baumann wrote to interface &lt;a href="http://common-lisp.net/project/mcclim/"&gt;McCLIM&lt;/a&gt; to &lt;a href="http://cairographics.org/introduction"&gt;Cairo.&lt;/a&gt; Mad props also to &lt;a href="http://common-lisp.net/project/cffi/"&gt;cffi,&lt;/a&gt; which is a really solid portable foreign function interface package.&lt;br /&gt;&lt;a href="http://common-lisp.net/project/glouton/"&gt;&lt;span class="" style="display: block;" id="formatbar_CreateLink" title="Link" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/21382508-113801643882524900?l=shiny-dynamics.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shiny-dynamics.blogspot.com/feeds/113801643882524900/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=21382508&amp;postID=113801643882524900' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/113801643882524900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/21382508/posts/default/113801643882524900'/><link rel='alternate' type='text/html' href='http://shiny-dynamics.blogspot.com/2006/01/munching-on-opengl-in-common-lisp.html' title='Munching on OpenGL in Common Lisp'/><author><name>Tim Moore</name><uri>http://www.blogger.com/profile/09629429704217731021</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry></feed>
