Category Archives: Graphics

First steps into a more “colorful” emulation

One of the major features of phase #2, as we originally wrote in the milestone and phase plan two years ago, is adding support for Color QuickDraw emulation. Even though a lot of APIs considered part of phase #1 are still incomplete, the application compatibility and overall progress of project appears good enough to justify starting the work on that particular feature at this point. Nevertheless, all missing phase #1 features will be worked on simultaneously as they come up when testing the applications.

Adding color support will eventually allow us to test a huge number of new applications and games, and it will also allow trying out the existing ones in color modes. Especially games from the early 1990s have very good support for multiple color depths, so it should be interesting (for example, Civilization’s support for 1-bit and 256 colors, Railroad Tycoon’s 1-bit and 16 color support, Glider’s 16-color art, etc…)

First steps: The slot-based architecture

Originally Apple’s Mac II lineup had a quite different architecture from the old “classic”-type compact macs, which also reflects on how Color QuickDraw operates. Instead of dividing the memory space into four regions as in “classic” Macs (4mb RAM, 4mb ROM, 4mb I/O and 4mb VIA space), the slot-based models (in original 24-bit model) divide memory into 1mb “slots”, which are more dynamically assigned. For example, IM:Memory 3-6 describes the following model (in 24-bit mode):

  • 0x000000-0x7FFFFF: RAM
  • 0x800000-0x8FFFFF: ROM
  • 0x900000-0xEFFFFF: Nubus slot addresses
  • 0xF00000-0xFFFFFF: I/O

That particular model fits quite well with the currently implemented 24-bit memory manager, so we use that as a starting point for Color QuickDraw machine emulation. It also allows us to partially emulate slow manager APIs (as slot numbers $9 through $E match their address space as on real Macs), and allows possibility for emulating multiple screen using multiple “virtual” slot manager cards, one for each screen. The drawback of this, though, is that only one megabyte is assigned for each video device in 24-bit mode, which limits usable VRAM to that 1 megabyte. What this practically means, is that these are the approximately maximum supported “standard” resolutions for each color depth:

  • 1-bit (black & white): 3840 x 2160 (4K)
  • 2-bit (4-color): 2560 x 1440 (QHD)
  • 4-bit (16-color): 1920 x 1080 (FHD)
  • 8-bit (256-color): 1280 x 720 (HD)
  • 16-bit (32K colors): 832 x 624 (Mac 16″)
  • 32-bit (16.7M colors): 512 x 384 (Mac 12″)

Of course, when we later someday add 32-bit memory manager support, we will have 256 megabytes per video device, and can get rid of this limitation.

The slot driver

One key component between the “virtual” slot-based video device emulation, and the Color QuickDraw, is the device driver for the slot device. In our case, we added the .Display_Video_MACE_FB driver (following Apple’s naming convention for slot drivers), which is used by QuickDraw’s and Color Manager to control video modes, color table, etc.

On real Macs slot manager would be responsible for iterating parsing sRsrc:s and other slot-specific data structures, but we forego those hardware-specific details and address the native video device data (currently SDL) through our platform-abstraction interface.

The DRVR calls are still important to implement properly, as they were quite standard on real Macs, and there might be apps using them directly, even though well-behaving apps should always use GDevice, Color Manager and Color QuickDraw API calls.

Platform abstraction for color video

As we already had prepared for adding color support when starting the project two years ago, most of the support for it existed already in the platform abstraction layer. There were a couple tweaks needed, but most work was just adding the output renderers for each of the new color depths (originally there was only 1-bit blitter, as it was the only color depth supported on classic Macs). This also included adding the color lookup tables in the pipeline, so that we are ready for Palette Manager when we get to the point of implementing it.

GDevices

As there may exist any number of screens, with any resolution and various color depths, Color QuickDraw added the concept of GDevices. Each GDevice represents one screen/video card attached to the system, with its own screen buffer, color & gamma tables, etc.

Color QuickDraw allows drawing to all of these devices at once using the standard toolbox API, doing all the color conversion and addressing for the user. This is what we need to implement next also in our emulator.

Color Manager

One key component of Color QuickDraw is Color Manager, which is responsible for managing the color tables for each GDevice. What this means, that it creates and manages the inverse color lookup tables (which are used to map RGB colors to indexed colors), and handles those lookups. It also keeps track of seed values for color tables, which are used to determine when color tables have changed, which is important especially if a previously expanded pattern is drawn after a new color table has been activated. For now, we implemented a very basic ITable generation for allowing RGBColors to work on indexed color modes.

Inverse color-lookup table

