Category Archives: Toolbox

Merry Christmas from MACE team!

What could possibly be better way celebrate the holidays, than implementing SecondsToDate trap in time to get the Dark Castle Christmas day easter egg visible? 🙂

Christmas tree in Dark Castle’s Great Hall on 25th of December 🙂

Control Manager, Icon Quest and Dark Castle main menu

One critical part of UI was still missing at this point, the Control Manager. Luckily implementing it was quite simple, as like with Window Manager, a lot of the core functionality depends on QuickDraw to do the difficult things.

IconQuest intro dialog

With support for Controls, we could now use buttons, like one in the above IconQuest introduction dialog, and the buttons below in Dark Castle main menu using ModalDialog:

Dark Castle main menu, almost working

The buttons still need titles, checkbox implementation is not complete, and TrackControl is implemented as a immediate return, but that is enough to allow entering The Great Hall in Dark Castle:

The Great Hall, with some bugs to iron out…

With this test case, Pukka identified a bunch of CPU bugs, including lack of BCD (Binary Coded Decimal) support which Dark Castle uses to display the values at bottom of the screen, which will be fixed next.

Update Events

When attempting to run 1000 miles, we soon noticed that it *could* draw to its windows, but it didn’t because we didn’t send update events to the application. As Window Manager implementation had already added foundation for posting the update events, we added support for it in the EventAvail/GetNextEvent, and stuff started happening.

After adding BeginUpdate, EndUpdate, and a bunch of other traps 1000 miles needed, such as PlotIcon and Pack7 (DecStr68K) package (for NumToString through LBin2Dec), we got nice looking interface of the game visible:

Update Events working; 1000 miles windows have now content

Title screen of Tetris (+ScrollRect)

After the recent changes, we decided to try out another classic game, Tetris:

The sound was not yet working correctly, but at least the title screen appeared correctly. As the game wanted to use ScrollRect to scroll text in the small box at bottom, this gave us a good excuse to go on and implement it:

Scrolling text in the title screen

The first Dialog

Now with Window Manager traps starting to get implemented, we could start work on the Dialog Manager. Technically, dialogs depend a lot on the Window Manager, as every dialog is a window, which contains extra information to track dialog items in it. After adding support for static text dialog items, we were able to display the intro dialog of one of our favourite games:

First appearance of a Dialog in our emulator

Menu titles and first windows

Menu Manager update

After some work on the virtual MBDF code resource, and related Menu Manager routines, we now have menu titles visible on the menu bar:

The menu titles are for the first time visible on the menu bar

For testing purposes, we also switched the desktop pattern by adjusting the ‘PAT ‘ 16 resource.

Window Manager

At this point, we wanted to get work done on the actual Window Manager routines, so we chose a few of the most simple applications we had for guiding our development and testing the results. One of them was the really old “3-D Maze” app by Mark Frohnmayer. Having the Pascal source code for it, it was quite easy to trace what the 68K code in it was attempting to do, so we could handle any issues we encountered. As this application is not a full game, but rather a demonstration for a Dungeon Keeper/Wizardry style engine, it consisted mostly of DrawPicture and CopyBits calls into a window.

Even the first GetNewWindow call had a lot of dependencies to other Window Manager traps (not to mention the ShowWindow and SelectWindow later!), but we got soon the first window displayed on the screen:

The first ever window, with picture drawn into it by the 68K test app

As we focused on the actual Window Manager implementation, we left the default WDEF for now as a simple one-pixel frame (and added for testing regions a small drop shadow), the windows look quite plain at the moment, but that should be enough to get applications run further.

1000 miles creates a lot of windows!

We also tested the new Window Manager routines with another app, 1000 miles, which was quite interesting because unlike most applications, which usually have one or a few windows, it had literally a window for every possible part of it’s user interface.

The menu bar

Now that the test application is passing its runtime startup, it’s attempting to initialize various Toolbox managers, which of course gives us a good excuse to start work on the Menu and Window Managers, beginning from InitWindows.

The menu bar and desktop are some of the most iconic parts of the Mac user interface, and as these initialization routines set up these, we have something that is finally stating to look like a real Mac desktop. Another benefit of having file system at this point is that we can actually read the desktop pattern from ‘PAT ‘ resource ID 16 (using new GetPattern trap) from System file, like a real Mac does, and use that to paint the desktop.

