Saturday, February 25, 2006

Names Aren't Forever

Dan Barlow refers to an article 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 responds 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 integrated environments these days. Slime, 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 in-package forms in the file. It would be a cool hack to write a rename-symbol-in-system elisp function that visits all the files in an ASDF 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!

Wednesday, February 01, 2006

Dark Teapots

Once I had a Common Lisp / OpenGL interface working in glouton, I of course wanted to render the classic computer graphics model, the Utah Teapot. Glut has a glutSolidTeapot function, so I slavishly translated the C code from Mesa, which defines a big array of Bezier surfaces and uses OpenGL evaluator functions to render them, into Lisp and let 'er rip.

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 foreign function interface 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 glutSolidTeapot (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!.

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 (glFrontFace GL_CW) and then everything's happy. Fair enough, but why?

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:
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!):

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?

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:

(loop
with u-order = (u-order patch)
and v-order = (v-order patch)
for patch-list in (patches patch)
do (loop
for patch in patch-list
do (glMap2f GL_MAP2_VERTEX_3 0.0 1.0 3 u-order 1.0 0.0 12 v-order
patch)
(glEvalMesh2 type 0 grid 0 grid)))

then the vertices in the quad strips define quads with the proper orientation:



Yay! We have our teapot.

Monday, January 23, 2006

Munching on OpenGL in Common Lisp

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.

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 "nameless bindings"
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 CLX , 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.

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 :configure-notify 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 here.
And then I bought a laptop with an Nvidia graphics card, and things stopped working...

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.

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!

Incidently, I first saw the two connection trick in code Gilbert Baumann wrote to interface McCLIM to Cairo. Mad props also to cffi, which is a really solid portable foreign function interface package.