As meantioned above, one key feature of Color Manager is the generation and management of ITab data structures, which are used to map RGB Colors back into color table indices in indexed video modes (2-, 4- and 8-bit depths). The generator is run in MakeITable trap handler, which takes handle of color table, handle of output inverse table, and desired channel resolution as arguments.

The inverse table is actually a RGB cube, where the cube’s channel size is defined by the number of bits given as the resolution; so for example resolution of 4bits gives 2^4 = 16, and the entire RGB cube would take 16x16x16 bytes which is 4096 bytes, or 4K of memory. As in three-dimensional XYZ space, RGB cube can be thought of in the same way; Each R, G, B coordinate are used to locate index in the cube’s 3-dimensional table.

When Color QuickDraw wants to get for example, index of RGB color #E39EA0, Color Manager would convert first the RGB components into cube’s resolution range (in this case, result would be (14, 9, 10]), and use those values of index the ITab data to get the value.

When the cube is generated by MakeITable, it is initially empty, but is given the seed values from the source color table; each seed value is the color lookup table index, placed at the RGB coordinate which it specifies. After this, the seed values are progressively iterated, so that each value “spreads” into adjacent RGB cube slots in any of the six axis directions (+R/-R, +G/-G, +B/-B). This is repeated as long until there are no longer any unfilled slots left in the RGB cube. This is familiar method from basic pathfinding, and some maze generation algorithms, and ensures that each RGB cube slot contains the index of color lookup table which is the closest available approximation for that particular RGB color.

PixMaps (and PixPats)

As BitMaps only supported 1-bit graphics, Apple added PixMap in Color QuickDraw to allow representing graphics of any bit depth using a standard data structure. Additionally, the GDevices use PixMap to represent the VRAM buffers, and PixPat (multi-color patterns) structure also uses PixMap as storage for the pattern data. And they also are by default implemented as Handles, which means they can be moved in the heap during compaction to prevent memory fragmentation (but require locking in certain cases).

The first step: Using legacy GrafPorts with Color QuickDraw

As Color QuickDraw has a lot of layers to provide backwards-compatibility for older applications, the first step was to start from the most basic one, legacy GrafPort support. As the very first call done to QuickDraw is to gray out the screen at startup, we focused on getting the most basic case for FillRect working at first. With adding support for pattern expansion to any pixel depth, and adding new srcCopy blitters, we got this fist monochrome output result after a couple weeks of coding:

First 1-bit monochrome rectangles using Color QuickDraw in 640×480 mode

When emulating the old-style GrafPorts, of of their interesting features to simulate was support for the 8 old-style QuickDraw colors (which map mostly to the colors used in ImageWriter printers with CMYK ribbon). With proper color mapping, and a couple days of banging the head against desk, we ended up with this result:

Rectangles drawn in old-style 8-color GrafPort using Color QuickDraw

Second step: CGrafPort support

As mentioned earlier, the old-style GrafPorts were limited to only displaying those 8 colors, so to get the full range of RGB colors displayed, we had to add a proper CGrafPort support. This included implementing OpenCPort and InitCPort, and initialization of all related data structures. For example, all patterns in CGrafPorts are PixPat patterns, so we had to do a Pattern-to-PixPat conversion.

Most importantly, the fgColor/bkColor no longer represented the old-style color constants, but instead needed to be mapped to bit-depth specific index (on indexed device modes) or pixel value (on direct device modes). To control these colors, we implemented the RGBForeColor/RGBBackColor traps, which map the RGB values to the mode-specific values.

After a couple of days of more hard work, we now have the RGB colors working in CGrafPorts:

There is still A LOT of things to do before we can get much beyond simple rectangles on the screen, but the tasks should get easier as we go along. A lot of the routines (such as color mapping) can probably be shared as-is with most of other Color QuickDraw APIs. Some of the tasks next up are:

  • Adding region masking variant to the color blitter
  • Adding other pattern modes beyond patCopy
  • Adding source transfer modes (only patCopy done at the time of writing this)
  • Color versions of the special horizontal single-scanline blitters
  • A lot of other stuff
  • OPTIMIZATION!

Full list of changes since last post

