Morphic graphics, Displaying fonts & canvases

sig siguctua at gmail.com
Fri Apr 20 14:40:03 UTC 2007


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



More information about the Squeak-dev mailing list