First appearance of the menu bar

Another interesting new feature was the support of virtual code resources read from the System file, using a customized mixed-mode loading mechanism which allows inserting UPP record for a native C code resource, such as in this case MBDF, into the MBDF resource read from the System file – which in this case was used to draw the menu bar!

Mouse support

Now with the first application, a lot of work has been going into fixing the CPU bugs, and implementing missing toolbox APIs one by one as required by the test application. In middle of this though, we added one feature which is quite important to a graphical system: Mouse support.

There’s not much to tell about this new feature, as technically the implementation is pretty trivial, with mouse hardware abstraction and new mouse low mem globals.

Hopefully we can soon use the mouse support for something cool.

A simple mouse input test in the testbed. This test prints the coordinates and button state at mouse location, with text inverted when button is held down.

The “Launch” call

Resource Manager

Thanks to the earlier work done on Resource Manager for the “Fake” ROM resources, we already had rudimentary support for accessing resources. As the ROZ resource map was built to have exactly same format like “real” resource maps, the main missing features needed were reading and loading the resource map from resource fork using the recently added File Manager traps, and implementing further file reading operations in LoadResource trap.

Segment Loader

And now with ability to load resources, the first thing to logically do is to start work on the Segment Loader. The Launch trap is used to:

  • Handle launch parameters
  • Init application one (unless doing a “Chain” launch)
  • Load jump table from CODE resource ID 0
  • Set up the A5 world and copy jump table to correct place
  • Set up 68K state
  • Jump to application entry point in 68K code

At this point, we can now for the first time start running an actual 68K Mac application, although there were, and still are, a bunch of 68K cpu bugs to fix. At least, now we can test the CPU emulator with actual, real program code!

Resource map dump of the first actual Mac test application

First steps of File Manager

The NativeFS

After a short one-month break, and with Device Manager now working, we were finally able to start implementation of the virtual file system, dubbed NativeFS at this point. We use the virtual “.NativeFS” DRVR to mount the file system, which we for now install as ExtFS hook for File Manager. This way, we can make the file system appear as a foreign file system similar to AppleShare for Mac apps, increasing compatibility with apps which can handle those file systems correctly. Also, we can later add real MFS/HFS support to the actual File Manager level if we want.

We also abstracted the native file system layer in such a way, that we are not bound by a single storage solution, but have a native file system backend which we can change if needed, without needing to rebuild the entire NativeFS layer. After long and careful consideration, we decided to use AppleDouble as the first implementation, as it provided the best features for our requirements. Initially, we were thinking about using MacBinary (similar to AppleSingle), which would have made transferring files easier, but would have had much higher overhead in write operations, as having data and resource forks combined in a single file would have required moving the other fork back and forth when changing size of the fork preceding the other one in the file. On Mac OS X, we could have used the real HFS (recently APFS) metadata for catalog information and resource forks, but this way we have immediately support for running applications on other platforms. The file naming convention we used follows the UNIX convention documented by apple in the AppleSingle/AppleDouble Formats for Foreign Files Developer’s Note.

A partial listing of AppleDouble files in the virtual volume folder, with some of the metadata shown

File Manager

To make interfacing with File Manager easier in the long run, we decided to organize the files in memory as a tree structure, which has similar search properties as real HFS B-trees. This means, that we use CNID-Filename pair as catalog key, and include thread records to map CNIDs to file/folder records. Main difference compared to real HFS that instead of B-trees, which are optimized for on-disk storage, we use AVL-tree (which at the time of writing this is implemented just as a simple unbalanced binary tree)

Console debug dump of the binary tree containing files on virtual volume

The NativeFS to File Manager ExtFS bridge was inspired by Apple’s FSM (File System Manager) documentation, which detailed how to use FSM to implement path resolving and generally handling various File Manager calls, which actually matched quite closely to the ExtFS interface.

First file read

After a few weeks of hard coding, we finally got file reading to work, and did the first successful file read test, in which we fetched the data fork contents of a file on the virtual volume using newline mode.