2020-01-31 18:02:57 +0200 • Basic support for "oldPat" PixPats in CGrafPorts
2020-01-31 16:35:14 +0200 • Implement InvertColor (default gdCompProc only!!!)
2020-01-31 13:47:55 +0200 • Some progress on CGrafPort colormapping & bugfixes
2020-01-30 02:10:42 +0200 • Add ColorQD Fore/BackColor & RGBFore/BackColor
2020-01-30 01:25:49 +0200 • Init default ColorQD PixPat patterns in InitCPort
2020-01-29 20:06:33 +0200 • Implement NewPixMap and NewPixPat
2020-01-29 01:42:41 +0200 • Initialize WMgrCPort (color port) in InitWindows
2020-01-29 01:41:59 +0200 • Implement OpenCPort and (mostly) InitCPort
2020-01-29 00:48:03 +0200 • Implement GetPixPat and GetCCursor colorQD traps
2020-01-28 22:12:56 +0200 • Implement DisposePixPat trap handler in color QD
2020-01-28 01:46:18 +0200 • Fix non-default colored patterns in 1-bit mode
2020-01-28 01:11:02 +0200 • ColorQD compatible GlobalToLocal/LocalToGlobal
2020-01-27 20:22:27 +0200 • Fix palette alignment issue in 8- and 15-bit modes
2020-01-27 20:20:38 +0200 • 15-bit (thousands of colors) SDL rendering support
2020-01-27 20:20:04 +0200 • 2-bit SDL output rendering support
2020-01-27 20:19:27 +0200 • Disable grayscale flag for now, test&fix it later
2020-01-27 20:18:37 +0200 • Fix last palette entry missing (zero-based count)
2020-01-27 13:33:46 +0200 • Add support for direct colors in color mapping
2020-01-27 13:26:34 +0200 • Set GDevice's gdType properly at initialization
2020-01-27 10:38:45 +0200 • GDev CLUT setup & rendering (first colors output!)
2020-01-27 09:44:47 +0200 • ColorQD ForeColor/BackColor in old-style GrafPorts
2020-01-27 09:43:56 +0200 • Fix initialization of QDColors low-mem global
2020-01-27 04:59:25 +0200 • Use Color2Index in color mapping for correct color
2020-01-27 04:56:41 +0200 • Set GDevice's gdResPref in the InitGDevice handler
2020-01-27 04:39:29 +0200 • Color2Index proto (no hidden color handling yet)
2020-01-27 04:36:27 +0200 • Fix the one-entry off "black-most black" index bug
2020-01-27 04:11:57 +0200 • Finish the first proto of MakeITable
2020-01-27 03:19:38 +0200 • Remove unneeded mitq resource from build
2020-01-27 03:18:51 +0200 • "Plant" seeds for the ITab generator from the clut
2020-01-26 00:24:21 +0200 • Start work on MakeITable
2020-01-26 00:23:50 +0200 • Tweak pattern blitters, preparing 8-bit support
2020-01-26 00:22:14 +0200 • Dummy Color2Index stub, prep use in colormapping
2020-01-25 17:05:21 +0200 • Hack 4- and 8-bit (16 & 256-color) output support
2020-01-25 17:01:45 +0200 • Fix old-type pattern to 8-bit conversion
2020-01-25 16:55:25 +0200 • Fix mask calculation for non-1-bit rectangle blits
2020-01-25 02:21:23 +0200 • First simple non-region FillRect case for ColorQD
2020-01-25 02:20:38 +0200 • Block attempting to post events before InitEvents
2020-01-25 02:19:04 +0200 • Fix the "dummy buffer" string RSAlloc overflow
2020-01-24 02:35:50 +0200 • Some progress on color blitter rectangle culling
2020-01-24 02:34:20 +0200 • Add QDErr low-mem global
2020-01-24 00:05:55 +0200 • Do CQD old 1-bit pattern to b&w GrafPort expansion
2020-01-23 00:18:35 +0200 • First CQD color mapping pass for old-type GrafPort
2020-01-22 17:53:29 +0200 • A bit of work on the color QD color mapping
2020-01-21 01:32:09 +0200 • Implement portBits to PixMap conversion to colorQD
2020-01-21 01:30:38 +0200 • Init lot of lowmem globals for default videodevice
2020-01-21 01:27:42 +0200 • Fix byteswap bug on device depth in CVGetVidParams
2020-01-20 15:02:02 +0200 • Refactor QD a bit in preparation of color support
2020-01-20 02:34:13 +0200 • Disable for now dirtyrect optimization in color QD
2020-01-20 02:22:37 +0200 • ColorQD versions of InitPort and OpenPort
2020-01-20 01:33:36 +0200 • Save LastMode/-Fore/-Back/-Depth in FMSwapFont
2020-01-20 01:32:29 +0200 • Fix two indexing bugs in ColorVideoInitOneSlot
2020-01-20 01:30:00 +0200 • Implement most of InitGDevice trap for color QD
2020-01-20 01:28:50 +0200 • Add empty stub for MakeITable trap
2020-01-19 23:29:53 +0200 • Add GetDeviceList trap
2020-01-19 20:37:49 +0200 • Add grayscale flag to video devices
2020-01-19 14:36:11 +0200 • Fill in GDevice's VPBlock from color video driver
2020-01-19 14:35:34 +0200 • Fill in DCE slot info in Open call for slot device
2020-01-19 05:03:02 +0200 • Add one more missing ROM clut resource
2020-01-19 05:02:32 +0200 • Add DisposePixMap, New/InitGDevice, GetNextDevice
2020-01-19 04:59:55 +0200 • Use cmake source_group TREE to clean up projects
2020-01-19 04:59:08 +0200 • Add MacVideo header
2020-01-18 23:54:18 +0200 • A couple more CQD resources (gama, mitq, cluts)
2020-01-18 05:51:16 +0200 • Add unit table debug dump tool to device manager
2020-01-18 05:50:37 +0200 • Add "virtual" slot DRVR installation support
2020-01-18 04:29:39 +0200 • Tweak video driver name & fix default slot amount
2020-01-18 04:26:22 +0200 • Implement DoVBLTask trap (untested)
2020-01-17 17:27:46 +0200 • Add SlotManager module + slot queue initialization
2020-01-17 01:52:09 +0200 • Implement color version of InitGraf
2020-01-17 01:28:37 +0200 • Add GetCTSeed/GetCTable/DisposeCTable to ColorMgr
2020-01-17 01:18:38 +0200 • Add TableSeed and HiliteRGB low-mem globals
2020-01-17 01:17:59 +0200 • Add default 'clut' tables to color ROM resources
2020-01-16 01:50:16 +0200 • Clean up linker errors for missing color QD stubs
2020-01-16 01:43:16 +0200 • Add setup of menubar 'mctb' color table (untested)
2020-01-16 01:35:33 +0200 • Empty stubs for GetCIcon, PlotCIcon & DisposeCIcon
2020-01-16 01:27:38 +0200 • GDevices module & GetMainDevice/GetMaxDevice stubs
2020-01-16 01:20:13 +0200 • Add empty stub for _ActivatePalette
2020-01-16 01:15:39 +0200 • Empty stubs for Delete/SetMCEntries & InitPalettes
2020-01-16 01:06:12 +0200 • Tweak ClassicSound to not fail colorQD compilation
2020-01-16 00:56:30 +0200 • Tweak some CMake configs for color-only apps
2020-01-16 00:55:31 +0200 • Refactor VBL code out of VIA + add slot# to video
2020-01-15 02:52:16 +0200 • Improve compilation of QDExtensions with color QD
2020-01-15 02:41:14 +0200 • Improve Menu Manager color QD compatibility
2020-01-15 02:40:40 +0200 • FMSwapFont color QD tweaks & LastSPExtra type fix
2020-01-15 02:36:37 +0200 • Fix ClassicSound compile error w/o Sound driver
2020-01-15 00:49:29 +0200 • Separate Mono & Color fake roms + add 32-mode flag
2020-01-15 00:47:24 +0200 • Add the DRVR 120 (.Display_Video_MACE) to fake rom
2020-01-15 00:45:59 +0200 • Add color video initialization call to boot code
2020-01-15 00:44:02 +0200 • Add stub for the color video driver
2020-01-15 00:42:54 +0200 • Add symbol name to binary-to-C converter

