Hello squeak-dev,
during my struggle to make morphic world be OpenGL ready i found
that current drawing protocols not providing a freedom in
selecting a methods on how the text/images is drawn on display.
As i can see, the current graphics classes
(Canvas/DisplayScreen/Morph) is heavily relying on blitting
operations and (wrongly) assume that canvases and/or their display
mediums supporting them by default.
First of all, DisplayScreen is a subclass of Form which is a
subclass of DisplayMedium.
A DisplayMedium comment reads:
I am a display object which can both paint myself on a medium
(displayOn: messages),
and can act as a medium myself. My chief subclass is Form.
This is wrong. I can give you tons of exapmles when display medium
represents a hard copy (take a look at the paper on you desk) and
can't be painted on other medium.
The printer can be considered as such medium to which you can draw
but can't draw a printed contents on other medium.
And i strongly presume that the DisplayScreen is such kind of
medium.
Even more, not all mediums can be represented as rectangular
area of pixels. Some of them can be presented as set of vectors
(vector displays) or other forms of drawings, and even have
non-rectangular display surface.
And thats where we need a Canvas to draw on it.
The drawing process by its nature is one way road and assuming that
we can freely draw between different mediums is totally wrong.
So, at abstract level we must think of a Medium to which we can draw
by issuing commands through its Canvas. Nothing more.
To simulate drawings from one medium into another we can use caching
canvas, which will collect all drawing commands and then pass them
to another canvas of target medium.
All morphic drawing is built on top of this wrong assumption,
which prevents me to make a nice and clean replacement of Display to
allow morphs drawn using OpenGL.
For making this possible there is need to make changes in many
places to conform different protocol(s).
And here is my proposals:
Fix the DisplayMedium protocol by revoking assumption that it
can be drawn on other medium.
DisplayScreen class:
- make it a subclass of DisplayMedium, not Form.
Canvas class:
- remove methods which based on assumtion that canvas is drawing
on top of Form. Refactor code which assumes such behavior.
Since canvas represents capabilities of DisplayMedium i think
that first references to Canvas must appear there, and any drawing
on medium must be a drawing using canvas received from #getCanvas
message.
The method #defaultCanvasClass must be removed. You cannot
connect a canvas to different medium and cannot use two
independent canvases for drawing on the same medium because this
leads to breaking its current internal state.
For caching/clipping purposes there are protocol in canvas itself,
which can give you instances for such uses and since they refer to
the main canvas, the risk of breaking the medium internal state
is minimal.
For example, if morph wants to use a Form to draw itself into (as in
Morph>>#imageForm:forRectangle:), then it must
directly instantiate a Form and use #getCanvas to draw on it.
If there is need in a form having same depth as screen - use
Display>>depth. But note, message #depth for DisplayScreen must
be considered as a hint, not a part of Form protocol.
In most cases, drawing in to independent form used for caching
purposes, when resulting image is then _blitted_ on the screen.
There is a class named CachingCanvas designed specially for
such purposes, and showing 0 references in my 3.9 image. Make a
conclusion :)
So, returning back to the needs pre-cached drawing i think the
best way is to use Canvas protocol, so it can return an
instance of CachingCanvas or its subclass to cache the incoming
drawing operations.
The caching canvas MUST be used by morphs and fonts.
Take a look at the TTCFont implementation, i cant look at it without
pain.. What do you think, is this the best way of drawing
true type glyphs using pre-cached bitmaps?
The authors of true type package made a great job by providing
TTF's for a squeak, but failed to make it in a really nice
fashion when glyphs are coming to draw on the screen.
This is another design flaw to which I would like to pay
attention. The protocol between Canvas and AbstractFont is need
to be redesigned in the way of using CachingCanvas for this
purposes.
Then there will be no need to introduce own bitmap cache what
is currently done in TTCFont class. And moreover, in case of
OpenGL a caching canvas is stored in video memory which greatly
improves performance when you need to copy it on the screen.
Displaying a string is simple set of commands which
draw part(s) of cached canvas(es) on the main canvas.
Comparing to Form(s), a caching canvas can store a list of
commands issued to it, instead of bitmap. And this can reduce
the memory usage and greatly improve speed, because of reducing
an excessive blitting operations.
I'd like to discuss all above metioned with you :)
Meanwhile my current implementation of GLCanvas draws a World from 3 to 8
times faster than current Display. And i think it can be even faster.
I think that performance can be increased to such level to make it
possible to draw
entire World in back buffer and still have decent frame rates.
--
Best regards,
sig