Older blog entries for ingvar (starting at number 172)

As some people may have noticed, *.hexapodia.net is down (dud powersupply, looks like).

As some others may have noticed, I am more-or-less in comms withdrawal, for a variety of reasons. Communications will be kept short. Emails may get read but will probably not be answered.

Hermitage in modern society is suprisingly hard work.

The last few weeks, I have spent almost 15 hours of coding towards my latest project (it's not anywhere near done, but it's a basic tank game where you zoom around a grid, and (hopefully) shoot at geometric forms). It's now at a stage where the constant move works and there's some steering (that's a definite advantage compared with the state-of-play when I sat down for this session, feeling a bit odd not coding too-early in the morning).

I have, today, fixed a couple of clipping bugs and optimised the clipping heavily (I start with clipping in 3D, in "camera space", to the view frustrum; I then clip in screen-space, using essentially the Bresenham line-drawing algorithm to fine-nudge things to within screen-space). I use the clipping for two distinct applications, one is in the "draw the grid" that spawned the 3D clipping and the other is in the "draw a geometric solid". Right now, there's only a few things being rendered in the screen update. A new grid (obviously), a radar screen, an aiming reticule and any geometric solid that happens to be in view.

Right now, I'm not using any 3D acceleration, instead preferring to do everything in code I've written, running on the main CPU. It seems my elderly AMD K6 is sufficient to provide a mostly jerk-free animation (though I am cheating and only doing 10 updates per second), even with apache, squid and friends running. "Go, go 233 MHz power!".

As usual, all of the code is written in CL, using CLX for the output layer. Next is writing more utility functions for creating solids (the code currently knows of triangular-base pyramids and six-sided solids with four-corner sides). I use what I thought a neat solution for handling the geometric objects.

Each type of geometric shape is a class. When they're defined (using a solid-defining macro), I say how many corners they have, provide an exhaustive list of their sides, mapping each corner of a side to one corner of the solid, then say how many of the sides can be displayed. This means I will need to order the sides to bottoms and (possibly) tops won't get listed, since there's no change in height for the camera. All vertex and side storage is done in vectors, for reasons that will, I guess become apparent.

The shape-defining macro also defines a whole bunch of methods. One method for each side, specialised on the shape and the number of the side. However, the base "draw solid on screen" routine is even simpler.

(defmethod draw-shape ((shape volume))
  (let ((max (min (to-show shape) (length (sides shape)))))
    (update-cam-vertexes shape)
    (let ((sides (sort (loop for n from 0 below max
			     append (find-side shape n))
		       #'>
		       :key 'y-average)))
      (loop for side in sides
	   do (draw-shape side)))))

This first computes a camera-space value for each vertex and caches it. It then builds a list of sides for the solid, sorted with the farthest first (I, possibly badly, chose a right-hand coordinate system with the Y axis pointing straight out of the camera), then all the individual sides are drawn (by computing a list of all the corners in camera space and first doing an XLIB:DRAW-LINES with a "fill in white" option and then doing it again with black, now only drawing lines.

There's some culling in the side DRAW-SHAPE method (if none of the corners are visible, we're done; if all the corners are visible, we can skip clipping; otherwise, build a list of corners where there is at least one clipping). It seems pretty quick now, though tere's no "100s of objects" and we'll see what happens then.

"Oooops!". I just realised I should probably re-order the list of objects to display instead of hoping to blind luck that things are drawn from far away and then closer.

Just in case someone has a problem downloading stuff from my source repository... I use a fairly agressive method for dealing with assorted scanning to my machine. The scanning IP (or netblock, if no reverse DNS or incorrect reverse DNS is available) gets routed to 127.0.0.1. At the moment, there's 138 entries matching this.

I haven't had a chance to look at lispg since before New Year's Eve, since there was a bit of a flu, followed by some floor-fixing, followed by some well-needed relaxation (when replacing some carpet with laminate flooring ends up with replacing floor joists, it takes time).

Other, long-range, coding is proceeding at some sort of pace.

So, an approximation of development time. Apparently, I started the coding on 2005-11-06. I usually code for max 1h a day (between 06:00 and 07:30, interspersed with assorted web browsing, solitaire-type games, morning necessities and cat-feeding), 5 days a week. This gives us an approximate 5h per week and from then to now is about 9 weeks. However, for at least two weeks of those, I did no coding. So the code as-is represents a bit short of a man-week of work. I think my optimistic estimate of "about a man-week" isn't too bad, for an off-the-cuff guess.

"Ooops!"

Seems I packaged things up a smidgen too early. Test-compilation with SBCL on the linux side of things throws up a whole lot of errors that didn't show up with lispworks on the Windows side of things. Expect a new packaging soo.

Just had a read through this (Dave Roberts' survey of and proposal for CL socket API(s)). One thing did tickle my sense of what is and what isn't proper (and probably betrays my roots in C, or similar).

As a footnote to SB-BSD-SOCKET's support for UDP it is mentioned:

In SB-BSD-SOCKETS, each write to a stream associated with a datagram socket is converted to an individual UDP datagram. Note that this may be out of date with very recent SBCL changes.

Now, since this is mentioned, I would expect it to NOT be the case for any of the other implementations surveyed. But to my mind, the very definition of a datagram transport is taht it doesn't provide a stream interface but rather provides a "If there is one or more datagrams available, a read returns exactly one datagarm" and "each write sends a datagram" service. This means that I would've preferred seeing footnotes on all other implementations, signifying that they were behaving oddly and counter-intuitively.

But, as usual, I guess it's just me.

28 Dec 2005 (updated 29 Dec 2005 at 13:21 UTC) »

So, it's nearing the end of the year. Things aren't as advanced as they should be. However, I feel that the world is better served by letting people lambast me for my bad code than I do this in solitude.

I present a non-production-ready framework for compiling (carefully restricted) shader code in lisp to (for now) GLSL. It's available here. If you expect something that's plug and play, don't bother. It doesn't even tie in to OpenGL at the moment (mostly because I haven't managed to get any of my development environments to successfully interoperate with OpenGL).

There's a fair few lessons to learn from this.

  1. Just because it's not complicated doesn't mean it's easy.
  2. It's usually handy having a rough idea of what something entails before embarking on it. I would've saved myself at least 2-3 rewrites if I'd only had a vague grasp of shaders before sprining forth. Good method of learning, though.
  3. It's hard to hack when a cousin-in-law is crashing in the hacking room.
  4. Fixing the plumbing is a higher priority than writing code.

I hope no one kept their breath held for two weeks? I'm aiming at purchasing some literature pertaining to lispg during next week. At that point, there should be some more sensible code happening.

Mangled packaging around a bit. I fear there will have to be multiple ASDF system definitions shipped. One for lispg itself and one for each backend. There might, possibly, in the future, be an even cleaner separation between things (though at the moment, I'm semi-favouring a nasty-nest-of-symlinks).

Other than that, nothing new. I may start soliciting external input sometime next week, though I wouldn't hold my breath.

OK, so everyone esle is harping about how Reddit changed from one implementation language to another. So what? They did a careful analysis of what they had, weighed that against what they thought they'd gain and the cost of getting from before to after. The estimated effort was less than the estimated gain, so they did it. Good for them, I say.

Meanwhile, in Lispland, there's more "utility glue":

LISPGRAPHICS> (defvert test-shader (a b) 
		(declare (ftype (function (fixnum fixnum) fixnum) test-shader))
		(return (sin (+ a b))))
TEST-SHADER
LISPGRAPHICS> (emit-code t :opengl (find-shader 'test-shader))
int testShader (int A,int B)
{
  return sin((a+b));
}
NIL
LISPGRAPHICS> (run-shader 'test-shader pi 0)
1.2246063538223773E-16

Stringification of symbols now changed (instead of starting capitalized, we check what package they live in and if they're tagged as being in the "opengl-glue" package we capitalize and prefix with "gl_", previously we always capitalised and prefixed with "gl_" if needed).

Type declarations for backends now in place. Still looking at getting a whole lot of "run code in lisp" glue in (quite a few of the OpenGL functions are suitably variadic and will thus need shadowing so we use internal functions instead of CL functions, since (sin #(3.0 0.1 1.0)) will cause a problem).

163 older entries...

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!