Windows version (and screen mode control)

As mentioned in the earlier posts, a large amount of this Christmas vacation was spent on the Windows version of M.A.C.E. runtime, and creating something for Windows users to try out. Now all the core work has been done, and we have the first prototype of the Windows port of runtime – with all of the existing test applications now available also as Windows executables. Now, there are a couple important points:

  • The windows executables are currently built only for the 64-bit x64 architecture
  • They have only been tested on Windows 10 (and only on Toni’s brand new 3.06Ghz Xeon W3550, and whatever processor Pukka’s new PC has). We have no idea on what other computers they work (or do not work)
  • You might want to avoid running them under certain virtualization software applications, as at least on Toni’s VirtualBox the performance was… not very stellar, at least compared to a physical PC without virtualization.
  • The PC keys are (for now) mapped permanently as follows:
    • Left alt = Left command
    • Left ctrl = Left option
    • Right alt = Right command
    • Right ctrl = Left control
  • Under windows 10, the “windows square” key (between Ctrl and Alt) cannot be used by the emulator as command or option key, because the Windows OS doesn’t seem to allow it to be fully captured (only partially).
  • AltGr key does NOT work as Right alt, because on Windows AltGr actually simulates Left Ctrl + Left Alt key presses. We need to investigate this more in the future.
  • The filesystem package is cached under Users -> username -> AppData -> Roaming -> MACE, with individual cache folder for each pre-packaged test application. So, if you for example create cool Continuum Galaxy files, this is where you’ll find them. And as AppleDouble files, they are exchangeable between M.A.C.E. on Windows, M.A.C.E. on Mac OS X, and theoretically (but not tested) with the Executor emulator which also uses AppleDouble files.

