Hi,
Maybe we could arrange IRC meetings or so; it would be useful for larger infrastructure changes. (I think that Jabber allows for multi-person conversations?)
It is good to get a quick check on an idea, but I must say I prefer email threads. One has time to think about it and it is very time-flexible.
My proposal would be to remove clipping information from Context and to think about some structure for "Drawing context". This structure could also include other style information and would act as a wrapper around context and used in convenience drawing functions.
If I understand correctly, we would then have a structure that describes a bitmap and its organization, and another structure that contains drawing settings? Let's say, a Canvas/Surface/Bitmap and a Context?
Something like that. I think about it as a DrawingContext that is bound to a Context (e.g. points to a context, but not the other way around, you could even have several DC for one Context).
The goal is to simplify the base api and modularize the library. I believe that we should allow separate use of any part of the library as much as possible - library supporting all kinds of weird devices can see many uses both with variable subset of the modules.
Well, modularization is a nice things, but please, do not overengineer that. Myriads of independent sub-libraries tend to create a dependency mess, complicate building of dependent projects, and slow things down.
Thanks for pointing that out. I am trying hard to be aware of that. For me, separation speeds development up rapidly, as I can actually make (API-preserving) changes without fiddling with unrelated but heavily entangled code.
My perspective is that we are creating a very powerful library (in terms of supported kinky 2bit HW etc.) and that many users would prefer only some of the API (having their own text-rendering, event management, etc.).
(I often find myself struggling with a library I wanted to use for one simple thing X, trying to make it do only X and not Y and Z as well, frustrated with the results)
I recently encountered "the golden rule of API design": If in doubt, leave it out. (rationale: if your API is neat, clean and stable, anyone can build a library providing the advanced feature they always wanted).
Arguments to move clipping from Context to drawing are
- One use of clipping is convenience when drawing primitives. This
should be handled with drawing functions. There, clipping can save some complicated reasoning.
- Blits should not respect clipping. Blitting a superset of
clip-region is very frequent and even if needed, calculating intersection of two rectangles is very easy.
Not sure about this; for myself I would say that a graphics system that does not respect clipping with some primitives and does with some others is confusing (how to remember which is which? Does a textured triangle, which is both a blit and a primitive, respect clipping?)
In other libraries, i see two things (or uses, though not entirely separated): 1) Sometimes you want the basics - load a bitmap, blit it, put some pixels, draw a line, perhaps do simple text. You want it simple and fast. I would personally still prefer to have this kind of interface, as in GP_Line(context, x1, y1, x2, y2, color); No state involved. 2) If you do something polished, you want all kinds of transparency, aliasing, clipping and nice font options. For that I hate the libraries that offer you some of those combinations under awkward names and letter combinations. Here having a state with such settings (aliasing, kind of transparency, font settings) is a great help and even allows the user to choose quality (aliasing on/off) simply, without carrying global settings around manually.
- One use-case of clipping is "user" routines drawing inside windows
etc. This can be done using subcontexts (context pointing to part of memory of other context). This has also the advantage of coordinate system being always (0,0) and solves the problem when (clipped) "user" drawing routine would like to use clipping itself. Of course that every context is still "naturally" clipped by (0,0,w,h).
Now that's what I call a brilliant idea! :-)
Unfortunately, there are some rough edges with nonadressability of <8bpp pixels, but I still want to implement it. Maybe we can use some walkaround (I have to think about it more).
From my own experience, I used clipping very rarely, but I see its value as a convenience mechanism. Having two variants of drawing functions - one "bare" (unclipped, without implicit style information, etc.) and an optional set of "convenience" functions (clipping, using implicit style info on BGcolor, clipping, aliasing, font, ...) would be the best of both.
I'm not sure; in accordance with Murphy's Law, the user will find out that she needs a function that uses one of the advanced features but not the rest (e.g. antialiasing but not clipping).
I belive we should aim for all combinations, if possible. But not exactly my area ...
I would rather vote for Guido van Rossum's way of "there should be preferably one correct way to do it". :-)
Hmm, and what would that be? Guido chose that so that Python is widely-readable. I do not see us having such requirement.
It still remains a question how to implement such wrapper (structure pointing to a context? context-independent structure? something extensible or fixed? ...). I haven't given it much thought. Any ideas?
Depends on what settings the structure should contain. If it should contain any kind of color information (color, filling, background, anything) then it will always need a pointer to the real bitmap data to convert the color into appropriate format. We can, of course, do it in every function call, but that costs us some time (negligible for larger elements, horrible for PutPixel - however, PutPixel and probably HLine are special anyway - they probably need an explicit color parameter anyway because there is a chance that color will be changed wildly often, and writing it into the context every time would also waste time).
Right. Putpixel is definitely part of core. I would like to avoid excessive repeated modifications to some kind of context to change color etc.
So, if the new Context structure contains any information that is somehow bound to the underlying bitmap, then it should be (IMO) bound to that bitmap, and rebinding should require a special function call (because it needs recalculations that cost time).
I thought about the DC as being bound to one Context (so noneed to pass both to functions), but using one DC for several contexts seems like good alternative. DC can then contain the PixelType, so it does not *have* to point to a Context. Still, where do you see the use-case for using one DC for Contexts of different PixelTypes?
OTOH, it would be useful to have a Context store a color in the most precise way so that it does not become subject to accumulation of rounding errors; it makes sense to store what the user *meant* (which is not necessarily what she gets).
"Most precise way" might be more trouble than use and giving the user what she meant is awfully hard. It is easier to make it easy for (and to teach) her to *get* what she wants. Even without mentioning palettes and such. Her program will mostly likely use one PixelType and she won't care which (+ conversions from constants and loaded images to the PixelType). If she uses several PixelTypes willingly, I believe she would prefer to have control over what is happening to her colors.
Tomas
-------------------- Let's give them enough rope.