# DirectDraw Notes

`Hwanse2.exe` imports `DDRAW.dll!DirectDrawCreate`. The import thunk is at
`0x00435d98`, and the confirmed call sites are `0x00415602` and `0x00415618`.

This file records the current static trace of the original video setup. The
generated review evidence lives in `out/directdraw_flow.html` and the structured
data lives in `out/directdraw_flow.json`.

## Import And Entry

`out/exe_imports.json` confirms:

| import | thunk | call sites |
| --- | --- | --- |
| `DirectDrawCreate` | `0x00435d98` | `0x00415602`, `0x00415618` |

The setup function at `0x004155e0` calls `DirectDrawCreate` with device selector
`0` or `2`, depending on graphics flag `0x004676d4`, and stores the resulting
`IDirectDraw*` in global `0x004676c0`.

Relevant globals:

| global | current name | note |
| --- | --- | --- |
| `0x004676c0` | `IDirectDraw*` | DirectDraw object |
| `0x004676c4` | `IDirectDrawPalette*` | DirectDraw palette |
| `0x004676c8` | `IDirectDrawClipper*` | windowed clipper |
| `0x004676cc` | last HRESULT/error | setup and draw paths write failures here |
| `0x004676d4` | graphics flags | controls fullscreen/windowed/device branches |
| `0x004676ec` | display mode selector | mode branch used by setup |
| `0x004676f0` | window handle | passed to cooperative level / clipper |

## Mode Setup

The confirmed display target is `640x480x8`.

| address | object | vtable offset | likely method | arguments |
| --- | --- | ---: | --- | --- |
| `0x00415660` | `IDirectDraw*` | `0x50` | `SetCooperativeLevel` | flags `0x00000008` |
| `0x0041568d` | `IDirectDraw*` | `0x50` | `SetCooperativeLevel` | flags `0x00000011` |
| `0x004156c8` | `IDirectDraw*` | `0x54` | `SetDisplayMode` | `640, 480, 8` |

The `0x00000011` path matches the usual exclusive fullscreen flags, while
`0x00000008` is the windowed/normal candidate.

## Surfaces

Surface wrapper records are indexed from `0x0055abd8`. The setup path creates a
front/primary wrapper, an offscreen/back wrapper, and in flip mode an attached
backbuffer wrapper.

| slot | wrapper global | role |
| ---: | --- | --- |
| `0` | `0x0055abd8` | primary/front surface wrapper |
| `1` | `0x0055abdc` | offscreen/back surface wrapper |
| `0xbf` | `0x0055aed4` | attached backbuffer wrapper |

Important creation and attachment calls:

| address | object | vtable offset | likely method | note |
| --- | --- | ---: | --- | --- |
| `0x00415766` | `IDirectDraw*` | `0x18` | `CreateSurface` | primary flipping candidate; caps include `0x218` |
| `0x0041579d` | `IDirectDraw*` | `0x18` | `CreateSurface` | simple primary candidate; caps `0x200` |
| `0x00415836` | `IDirectDrawSurface*` | `0x30` | `GetAttachedSurface` | attached backbuffer lookup |
| `0x004158d1` | `IDirectDraw*` | `0x18` | `CreateSurface` | offscreen `640x480` candidate |
| `0x00415a0f` | `IDirectDraw*` | `0x18` | `CreateSurface` | alternate offscreen `640x480` candidate |
| `0x00415a9f` | `IDirectDraw*` | `0x10` | `CreateClipper` | windowed clipper global `0x004676c8` |
| `0x00415ad6` | `IDirectDrawClipper*` | `0x20` | `SetHWnd` | attaches `0x004676f0` |
| `0x00415b0f` | `IDirectDrawSurface*` | `0x70` | `SetClipper` | applies clipper to the primary surface |

## Palette

The palette allocation path creates a 256-entry `PALETTEENTRY` block:

| global | note |
| --- | --- |
| `0x004676e4` | palette header/allocation |
| `0x004676e8` | first raw palette entry |

The header writes `0x0300` as the version field and `0x0100` as the entry count.
The palette is created at `0x0041652e` through `IDirectDraw::CreatePalette`
and applied to the primary surface through `IDirectDrawSurface::SetPalette` at
`0x00416555` and `0x00416606`. Palette ranges are updated through
`IDirectDrawPalette::SetEntries` at `0x00416649` and `0x00416708`.