Below is a screenshot of the currently available test apps running on Windows 10:

If you have Windows, you can right now try them out in the Downloads section on this page.

Screen mode control: Full-screen mode and pixel doubling

Another neat new feature that was added to the new M.A.C.E. runtime version, besides the Windows compatibility, is the ability to switch between windowed/fullscreen modes on the fly, and also toggling the pixel-doubling feature. The shortcuts for these are:

  • Cmd+Shift+1: Toggle pixel doubling mode
  • Cmd+Shift+2: Switch between windowed and full-screen modes

These keyboard shortcuts were chosen (for now) as they should conflict very little with existing Mac applications, as they were used as disk eject FKEYs on real Macs.

This new feature has been both updated into the existing Mac OS X test app bundles, as well as in the new Windows versions.

Full list of changes since last post

2020-01-07 00:39:56 +0200 • Skip unwanted packaged VFS entries
2020-01-06 23:40:32 +0200 • Don't cache OSX 10.6 vs 10.9 target in CMake
2020-01-06 20:32:52 +0200 • Fix typo in scaline range check in _StretchBits
2020-01-06 19:10:24 +0200 • Bump runtime version & tweak version info format
2020-01-06 07:08:39 +0200 • Load package VFS from Win32 resource on Windows
2020-01-06 07:07:18 +0200 • Include dynamically generated .rc in win32 targets
2020-01-06 07:06:34 +0200 • Fix encoding of special symbols in two test apps
2020-01-06 06:05:01 +0200 • Add extracting VFS archive in initialization code
2020-01-05 04:30:25 +0200 • Add file archive reader, and clean up CMake files
2020-01-04 23:20:46 +0200 • Sign-extend <32bit args to prevent ARM optimizat..
2020-01-04 04:18:12 +0200 • Try fix Raspberry hMenu bug, enforce 16-bit menuID
2020-01-03 22:22:10 +0200 • Lock SDL window data during screen mode switch
2020-01-03 21:52:42 +0200 • Refactor display toggles to use DynamicConfig keys
2020-01-03 21:50:30 +0200 • Add first part of DynamicConfig system (UserPrefs)
2020-01-01 17:54:41 +0000 • Disable JSON parser tests from build
2020-01-03 01:20:14 +0200 • Fix DynamicConfiguration JSON dependency + bin dir
2020-01-03 00:39:24 +0200 • Merge branch 'master' of 
2020-01-03 00:39:21 +0200 • Add missing header search path for JSON lib
2020-01-03 00:36:54 +0200 • Fix OSX target, CMP0066 and set SDL2 debug/release
2020-01-02 23:08:12 +0200 • Merge branch 'master' of 
2020-01-02 23:08:06 +0200 • Specialize OSX Cmake config to 10.6 and 10.9 bases
2020-01-02 20:36:10 +0200 • Add JSON parser to the MACE runtime (for configs)
2020-01-02 19:09:33 +0200 • Also fix the Mac icns for previously invalid icons
2020-01-02 18:51:14 +0200 • Add stub for DynamicConfiguration module
2020-01-02 18:50:30 +0200 • Sanitize Windows key mappings to be more usable
2020-01-02 04:13:26 +0200 • Add ICO files to EXEs, & use console only in debug
2020-01-02 04:11:18 +0200 • Use debug/release SDL2 lib depending on app target
2020-01-02 04:09:56 +0200 • Reconvert Windows ICO files
2020-01-02 04:09:39 +0200 • Fix incorrect icon assignments of couple test apps
2020-01-02 04:08:20 +0200 • Make SDL2-static compile on VC release mode
2020-01-02 00:51:30 +0200 • Add processing of Windows ICO files
2020-01-01 23:49:58 +0200 • Fix trap glue generator to use new byteswap macros
2020-01-01 23:48:56 +0200 • Refactor cmake to use offline icon conversion
2020-01-01 20:39:58 +0200 • Add lpng 1.6.37 to ThirdParty external libraries
2020-01-01 17:10:36 +0200 • Force redraw of screen on SDL expose events
2020-01-01 15:38:09 +0000 • Haiku compilation fixes

Second mid-summer update: Post-roadtrip, TextEdit progress, Clipboard…

Okay, so both members of development team have been busy being on vacation trips for the past few weeks, but we’re again back (although still on “kind of” summer break). To celebrate this we decided to each post a picture of what we’ve been up to, but to make this appropriate to topic of this blog, we do this by showing the photos using M.A.C.E running Photoshop 🙂

Road trip vacations

First, Pukka went on a road trip to Eastern Finland with his good old trusty Volvo station wagon for one week:

Pukka went on a road trip to Eastern Finland with his good old trusty Volvo station wagon for one week

