Very generally speaking, the way I do autogeneration is from a broad description to a more specific description. You can have as many layers as you need along the way, in the end you've got to have pixels. This is really just the same thing as multilayered abstraction and it's basically what computers do, period.
@p
Anyhow, one of the lower level abstraction layers is that of a "renderable". This is just a description of cubes, planes, effects, animations, and so forth to be fed to the rendering engine which is in C++. So this represents the lowest level, roughly, that I go to while in Lua (remember that Texas is mostly made in Lua, with a core engine in C++).
@p
Renderables can operate on each other, so you can wrap one particular renderable (say a bathtub) in a reflection effect (for the porcelain). Or you can wrap another (say a windmill) in an animation (spinning); you could even wrap the whole thing again to have a reflecting, spinning windmill. It's actually not that complicated once you get the idea.
@p
The beauty and simplicity of renderables is that they don't have very much context, really. They are ultimately going to represent unknown sets of GL (drawing) commands to be sent to the graphics card together with a bit of local context (i.e., specific to each renderable so it is opaque) and an update (T) function.
@p
Sometimes you need a little more context. Normally, you want to avoid additional context. You actually want to keep things loose, and intentionally *NOT* care how big something is, for instance, or whether it's an effect or an object or whatnot. You can still have code internally that sorts this out, but when you're generating these things, you ordinarily just want to know that you've got yourself a Renderable, and not worry beyond that.
@p
Which brings us to my current situation. The one bit of context that is useful, the "next most basic bit" of context as it were, is spatial context. Not in terms of position, but in terms of size. So we'd like to know, not just that this is a Renderable, but this is a Renderable that "somehow fits" into a given 2D (L, W) space. When I call this context, what I mean is that it's public context. So think of this as an AreaFiller, not just a Renderable, because it "fills" a given area which you pass in. When we want to "draw" an AreaFiller, it not only needs it's own local opaque context, but also (L, W) context to passed in by the user class. When we "draw" an AreaFiller we're actually producing simple renderables.
@p
Here are examples of some AreaFillers:
@p
1. Books. We can create a books areafiller by describing the properties of the books it will fill. We specify everything about the size and shape of the books, including their overall height. We could conceivably specify a number of books, as well, but more likely we would specify a "density" factor.
@p
2. Towels. Sort of like books, but laying down. We'd specify the average width of a towel, how many tall they could stack, and so forth.
@p
3. Trinkets. We could specify a big list of renderables (or, functions generating renderables), along with some way to change their sizes slightly.
@p
You've now created your AreaFiller, let's use it. Let's create a shelf renderable. Pass in the dimensions of the shelves, how many there are, the type of wood to make it of, thickness of the boards, that sort of thing. Also pass in an AreaFiller. What areafiller? It doesn't matter. The shelf can use the AreaFiller to put things on itself; the shelf when generating knows the (L, W) context of each individual shelves. Because AreaFiller defines only areametric space, not location context, we can also place the objects wherever we want.
@p
Voila, we've now separated shelves from their contents, making it mix-and-matchable. Better yet, when we create a table we can also use AreaFillers to put trinkets, towels or books on it. Hopefully you get the picture. These kind of things are actually my deepest, hardest won secrets of autogeneration.
2008-08-15