## Presentation

The original renderer presents through both fullscreen flip and blit/copy
paths:

| address | object | vtable offset | likely method | note |
| --- | --- | ---: | --- | --- |
| `0x0041769b` | `IDirectDrawSurface*` | `0x2c` | `Flip` | fullscreen/page-flip path |
| `0x00417722` | `IDirectDrawSurface*` | `0x14` | `Blt` | copy/update path |
| `0x0041784b` | `IDirectDrawSurface*` | `0x14` | `Blt` | copy/update path |
| `0x00417938` | `IDirectDrawSurface*` | `0x14` | `Blt` | copy/update path |
| `0x00417b4b` | `IDirectDrawSurface*` | `0x14` | `Blt` | windowed/scaled copy path |
| `0x00417b8a` | `IDirectDrawSurface*` | `0x14` | `Blt` | windowed/scaled copy path |
| `0x00417bdf` | `IDirectDrawSurface*` | `0x14` | `Blt` | windowed/scaled copy path |

## Verified Call Sequence

`out/directdraw_flow.json` currently records 25 DirectDraw-related vtable calls,
and all 25 rows have the expected vtable offset verified. This sequence is a
call-surface trace: it grounds the API surface and the broad setup/presentation
phases, but it does not yet prove the exact dirty-rectangle ordering or every
surface composition step.

Method counts:

| method | count |
| --- | ---: |
| `SetCooperativeLevel` | 2 |
| `SetDisplayMode` | 1 |
| `CreateSurface` | 4 |
| `GetAttachedSurface` | 2 |
| `CreateClipper` | 1 |
| `SetHWnd` | 1 |
| `SetClipper` | 1 |
| `CreatePalette` | 1 |
| `SetPalette` | 2 |
| `SetEntries` | 2 |
| `GetEntries` | 1 |
| `Flip` | 1 |
| `Blt` | 6 |

Full verified sequence:

| # | VA | Interface | Method | Offset | Role | Notes |
| ---: | --- | --- | --- | --- | --- | --- |
| 1 | `0x00415660` | `IDirectDraw` | `SetCooperativeLevel` | `0x50` | windowed cooperative level candidate | flags `0x00000008` |
| 2 | `0x0041568d` | `IDirectDraw` | `SetCooperativeLevel` | `0x50` | exclusive fullscreen cooperative level | flags `0x00000011` |
| 3 | `0x004156c8` | `IDirectDraw` | `SetDisplayMode` | `0x54` | fullscreen display mode | `640x480x8` |
| 4 | `0x00415766` | `IDirectDraw` | `CreateSurface` | `0x18` | primary flipping surface candidate | `DDSD_CAPS|DDSD_BACKBUFFERCOUNT`, caps `0x218` |
| 5 | `0x0041579d` | `IDirectDraw` | `CreateSurface` | `0x18` | simple primary surface candidate | `DDSD_CAPS`, caps `0x200` |
| 6 | `0x00415836` | `IDirectDrawSurface` | `GetAttachedSurface` | `0x30` | attached backbuffer lookup | caps `0x00000004` |
| 7 | `0x004158d1` | `IDirectDraw` | `CreateSurface` | `0x18` | offscreen 640x480 surface candidate | `DDSD_CAPS|HEIGHT|WIDTH`, caps include `0x40` |
| 8 | `0x0041596f` | `IDirectDrawSurface` | `GetAttachedSurface` | `0x30` | attached backbuffer lookup | caps `0x00000004` |
| 9 | `0x00415a0f` | `IDirectDraw` | `CreateSurface` | `0x18` | offscreen 640x480 surface candidate | `DDSD_CAPS|HEIGHT|WIDTH`, caps include `0x40` |
| 10 | `0x00415a9f` | `IDirectDraw` | `CreateClipper` | `0x10` | windowed clipper creation | out `0x004676c8` |
| 11 | `0x00415ad6` | `IDirectDrawClipper` | `SetHWnd` | `0x20` | clipper `SetHWnd` candidate | hwnd `0x004676f0` |
| 12 | `0x00415b0f` | `IDirectDrawSurface` | `SetClipper` | `0x70` | primary `SetClipper` candidate | clipper `0x004676c8` |
| 13 | `0x0041652e` | `IDirectDraw` | `CreatePalette` | `0x14` | palette creation | 256-entry palette buffer |
| 14 | `0x00416555` | `IDirectDrawSurface` | `SetPalette` | `0x7c` | primary `SetPalette` | palette `0x004676c4` |
| 15 | `0x00416606` | `IDirectDrawSurface` | `SetPalette` | `0x7c` | refresh primary `SetPalette` | palette `0x004676c4` |
| 16 | `0x00416649` | `IDirectDrawPalette` | `SetEntries` | `0x18` | `SetEntries` | writes changed palette range |
| 17 | `0x00416708` | `IDirectDrawPalette` | `SetEntries` | `0x18` | `SetEntries` | writes changed palette range |
| 18 | `0x00416856` | `IDirectDrawPalette` | `GetEntries` | `0x10` | `GetEntries` | reads palette range |
| 19 | `0x0041769b` | `IDirectDrawSurface` | `Flip` | `0x2c` | `Flip` | fullscreen/page-flip path |
| 20 | `0x00417722` | `IDirectDrawSurface` | `Blt` | `0x14` | `Blt` | copy/update path |
| 21 | `0x0041784b` | `IDirectDrawSurface` | `Blt` | `0x14` | `Blt` | copy/update path |
| 22 | `0x00417938` | `IDirectDrawSurface` | `Blt` | `0x14` | `Blt` | copy/update path |
| 23 | `0x00417b4b` | `IDirectDrawSurface` | `Blt` | `0x14` | `Blt` | windowed/scaled copy path |
| 24 | `0x00417b8a` | `IDirectDrawSurface` | `Blt` | `0x14` | `Blt` | windowed/scaled copy path |
| 25 | `0x00417bdf` | `IDirectDrawSurface` | `Blt` | `0x14` | `Blt` | windowed/scaled copy path |

