More Stuff on Escher
Tuesday, June 30th, 2009OK, so the whole notion of having separate textures and pictures is stupid. What I actually want to do is render to surfaces, yielding surfaces with things on them. Paths can be stroked, filled, or textured to yield pictures. Pictures can be rendered to yield a surface. Now, Escher’s conception of a surface should not just be a big bitmap or a printed page. It should be a surface with a clipping path and a transformation matrix.
In fact, one should render to a surface yielding another surface (this time with the actual backing bitmap or page changed, duh). This makes the type of the render method render: (window,surface) -> surface. Yay. That actually makes the whole conception of how it works to place windows much easier. The owner window has some spot it wants to render the child window into represented by a clipping path and a transformation matrix. It can take the surface it was given to render into and apply those to get a new surface value that it passes to the child window. Child window renders to mutate the surface and returns it. Wallah!
So, operators with surfaces for rendering things…
subsurface: (surface,matrix,clip) -> surface
render: (picture,surface) -> surface
Well what do those look like in syntactic terms? I already have a “compose” operator that puts paths and pictures on top of one another.
x -> y means x rendered on top of y, or y rendered followed by x. I can easily just add the capability to take a surface as the second operand and do rendering that way. Oh, and x -> y where both x and y are surfaces blits x onto y.
x:(y,z) means to yield the surface x subject to the transformation matrix z and the clipping path y. Looks good enough.
Add a library function for inverting a matrix. Actually, for a two-dimensional world would a quaternion (3 floats), a scaling vector (2 floats), and a translation vector (2 floats) be less floats than a 3×3 matrix? Well yes, but then I can’t compose operations by matrix multiplication. Well I do have first-class functions, so what the hell do I need composition by matrix multiplication for? Oh, right, speed. It’s faster to compose 2 functions into a new function, but slower to actually apply the composed function than to vector*matrix multiply. Well, actually the matrix approach gets cheaper with the number of operations composed.
Anyway, my standard library ought to include functions for making rotation matrices, scaling matrices, translation matrices, and inverting matrices. This will help in dispatching input events that specify a point inwindow: just check clipping paths for a sub-window it falls in and then multiply the input by the inverse of the transformation matrix for that sub-window.