Monthly Archives: August 2018

Drawing PICTures

Now that the source transfer modes were added for drawing text, a logical next step was adding support for drawing the most basic bitmap-only PICT resources. For this purpose, we added a very simple test PICT resource into the Fake ROM resources, which we used to test this feature.

More than a bitmap

What makes the basic QuickDraw PICT format different from many other image formats is the fact, that it is actually not a pure bitmap container, but rather a recording of drawing commands, which can be played back at any time. Basically this allows majority of QuickDraw commands to be “recorded” into a picture, and later played back. Even better, these pictures can be “played” also on other devices besides screen, such as printers! This allows a picture with geometric shapes to have a rasterized on-screen representation, but appear as a sharp image on for example a laser printer. Furthermore, these pictures can be scaled during playback to a target rectangle, allowing them to adapt to different screen/device sizes as appropriate. Of course, all this makes displaying a simple scanned bitmap photo of a cat a bit more complex than one would expect.

A simple PICT image

Attempting to create the monochrome old-style PICT resource was a bit challenging on modern Macs, so we ended up transferring the photo on the reliable good old PowerBook G3, and exporting to resource from there using old version of PhotoShop.

Playback time!

So basically what we needed to display the cat picture, was just take the PICT resource and do the following:

  1. Read the picture size and picFrame from the header
  2. Save copy of content of current GrafPort
  3. Set up defaults for the GrafPort (including new clipping region)
  4. Initialize a playback state record
  5. Execute each picture opCode from picture data one by one
  6. Dispose playback state and restore original GrafPort state

Even in this simple format, the following opcodes were required for the test PICT: Version, LongComment, PackBitsRect, and EndOfPicture.

Type 1 picture opcodes encountered in the cat PICT

All other opcodes were trivial to implement, except PackBitsRect which ended up using UnpackBits trap, so we had good excuse for implementing it also at this point. With unpacking implemented, the drawing ended up with a simple call to StdBits, which was was already previously added for text drawing, and we got the cat quickly on the screen:

First appearance of the cat PICT

As clipping was already implemented, we were able to goof around by drawing the PICT in funky clipping region (with some text added for fun):

Cat PICT drawn masked by another, larger region, which was later framed with FrameRgn using different sizes and patterns to create gradient edge

More regions, and text clipping

Region recording

Previously, during the spring, we had added the basic region operations, which already allow us to do a bunch of cool stuff, but next up on the list was implementing region recording. This neat feature QuickDraw allows the program to open a new output region for “recording”, to which certain QuickDraw “FrameXXX” operations will output inversion points into. This includes StdLine, StdOval, StdRect, StdRgn, and RoundRects.

The article on MacGUI, which was mentioned earlier when discussing regions, also contained a neat screenshot of results of OpenRgn/CloseRgn operation with accompanying Pascal source code. We made adaption of this code for the C Toolbox testbed, so we could have a picture to compare to, to see that the results would match ones expected on a real Mac.

Again, first attempt rarely works…

At the same time, we were working on adding “source” transfer mode support to the region-clipping blitter, as transferring text to screen uses those to handle moving the text from offscreen buffer to the screen (previously we only implemented the non-clipped blitter). After getting this to work, there was also a nice benefit that non-scaled CopyBits can also be implemented easily soon, although only for cases where source and destination bitmaps are different (ScrollRect and window manager will use same source and destination, forcing inverted blitting direction depending on their locations).

Region recording works now, as does the text clipping

Styled text

A few days earlier, we got the non-styled direct-to-screen text drawing working, but we also need to support all the other cases. At this point, we want to have the clipping and styling support, but we’ll leave the scaling to some point in the future.

As styled text required an offscreen buffer for styling, we started by adding that. Interesting feature of QuickDraw FMSwapFont mapping is, that as any styles can be combined together, the FOut record contains a set of styling attributes which tells the text rendering how to adjust the final appearance of the font, such as bolding amount, how much slanted the italic style is, how deep the shadow is, etc.

Well, as usual, the first run didn’t go quite the way it was supposed to

After a few days to debugging, bug-fixing, more debugging, and even more bug-fixing, we go the text to render properly:

The final, correct styles

For reference, styles from PowerBook G3 running Mac OS 9. Note the difference in outlined/shadowed text.

An interesting discovery was, that it appears that “Classic”-type QuickDraw and Color QuickDraw handle the outline styles a bit differently. This may be due to the way outline/shadow styled text is combined during drawing, as the “inside” of outlined text is drawn over the shadow/outline using srcXor mode. Another interesting point is, that even Color QuickDraw falls back to the “old” type drawing if the GrafPort is old-type monochrome port (i.e. high-order bit of rowBytes is zero)

Even more combinations of styles and drawing modes!

Fonts and text drawing

Font Manager and the notorious FMSwapFont

As mentioned earlier, the next target is to get QuickDraw text rendering to work. For this purpose, we’ve been working on important part required by it, The Font Manager. The most important interface between QuickDraw and Font Manager is the FMSwapFont trap, which takes the FMInput record, and outputs an FMOutput record. On a real Mac, the font substitution has a bunch of special cases which we luckily don’t need to worry about; for example, we don’t need to worry about choosing right font to display the disk-switch alert. However, there are a number of substitutions we need to support:

  • Substitute non-present font to default font
  • Choosing nearest-size font strike to substitute a non-present (scaled) size of a font
  • FOND tables
  • Fallback to old FONT resources in case requested FOND does not exist (using the familiar family * 128 + size formula)
  • Etc.

Getting the strike loaded and on the screen

Majority of time spent for this milestone so far was investigating and implementing the quirks of the previously mentioned FMSwapFont trap. After finding the correct (or near-correct) strike, we finally got a FONT resource which we could work on. Of course, this meant that as first step dump the raw font bitmap on the screen buffer byte-by-byte 🙂

12 pixel “Chicago” font dumped on the screen. Tight fit, huh?

Of course getting the actual text to output, each of those characters would have to be individually masked and blitted to the correct location. For the first test, the original QuickDraw luckily appears to have “optimized” way to blitting non-clipped, non-scaled, non-styled srcOr-mode text directly to the screen, without having to go through offscreen buffer for styling and clipping. Implementing this was also pretty straightforward, resulting in the following tidy output using different fonts:

First successful text output, with various fonts in the fake ROM

Back from the summer break

Still alive and kicking!

It’s now about four months since the last update, but we’re back now from the holidays. Not much has happened during this time, the plan is to next add text drawing support, so foundation for Font Manager was laid briefly out, and Resource Manager is being reworked to allow calls to GetResource or ROM fonts soon.

Trap generator

The biggest change at this point in the recent days has been the work on automatic trap glue code generator. So far, all trap definitions have been added manually into the C headers and the glue code written by hand for each of them, but now we’re taking the bullet and actually implementing the generator responsible for creating those files.

For this task, we did careful consideration of a bunch of ways to handle generating this glue code, and ended up with using AWK scripts combined with basic unix shell script calling those AWK scripts. As all our Toolbox trap definitions are stored in a CSV file, which we generate from the master Excel file, the nature of AWK as line-by-line text processing tool fits pretty well.

C glue code generated by the trap generator
ProcInfo defines generated by the trap generator

At this point, we also tweaked further the argument formats, to make them better suited to the future MixedMode calling, such as converting arguments which were accidentally added as value-types into proper pointers (such as Pattern arguments in QuickDraw, etc)