The admin format review page mirrors this table in `DirectDraw 호출 시퀀스`
and exposes the browser marker
`browserFormatDirectDrawCallSequenceImplemented=true`.

## Field Vs Battle Draw Unit Model

`out/render_pipeline_model_review.json` consolidates the current static evidence
for the engine layer immediately above DirectDraw.

- Field maps are tilemap-driven. The confirmed visible grid is 37x21 tiles, with
  dirty/visible bytes at `0x005957d0 + y * 37 + x`, live layer1 flags at
  `0x0058d7d0 + index * 2`, live layer0 tile ids at `0x00595af0 + index * 2`,
  camera tile position at `0x004576dc/de`, and map width at `0x00595ada`.
- Field layer1 bit `0x40` is grounded as a redraw invalidation input: the
  viewport scan tests the bit and marks the visible dirty grid. That path does
  not select alternate tile ids or animation frames.
- The inspected field tile draw path converts the current live layer0 tile id to
  a source rect with wrapper metadata: width `wrapper+0x2e`, height
  `wrapper+0x30`, and columns `wrapper+0x32`.
- Battle rendering is object/sprite/effect-driven. Active objects use
  `object+0x28` as a packed draw-source selector: low word is the source
  rect/frame index and high word is the surface slot looked up from
  `0x0055abd8`. Projected draw coordinates are read from `object+0x1c/+0x20`
  as fixed 16.16 values.

This means the DirectDraw API surface is shared, but field and battle diverge in
the game engine before `Blt`/`Flip` is called.

## Web Runtime Implications

- The browser runtime should continue treating the source resolution as
  `640x480` and scale the canvas presentation, not reinterpret the original
  assets as a higher-resolution native layout.
- The original video path is palette-based, so CNS palette decoding and
  palette-entry preservation remain useful for visual fidelity.
- This report grounds the DirectDraw setup only. It does not promote route
  transitions, event execution, or combat behavior.

## Remaining Work

- Trace the exact draw-order and dirty-rectangle routines around the `Blt`
  paths.
- Identify which `Blt` calls correspond to whole-surface copy, dirty-rect
  invalidation, and windowed scaling.
- Tie sprite/object draw records to the surface wrapper table more precisely.
- Decode draw flags, including source color-key requests, as call/context state
  rather than treating CNS transparency as sufficient by itself.
- Reconcile the `Flip` path and the windowed `Blt` path against mode flags
  `0x004676d4` and display selector `0x004676ec`.
- Keep event and route proof gates separate from this renderer evidence.