Toni went on a two-week road trip to Northern Germany, visiting 12 cities in 14 days, including taking this amazing train from Hamburg to Kiel:

Toni went on a two-week road trip to Northern Germany, visiting 12 cities in 14 days, including taking this amazing train from Hamburg to Kiel

TextEdit progress (and Scrap Manager)

During this two weeks of visiting a lot of places, Toni had a couple evenings time to do some work on (non-styled) Text Edit, which now is nearly complete, and is able to run TeachText with almost all text editing features working:

TeachText works now on M.A.C.E.!

These are the notable features which work now in TextEdit:

  • Multi-line text display, with scrolling support (viewRect/destRect offsetting)
  • TEKey text input (still a bit hacky but functional)
  • TEClick with autoscrolling support, double-click word selection (using TEFindWord), and fExtend support for “shift-key”-type extending of selection, and recognition of left/right side of character for proper caret positioning
  • TextEdit hook support for nearly all TE Hooks (TEDoText, TERecalc, TEWordBreak, ClikLoop, TEFindWord, TEFindLine, TETrimMeasure, EOLHook, HighHook, etc…) which can be customized by 68K apps
  • Caret support with TEIdle blinking, TEKey cursor key movement (including multi-line support), and multi-line selection range support
  • Nearly all “quirks” of regular System 7.x TextEdit implemented as they work on real Mac; including the weird way caret gets positioned when moving across line boundaries using left/right arrow keys if previously clicked on right-hand side of a character, etc…
  • Dialog Manager edit field support, with System 7-type multi-line text support (i.e. edit fields with one line get extended horizontally 2x size, and scroll both horizontally and vertically, while multi-line edit fields only scroll vertically), “tabbing” between edit fields, and complete TEKey/TEClick support
  • Maybe some others I’ve forgotten to mention

Additionally, as TeachText wanted to use also Scrap Manager for edit functions, in parallel to implementing TECut/TECopy which use private TextEdit scrap, the implementation of generic Scrap Manager was finalized so that Clipboard file is fully supported (previously only in-memory state of scrap was implemented).

However, TEPaste still needs to be added for a 100% completion of “Edit” menu features for TeachText – and also, styled TextEdit work has not yet been started, which will be required in future to support more complex apps such as SimpleText and HyperCard 2.x.

Next up, on Toolbox API side, work is being done on Resource Manager’s resource fork write support, mostly just because after Scrap Manager was implemented, SuperPaint was able to progress a bit further in it’s startup, but wants to create “SuperPaint Prefs” file using Resource Manager’s functions, so might as well add that next. As of writing this, there’s already support for AddResource, ChangedResource and WriteResource, but we need to add resource fork compacting support to UpdateResFile to actually write the file properly. But we’ll get back to that later.

Bonus pic – for fun 🙂

Meanwhile, here’s a funny pic of what it looks when we run 28 M.A.C.E. instances at once 🙂 All quite responsive even though they’re all in full debug mode, although same can’t be said about the old Mac Pro when it was running them… 😀

28 individual M.A.C.E. applications (in debug mode) running at once 🙂

Experimenting with INIT/cdev support

This previous weekend, while helping Pukka to fix a mysterious coordinate calculation bug in Fool’s Errand intro, I decided to experiment with one weird idea: How about adding support for System Extensions and Control Panels? Therefore, yesterday I added the After Dark ‘cdev’ control panel to MacPaint app’s build settings to be included in the System Folder, and took some time to look what it would take to make it work.

Basically, INITs and cdevs are loaded during the startup by Mac OS by checking a few bits (such as file type, visibility, etc), opening the resource map of each file, and executing the first ‘INIT’ code resource found. At this experimental stage, we don’t yet have full INIT/cdev scanning, but instead have just a hard-coded filename to load INIT code from which works ok enough for this test case.

Our boot-time heap wasn’t quite properly set up yet, as the boot stack was too high, not leaving enough space between MemTop and BufPtr, which on the first attempt of running the INIT caused After Dark’s InitZone call to actually end up at top of the stack, causing all sorts of havoc. Besides that, there were a ton of bugs/improvements:

  • 68k-to-68k trap calls did not work correctly (i.e. calling a trap patched with 68k from 68k code)
  • InitZone parameter block handling was completely broken from the last year’s trap refactor, so it was fixed
  • Memory Manager’s Handle validation had not taken into account the case where handle’s “relative handle” field would point to invalid memory location in some “fake” handles (as one in After Dark), for which validation was added
  • Empty stubs were added for Notification Manager calls to allow After Dark to call them during activation/deactivation of screen saver
  • Locking of 68k mutex was not done early enough, so After Dark’s VBL handler was making the initial call Launch trap to have invalid register values
  • After Dark uses grafProcs to call QuickDraw, so one missing case used by it was added (ovalProc for ovals)

