-*- outline -*- *Events - maintain a thread which polls for SDL events and dresses them in Smalltalk clothing - pass them on the gesture recogniser, which then does hit testing and invokes handlers on widgets - widgets have their own threads in which to respond to events *Object model **World The world has a distinguished camera and a surface to draw to. **Cameras A camera has a view transform and something that it's looking at (a layer). (It might have several layers, so there's some aspect of z-order.) It also has a "glass" layer for things that aren't transformed by the view transformation. **Layers (Do I need layers or shall I just maintain a collection of visuals?) **Visuals A visual is something that renders to the screen. **Lens A lens is a visual that renders the view of a camera. *Rendering Widgets register damage as a rectangle to redraw, when they change. To register damage, we need to know the bounds in device coordinates. Since each thing knows its own transform only, it'll have to report to its parent. It may have several parents, so this will have to be observable/observed. A camera will hear from things at which it is looking. Damage registration: - Widgets register damage rectangles - DamageList coalesces damage into rectangles - on what basis -- maybe some minimising function? an heuristic? - Renderer treats each damage rectangle as a task To render a rectangle: - Find everything that is contained in the rectangle - Render in reverse z-order (i.e., painters' algorithm) - Tell SDL tell only update that rectangle. Complications: - Things with opaque backgrounds may obviate rendering parts of the rectangle 'underneath' -- could it collect a clipping area on the way down? (is it worth it?) - Lenses will need to know about things that are viewing being damaged - Do we clip in Cairo, or in SDL, or both? Clipping in SDL won't save drawing operations. We have to be careful clipping in Cairo since clipping off pixel boundaries can be expensive (or it was a few versions ago) -- see http://cairographics.org/FAQ/#clipping_performance. - It may be the case that damage is under an opaque object that isn't damaged, in which case we don't have to redraw it. - Occlusion is per-camera. Simplifying to start with: - Don't bother with spatial indexing, just test everything - Ignore z-order for the time being -- just render in pre-order and test bounds - Don't coalesce rects, or trivially combine them into the MBR It's worth bearing in mind that quite often the damaged rect will be the whole space, since a lot of navigation will end up being transforms of the root camera. (Can we do the pannning trick?) - Have a renderer thread which tries to render on scheduled frames - It runs through its tasks, and each render is given a (target) frame clock time *Primitives A zorph does these things: - paints something on the screen - responds to events We may also want a group zorph, which simply contains a list of other zorphs, and paints them in order when asked to paint itself. Mainly the reason to group things together is to transform them all at the same time, so we include a transformation in the group. Actually, it could be better to put the transform in zorph, and have groups only for .. grouping things: Group < Zorph. There will be a bunch of other things we require from zorphs for the event and rendering system. There's also lenses, which contain both a transform and the thing at which they are looking (presumably a group). There's a distinguished lens called the root lens, which occupies the whole of the view. - Sticky zorphs/lenses? Zowie in Scheme had a world object that was handed the drawing surface and had the root camera. **Later There's loads of things we can do to avoid rendering things: - test whether the bounds will be smaller than a pixel under the current transform - keep a clipping area (have to be careful though, since clipping can end up being expensive) - clip to lens bounds (we have to do this anyway) - clip for opaque, rectangular objects (how many of these will there be? Full opacity may have to be a special case) - clip for original damage rect **Miscellania http://www.cliki.net/spatial-trees has a CLOS implementation of spatial tree indexes (via Wikipaedia:R Tree). cairo_push_group and cairo_pop_group can be used to composite a fill+stroke with alpha (doing each with alpha means one shows through the other). http://www.ddj.com/architect/184408948 has a description and code for keeping a list of damage rectangles. It makes sure no rectangles overlap.