DDirectorWikiDirector & Lingo Encyclopedia

Native Stage, Input, and Timing

Recovered projector flags, the presentation rect recompute (CenterStage/ResizeStage), window rebinding, the input dispatch pipeline, and score/timing native surfaces.

Projector startup and flags

Proj.dll parses projector settings from RT_STRING resources into a flag word. Decoded flags and bits:

ResourceSettingBit
0x57fAnimation0x800
0x580SystemFriendly0x2000
0x5aaEscapeOk0x2
0x5acFullScreen0x4
0x5adUseTitleBar0x8
0x5aeBackgroundAnimation0x10
0x5afSwitchColorDepth0x20
0x5b0CenterStage0x40
0x5b1ResizeStage0x80
0x5bbSingleInstance0x1000
0x5bcSingleTaskbarEntry0x10000

Use sites: FullScreen selects fullscreen IML32 window helpers (window flag 0x20000 vs 0x10000 windowed); CenterStage calls Dirapi ordinal 52 at setup; ResizeStage is inverted into ordinal 53; SwitchColorDepth calls ordinal 161; EscapeOk is inverted into ordinal 92.

The projector drives the runtime through a small ordinal API: forward the HWND and presentation flags (ordinals 86/87/92), pump idle/event processing (93), read-and-clear runtime status (94), enter/exit active drawing state (96/98).

IML32 window and rect helpers

Confirmed ordinals (building blocks of all presentation math):

OrdinalFunction
1060Write a rect (l, t, r, b).
1064Offset a rect by dx/dy.
1068Rect intersection test (strict < on all four edges).
1810Create the ImlWinCls HWND from a rect.
1815 / 1818Focus+activate / show+hide.
1820InvalidateRect + UpdateWindow (null rect = whole window).
1826Render an IML backing bitmap into an HWND (BeginPaint/GetDC + BITMAPINFO draw).
1832 / 1833 / 1834MoveWindow with child adjust / read+normalize client rect (menu-height aware) / move outer window so a client rect lands at a screen position.
2031Obtain display/screen bounds (per display index).

Splash/error windows demonstrate the pattern: build rect at origin (1060), get display bounds (2031), center via offset (1064), create (1810), draw (1826). Centering is rect construction before window creation, not post-hoc scaling.

The presentation record and rect recompute

The recovered stage-presentation routine (reached from CenterStage setup, FUN_680607fd in Dirapi.dll):

  1. Requires a live display/movie object (flag bit 0x8).
  2. Reads display 0's rect, aggregates all displays' bounds (ordinal 2031 loop).
  3. Builds the presentation candidate from the presentation record (x, y, width, height).
  4. If resize-stage is disabled (stored at +0x380) or the candidate is invalid, falls back to four authored shorts (+0x198...+0x19e).
  5. If center-stage (+0x378) is set, centers the candidate within display 0 (ordinal 1064).
  6. If the candidate intersects no display, recenters it.
  7. Commits via a helper that invalidates newly exposed bottom/right strips when shrinking, then stores origin and size on the presentation record (+0x8 x, +0xc y, +0x10 w, +0x14 h).
  8. Optionally moves the real window/client rect (ordinal 1834).

The architectural lesson: Director keeps three separate concepts that emulators routinely conflate:

  • logical stage coordinates (what Lingo sees),
  • the native presentation/window rect (the record above),
  • the backing/display surface (canvas, DPI).

Native code never treats the backing canvas or CSS-like element size as the coordinate system. Resize bugs in emulators (wall/floor desync, offset avatars, misplaced loaders) trace to mixing these spaces.

Window rebinding rebuilds channels

When the projector rebinds the runtime to a new HWND (ordinal 86 route), Dirapi writes the HWND into the display/window state block and then walks all sprite/channel entries (0x170 bytes each), dispatching per-type rebuild/reset routes that clear type fields, flags, and cached rect data. Native resize handling is a shared channel-state rebuild, never per-content offsets: the strongest possible argument against per-room resize hacks in emulators.

directToStage is likewise an operation mode: its property read temporarily toggles dispatch/draw state flags around channel calls rather than choosing a different renderer.

Input dispatch pipeline

Native surfaces proved by table/descriptor evidence: eventPassMode, dontPassEvent, sendSprite, sendAllSprites, stopEvent, mouseDown/Up(Script), mouseWithin/Leave/Enter, mouseStillDown, mouseUpOutSide (note the native capital S spelling: normalize event names, do not string-match), clickLoc, clickOn, doubleClick, lastClick/Roll/Event, mouseSprite, keyboardFocusSprite, editFocusSprite, plus the modifier and selection families. Mouse state descriptors (mouseH [0x40, 0x1af], mouseV [0x40, 0x1b0], doubleClick [0x40, 0x1bb]...) ride the simple descriptor branch documented in Native Lingo internals.

Two separately traceable native routes:

  1. Target selection: host coordinates -> stage coordinates -> candidate sprites from the last baked frame (front to back) -> per-candidate hit policy by member type and ink -> mouse-down/hover/up target retention.
  2. Event execution: selected target -> primary handler -> behaviors -> cast member -> frame -> movie, honoring pass/stopEvent/default behavior (message hierarchy).

Bug classification by layer (works for any engine):

LayerTypical symptom
Coordinate conversion (DPI, presentation rect)Clicks offset after resize
Candidate list (order, visibility, locZ)Front UI ignored
Hit policy (matte/key/text rules)Only some pixels clickable
Target retention (down vs up sprite)Buttons miss on release
Primary handlerHandler never fires
Propagation (order, pass, stopEvent)Wrong handler consumes
Timing (double-click, drag capture)Single click acts as double

Hit-policy cases still needing native microtests: mouseUp target when press and release differ; doubleClick timing and target-identity requirements; matte hit source (coverage stream vs simplified scan); background-transparent hits vs keyed pixels; editable-field focus consumption; drag capture semantics.

Score and timing surfaces

Native tables group the expected lifecycle/timing surface: prepareMovie, beginSprite, prepareFrame, enterFrame, exitFrame, actorList, frameTempo, updateStage, and the timeout family (timeout, timeoutScript/List/Handler/Length/Lapsed/Keydown/Mouse/Play). This proves the native surface and its grouping; exact handler order and timer cadence remain to be proved by native microtests (the documented order in Event lifecycle is the working model). Open timing questions worth microtesting: whether updateStage forces immediate paint or marks dirty; whether mouse movement pumps frame work; timeout firing position relative to exitFrame; actorList mutation during iteration.