After that bunch of minor tweaks, we have now at least After Dark working nicely!

After Dark icon displayed during loading of MacPaint

Although the INIT code itself works, there is not yet any UI for displaying cdevs (Control Panels), so modules cannot be configured yet, and thus only the default “Starry Night” built-in module is displayed.

“Starry Night” (default module) running in After Dark inside MacPaint application bundle

There’s also a short video to demonstrate After Dark running:

Although not very usable feature at the moment, this will definitely allow interesting possibilities in the future, as theoretically we should be able to run applications requiring certain application-specific extensions to be present in the System Folder. This experimenting with After Dark has anyway allowed us to find a number of important bugs (as previously mentioned), and also works as a very good “compatibility” test to see how well our Toolbox API and 68k implementation can handle one very quirky control panel, as it patches a ton of toolbox traps and does a lot of low-level stuff which all appear to be compatible with our emulation.

File system write support (and MacPaint kind of works)

This week we reached a major milestone! From the encouragement on the work on HyperCard on 68KMLA forums, we got inspired to attempt tackling one major obstacle that was preventing it from working – file system write support!

As we mentioned earlier last year, when we last fall added the file system API, we did so using abstraction on top of AppleDouble file format. As Mac file system has the special dual nature of being split to data and resource forks, the AppleDouble format helps managing this in the emulated file system. Data fork, as mentioned earlier, is saved directly in its own file, while resource fork is merged with other file metadata in the AppleDouble header file. With this distinction, adding support for writing to data forks was really just trivial mapping of file manager write calls to the data file. Resource fork writing is a bit tricky, but we currently force the AppleDouble headers to keep resource fork as last element in the file, which allows us to offset also write operations from the beginning of resource data, and allows us to expand/shrink file easily, as end of resource fork is the actual end of header file. (One side note, setting EOF of files doesn’t have a standard C file operation, so we’re for now using the POSIX extension “ftruncate” which works at least on Mac OS X, but may lead to portability issues.)

Currently there’s very limited set of features for writing to file system implemented, basically just “Create” and “Write” file manager calls. For example, resource manipulation does not yet work as it will require a number of routines added to the Resource Manager to support it. However, one test application that directly benefited from this new feature was our beloved MacPaint, as it requires two scratch files to be present on startup volume/folder to function. This was nice, as it allowed us to add a few other missing features, such as PackBits (which also benefitted other apps and picture recording).

Hello from MacPaint!

Although all tools don’t yet work perfectly, most of basic drawing functions are solid enough to not only allow drawing, but the experimental file writing also allows saving of MacPaint files, which appear to be readable by the Preview application in development host system Mac OS X 10.12!

FatBits and some test pixels drawn (including ‘hello’ done with the MacPaint text tool)

Additionally, many other applications have seen improvements from this, as now we can save Civilization games and continue playing them! (Although Standard File package is still using hard-coded SFReply records).

Photoshop 1.0 (and MacApp support)

The past week we’ve been busy working on optimizations on the 68k CPU and various improvements to the toolbox API. One of the improvements has been adding support for Apple’s MacApp MethodDispatch routine, which is used by Object Pascal and C+- (yes, that’s “C plus minus”, Apple’s proprietary C++ version which was briefly out before official C++ came to Mac). Basically, MethodDispatch is the virtual function table dispatcher commonly seen in C++ programs, but instead of being bundled in the application, it is actually implemented by the operating system as a toolbox trap – although with special calling convention, which cannot be called directly through A-line traps, but needs to be invoked through jump from 68k code. It handles selecting the correct implementation for class functions which can be inherited and overridden.

With the new MacApp method dispatching support, we should now be able to try running any MacApp-based applications – one cool such application, which is written in Objective-Pascal, is the first version of Adobe Photoshop:

About box and intro screen of Adobe Photoshop 1.0

Most of the dialog boxes appear to display (almost) correctly, although color picker, text input and popup menu support are missing so there’s little that can be done here:

Color separation preferences dialog in Photoshop

And just to test out how it works, we did a quick “Hello world” drawing using Photoshop drawing tools inside MACE:

“Hello world” from MACE!

Although implementing the method dispatching routine was fairly trivial, some time was taken by other features used by Photoshop, such as crude International Utilities/Script Manager support, PrGlue dispatcher for printing (or as in current case, telling application that printers are not available), proper Gestalt support, and various bug fixes even to some fairly low-level things as handling of empty regions in UnionRgn calls, rewriting the 80-bit “Extended” floating-point format conversion in SANE, etc… A few other test applications did benefit of those additions, but we’ll post more about them later!

Ps. In case you are interested how MacApp-based application code looks like, the original Object Pascal source code for the first Mac Photoshop was at some time ago published as open-source and is available on github: https://github.com/amix/photoshop

StretchBits (and font scaling)

An important feature which was implemented a few days ago is the StretchBits trap. It was actually implemented for the first “Stunt Copter” prototype, but as it’s effects are visible in many places, I felt proper to write a separate blog entry for it just to demonstrate a few cases where it had big impact on the content:

Railroad Tycoon map & minimap AFTER adding StretchBits
Railroad Tycoon map & minimap BEFORE adding StretchBits

Before implementing StretchBits, calls to it were directed as a placeholder to StdBits, which would show the content partially depending on the context, but causing graphic glitches as can be seen. On the Railroad Tycoon map, the “Map” uses both double-size scaling to draw the map, and half-size scaling for the mini-map on the right hand side. Also, the “New Train” screen uses stretching to scale locomotive PICT resources to fit the List Manager list it uses:

Railroad Tycoon “New Train” screen AFTER adding StretchBits
Railroad Tycoon “New Train” screen BEFORE adding StretchBits

Also the text rendering benefits of this, as text can now be scaled to arbitrary sizes, which is quite important when drawing bitmapped fonts in non-exact resolutions, such as in Missile:

Missile AFTER adding StretchBits/font scaling

Missile BEFORE adding StretchBits/font scaling

The scaling algorithm has some room for improvement, as it for now only has the generic method for scaling bits one pixel at a time. For now, this seems to be enough to allow working on other missing features.

Old-style FONTs (and Harrier Strike Mission II)

Today we tried running Harrier Strike Mission II for the first time. The game appears stable, but runs way too fast, and the 3D drawing has some minor glitches causing some polygons to go to wrong place.

However, the most interesting part of this game was how it’s drawing its user interface. On the first run, this is the weirdness that we got:

Main menu, before old-style FONT support
In-game UI, before old-style FONT support

As you can see, there was a lot of text all over the place, as we didn’t have yet old-style FONT loading in place (up to this point only FOND & FONT/NFNT combination, which most of previously tested apps/games used). So, after implementing some “TODO” parts in our Font Manager implementation, we ended up with this:

Main menu after implementing old-style “FONT” loading support
In-game view after implementing old-style “FONT” loading support

It’s rather interesting to see fonts used in such way. As a nice bonus of this, we also got the tool palette icons to appear in MacPaint, which are also implemented as a custom old-style FONT:

The tool palette of MacPaint is now visible too!

MacDraw & basic shapes

After some effort, we now have basic shape drawing working in MacDraw. One fun part of this was implementing FixDiv, which uses the binary long division algorithm like the original one on Mac. MacDraw uses this routine excessively to handle document grid sizing and coordination of all shapes drawn on the canvas.

“Hello” from the MACE team (with MacDraw’s custom MDEFs usable). No scrollbars visible yet though, have to get on finishing the CDEF 1 soon…

There was also a minor bug in MenuSelect causing zero item selections in MacDraw’s custom menus, but after a quick fix we can now also use them.

Contrary to many other applications, MacDraw uses a different approach to implementing custom menus – instead of providing a MDEF and assigning it to the menu using the menu definition proc ID in resource, it has its MDEF code as part of the program, and creates a fake handle which it assigns to the menu manually. Because of this, we had to tweak the memory manager handle operations to silently fail on such handles, and instead return the proper memAZErr (-113) in D0/MemErr.

Still no text drawing though, and there’s minor tweaking required for line drawing, but it’s looking promising at the moment.

The “About” box of MacDraw

Indiana Jones and the Last Crusade

Although we could make Indy launch already a while ago, for some reason we did not get any graphics to display. However, after Pukka fixed some more CPU bugs (including ror.l instruction), we suddenly got everything appear on the screen:

Lucasfilm Games logo

Indiana Jones title screen

Interestingly, the game uses Sound Driver to play intro music, *but* after intro completes, it switches to Sound Manager. As we don’t have yet Sound Manager implementation, we added some empty stubs that just return error for the caller, and it seems Indy is happy with that as we can now proceed in the game all the way until getting stuck on quests 🙂

Indy boxing

At this point we also noticed that we had accidentally handled the Style parameter of TextFace as 8-bit value instead of 16-bits as we should have, so the style calls had not been working until now that we fixed it. Indy uses these styles to adjust appearance of text on the UI buttons:

Game controls at bottom of the UI

Here’s also a short video of the intro (with audio), and few first minutes of the gameplay:

Indiana Jones and the Last Crusade running on MACE, intro with music and few first minutes of gameplay