Status notation

Each entry carries one of: Implemented — works as expected, Partial — works for the common case with documented gaps, Stub — compiles, returns success, performs no real work, Not supported — absent or always errors.

Contents


Global function

DirectDrawCreate function Partial
HRESULT WINAPI DirectDrawCreate(
    const GUID* lpGUID,
    LPDIRECTDRAW* lplpDD,
    IUnknown*     pUnkOuter
);

Creates a new DirectDraw device object backed by an SDL3 renderer. This is the entry point for all DirectDraw usage.

Parameters

ParameterTypeDirectionDescription
lpGUIDconst GUID*in Ignored. In the original API this selects a specific DirectDraw driver (NULL = primary display driver, a specific GUID = a secondary adapter). free-direct always creates one SDL-backed instance regardless of this value.
lplpDDLPDIRECTDRAW*out Receives the pointer to the newly created IDirectDraw object. Must not be NULL. The returned object has an initial reference count of 1. Caller must call Release() when done.
pUnkOuterIUnknown*in Must be NULL. COM aggregation is not supported. Passing a non-NULL value returns DDERR_INVALIDPARAMS.

Return values

DD_OKObject created successfully.
DDERR_INVALIDPARAMSlplpDD is NULL, or pUnkOuter is non-NULL.
DDERR_OUTOFMEMORYHeap allocation for the internal object failed.

Ownership and lifetime

Caller owns the returned object. Call Release() exactly once when done. All surfaces, palettes, and clippers created through this object hold their own references and are independent.

Behavioral difference from original DirectX 3

The original function consults the DirectDraw driver registry and can fail if no display driver is installed. free-direct always succeeds on any SDL3-capable platform.

IDirectDraw interface

Returned by DirectDrawCreate. Provides top-level device operations: cooperative level, display mode, and object factories for surfaces, palettes, and clippers.

typedef struct IDirectDraw* LPDIRECTDRAW;
IDirectDraw::AddRef method Implemented
ULONG WINAPI AddRef();

Increments the internal reference count by 1. Returns the new count.

Thread-safe: uses std::atomic<ULONG> internally.

IDirectDraw::Release method Implemented
ULONG WINAPI Release();

Decrements the reference count by 1 and returns the new count. When the count reaches 0, the object is destroyed:

  • The SDL renderer is destroyed (SDL_DestroyRenderer).
  • The window is restored from fullscreen via FreeApiSetWindowFullscreen(false).
  • The SDL window handle is released (but not destroyed — the window belongs to the caller).
IDirectDraw::QueryInterface method Stub
HRESULT WINAPI QueryInterface(const GUID& riid, void** ppvObject);

Always returns DDERR_UNSUPPORTED. COM interface promotion (e.g. to IDirectDraw2, IDirectDraw4) is not implemented.

IDirectDraw::SetCooperativeLevel method Partial
HRESULT WINAPI SetCooperativeLevel(HWND hWnd, DWORD dwFlags);

Associates the DirectDraw object with a window, creates the SDL renderer for that window, and optionally requests fullscreen mode. Must be called before any surfaces are created.

Parameters

ParameterTypeDirectionDescription
hWndHWNDin Handle to the application window. free-api uses SDL windows internally; the HWND is a reinterpret-cast of SDL_Window*. Must not be NULL — returns DDERR_INVALIDPARAMS if NULL.
dwFlagsDWORDin Cooperative level flags. See DDSCL_* flags below. The combination actually determines windowed vs. fullscreen behavior.

What happens internally

  1. Stores hWnd and casts it to SDL_Window*.
  2. If DDSCL_FULLSCREEN: calls FreeApiSetWindowFullscreen(true).
  3. If DDSCL_NORMAL: calls FreeApiSetWindowFullscreen(false).
  4. Destroys any pre-existing renderer attached to the window (legacy re-init pattern).
  5. Calls SDL_CreateRenderer(sdlWindow, NULL) to create a hardware-accelerated renderer.
  6. If the default renderer fails, falls back to SDL_CreateRenderer(sdlWindow, "software").
  7. Enables VSync via SDL_SetRenderVSync(renderer, 1) unless FREE_DIRECT_ENABLE_VSYNC=0.

Return values

DD_OKRenderer created successfully.
DDERR_INVALIDPARAMShWnd is NULL.
DDERR_GENERICBoth default and software renderer creation failed.

Limitations vs. original DirectX 3

  • Does not acquire exclusive hardware access.
  • DDSCL_EXCLUSIVE is accepted but provides no additional privilege.
  • Multiple calls on the same object destroy and recreate the renderer.
IDirectDraw::SetDisplayMode method Partial
HRESULT WINAPI SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP);

Stores the game's logical rendering resolution and requests fullscreen mode. Does not change the physical display resolution.

Parameters

ParameterTypeDirectionDescription
dwWidthDWORDin Logical width in pixels (e.g. 640). Stored internally as displayModeWidth_ and used as the primary surface width when CreateSurface is subsequently called with DDSCAPS_PRIMARYSURFACE.
dwHeightDWORDin Logical height in pixels (e.g. 480). Stored as displayModeHeight_.
dwBPPDWORDin Bits per pixel requested (e.g. 8, 16, 32). Stored but not used by the current implementation. Primary surface BPP is always determined by the DDPIXELFORMAT field in CreateSurface, or defaults to 32-bit when none is provided.

Side effect

Calls FreeApiSetWindowFullscreen(hwnd_, true) if a window has already been associated via SetCooperativeLevel. SDL3's logical presentation (letterbox scaling) is applied at first present.

Return values

DD_OKAlways returned (values are stored unconditionally).
IDirectDraw::CreateSurface method Partial
HRESULT WINAPI CreateSurface(
    const DDSURFACEDESC*  lpDDSurfaceDesc,
    LPDIRECTDRAWSURFACE*  lplpDDSurface,
    IUnknown*             pUnkOuter
);

Creates a DirectDraw surface object. Allocates a CPU pixel buffer immediately. The exact type and dimensions depend on the descriptor.

Parameters

ParameterTypeDirectionDescription
lpDDSurfaceDescconst DDSURFACEDESC*in Pointer to a filled DDSURFACEDESC structure. dwSize must equal sizeof(DDSURFACEDESC). Must not be NULL.
lplpDDSurfaceLPDIRECTDRAWSURFACE*out Receives the new surface pointer. Must not be NULL. The returned object has an initial reference count of 1.
pUnkOuterIUnknown*in Must be NULL. Returns DDERR_INVALIDPARAMS if non-NULL.

Supported surface types (determined by ddsCaps.dwCaps)

Cap flagBehavior
DDSCAPS_PRIMARYSURFACE Creates the primary surface. Dimensions: uses displayModeWidth_ × displayModeHeight_ if SetDisplayMode was called, otherwise defaults to 640 × 480. BPP: 32-bit (unless the descriptor sets DDPF_PALETTEINDEXED8). The descriptor's dwWidth/ dwHeight fields are ignored for the primary surface. Cannot be combined with any offscreen cap.
DDSCAPS_OFFSCREENPLAIN Creates an offscreen surface. Requires DDSD_WIDTH | DDSD_HEIGHT in dwFlags. BPP comes from ddpfPixelFormat.dwRGBBitCount if DDSD_PIXELFORMAT is set, otherwise defaults to 32. Only 8 and 32 are accepted; any other value is promoted to 32.
DDSCAPS_SYSTEMMEMORY Treated identically to DDSCAPS_OFFSCREENPLAIN. Used by legacy code to explicitly request a CPU-side surface.

Return values

DD_OKSurface created.
DDERR_INVALIDPARAMSNULL pointer, wrong dwSize, invalid cap combination, or missing width/height for offscreen.
DDERR_OUTOFMEMORYPixel buffer allocation failed.

Pixel buffer layout after creation

  • 8-bit: width × height bytes, one byte per pixel = palette index.
  • 32-bit: width × height × 4 bytes, four bytes per pixel in R,G,B,A order.
  • All pixels initialized to 0.
IDirectDraw::CreatePalette method Implemented
HRESULT WINAPI CreatePalette(
    DWORD                dwFlags,
    LPPALETTEENTRY       lpColorTable,
    LPDIRECTDRAWPALETTE* lplpDDPalette,
    IUnknown*            pUnkOuter
);

Creates a palette object holding up to 256 color entries.

Parameters

ParameterTypeDirectionDescription
dwFlagsDWORDin Capability flags. DDPCAPS_8BIT (0x4) is the expected value for 256-entry 8-bit palettes. The flag is stored but not further interpreted; all palettes are always 256 entries.
lpColorTableLPPALETTEENTRYin Pointer to an array of 256 PALETTEENTRY values. If NULL, all 256 entries are initialized to {0,0,0,0} (black, opaque).
lplpDDPaletteLPDIRECTDRAWPALETTE*out Receives the new palette pointer. Must not be NULL. Initial reference count is 1.
pUnkOuterIUnknown*in Must be NULL.

Return values

DD_OKPalette created.
DDERR_INVALIDPARAMSlplpDDPalette is NULL or pUnkOuter is non-NULL.
DDERR_OUTOFMEMORYAllocation failed.
IDirectDraw::CreateClipper method Implemented
HRESULT WINAPI CreateClipper(
    DWORD                 dwFlags,
    LPDIRECTDRAWCLIPPER*  lplpDDClipper,
    IUnknown*             pUnkOuter
);

Creates a clipper object. In free-direct the clipper's main function is to signal that a surface is operating in windowed mode, enabling automatic screen-to-client coordinate translation during Blt calls on the primary surface.

Parameters

ParameterTypeDirectionDescription
dwFlagsDWORDin Ignored. Pass 0.
lplpDDClipperLPDIRECTDRAWCLIPPER*out Receives the new clipper pointer. Initial reference count is 1.
pUnkOuterIUnknown*in Must be NULL.

Return values

DD_OKClipper created.
DDERR_INVALIDPARAMSlplpDDClipper is NULL or pUnkOuter non-NULL.
DDERR_OUTOFMEMORYAllocation failed.

IDirectDrawSurface interface

The main rendering surface. Obtained via IDirectDraw::CreateSurface. Represents either the primary surface (what is displayed) or an offscreen surface (used as a back buffer, sprite sheet, or scratch space).

typedef struct IDirectDrawSurface* LPDIRECTDRAWSURFACE;
IDirectDrawSurface::AddRef / Release method Implemented
ULONG WINAPI AddRef();
ULONG WINAPI Release();

Standard reference counting. When Release() reaches 0:

  • The SDL texture (if any) is destroyed via SDL_DestroyTexture.
  • The attached palette (if any) has its reference released.
  • The attached clipper (if any) has its reference released.
  • Any attached DC is destroyed via FreeApiDestroySurfaceDC.
  • The CPU pixel buffer (std::vector<uint8_t>) is freed.
IDirectDrawSurface::QueryInterface method Stub
HRESULT WINAPI QueryInterface(const GUID& riid, void** ppvObject);

Always returns DDERR_UNSUPPORTED. Interface promotion not implemented.

IDirectDrawSurface::Blt method Partial
HRESULT WINAPI Blt(
    LPRECT               lpDestRect,
    LPDIRECTDRAWSURFACE  lpDDSrcSurface,
    LPRECT               lpSrcRect,
    DWORD                dwFlags,
    LPDDBLTFX            lpDDBltFx
);

General-purpose blit. Operates entirely in CPU memory. Two modes are supported: color fill (when DDBLT_COLORFILL is set) and surface-to-surface copy (when lpDDSrcSurface is non-NULL).

Parameters

ParameterTypeDirectionDescription
lpDestRectLPRECTin Destination rectangle on this surface. If NULL, the entire surface is the destination. Coordinates are clamped to surface bounds.

Windowed coordinate adjustment: when this surface is the primary surface and has a clipper attached, the rectangle is adjusted from screen coordinates to window-local coordinates by subtracting the SDL window position (SDL_GetWindowPosition). This compensates for legacy game code that converts client coords to screen coords before blitting.
lpDDSrcSurfaceLPDIRECTDRAWSURFACEin Source surface for surface-to-surface copy. Pass NULL when using DDBLT_COLORFILL.
lpSrcRectLPRECTin Source rectangle on lpDDSrcSurface. If NULL, the entire source surface is used. Coordinates are clamped to source surface bounds.
dwFlagsDWORDin Bitmask of DDBLT_* flags controlling the blit mode. The most important flags are:
  • DDBLT_COLORFILL — fill destination with lpDDBltFx->dwFillColor.
  • DDBLT_KEYSRC — apply source color key transparency.
  • DDBLT_WAIT — accepted, no-op.
  • DDBLT_ROTATIONANGLE — accepted, rotation NOT performed.
lpDDBltFxLPDDBLTFXin Pointer to a DDBLTFX structure providing effect parameters. Required when DDBLT_COLORFILL is set (returns DDERR_INVALIDPARAMS if NULL in that case). Ignored for plain surface-to-surface blits.

Color fill mode (DDBLT_COLORFILL)

Fills the destination rectangle with a solid color from lpDDBltFx->dwFillColor:

  • 32-bit surfaces: dwFillColor = 0x00RRGGBB. Alpha byte is set to 255 (opaque).
  • 8-bit surfaces: the low byte of dwFillColor is used as the palette index. The color key value 0 makes index 0 transparent in subsequent blits.

Surface-to-surface copy

Copies pixels from the source surface rectangle to the destination rectangle:

  • Nearest-neighbor scaling when source and destination rectangles have different sizes.
  • Only 8→8 and 32→32 bit depth combinations are handled. Mixed depths (8→32 or 32→8) skip all pixels silently.
  • Source color key is applied when DDBLT_KEYSRC is set and the source has a color key (see SetColorKey).

Auto-present behavior

If the destination is the primary surface, owner->renderer_ is non-NULL, and Flip() has never been called on the owning IDirectDraw instance, PresentPrimary is called automatically after a successful blit. This supports the Speedy Blupi pattern of blitting directly to the primary without a separate Flip call.

Return values

DD_OKBlit completed (or fill completed).
DDERR_INVALIDPARAMSCOLORFILL without DDBLTFX, or source surface type mismatch.
DDERR_UNSUPPORTEDUnsupported flag combination (no source, no fill).
IDirectDrawSurface::BltFast method Implemented
HRESULT WINAPI BltFast(
    DWORD                dwX,
    DWORD                dwY,
    LPDIRECTDRAWSURFACE  lpDDSrcSurface,
    LPRECT               lpSrcRect,
    DWORD                dwTrans
);

Fast surface-to-surface copy without scaling. Copies the source rectangle to position (dwX, dwY) on this surface. The destination rectangle is always the same size as the source rectangle.

Parameters

ParameterTypeDirectionDescription
dwXDWORDin X coordinate of the top-left corner of the destination on this surface.
dwYDWORDin Y coordinate of the top-left corner of the destination on this surface.
lpDDSrcSurfaceLPDIRECTDRAWSURFACEin Source surface. Must not be NULL; returns DDERR_INVALIDPARAMS if NULL.
lpSrcRectLPRECTin Source rectangle. If NULL, the entire source surface is copied. The destination area is computed as (dwX, dwY, dwX + srcWidth, dwY + srcHeight).
dwTransDWORDin Transparency flags. See DDBLTFAST_*:
  • DDBLTFAST_NOCOLORKEY (0): copy all pixels including those matching the color key.
  • DDBLTFAST_SRCCOLORKEY (1): skip pixels whose value falls within the source color key range.

Return values

DD_OKCopy completed.
DDERR_INVALIDPARAMSlpDDSrcSurface is NULL or type mismatch.

Auto-present behavior is the same as Blt.

IDirectDrawSurface::Flip method Partial
HRESULT WINAPI Flip(
    LPDIRECTDRAWSURFACE  lpDDSurfaceTargetOverride,
    DWORD                dwFlags
);

Presents the primary surface to the screen by uploading the CPU pixel buffer to SDL and calling SDL_RenderPresent. This is not a real DirectDraw page flip. There is no flip chain; only the primary surface's CPU buffer is presented.

Parameters

ParameterTypeDirectionDescription
lpDDSurfaceTargetOverrideLPDIRECTDRAWSURFACEin Ignored. In the original API this selects a specific surface from a flip chain.
dwFlagsDWORDin Ignored. In the original API controls flip timing (DDFLIP_WAIT etc.).

Effect of calling Flip

After the first call to Flip():

  • owner_->usesFlip_ is set to true.
  • Auto-present from Blt / BltFast is disabled.
  • Flip() becomes the only way to update the screen.

Presentation pipeline (called internally)

  1. Frame throttle: if called within the frame interval (default 1000 ms / 60 = 16.67 ms) since the last present, returns DD_OK immediately.
  2. Dirty check: if the primary surface pixel buffer has not been written since the last present, skips upload and present.
  3. Palette expansion (8-bit only): expands all pixel indices to RGBA32 using the attached palette (or a default 3:3:2 palette if none is attached). Uses a cached paletteConvertBuffer_ to avoid per-frame heap allocation.
  4. Texture upload: SDL_UpdateTexture uploads the pixel data to a cached streaming SDL_Texture (RGBA32, STREAMING access).
  5. Render clear: SDL_RenderClear with black.
  6. Logical presentation (once): SDL_SetRenderLogicalPresentation(renderer, W, H, SDL_LOGICAL_PRESENTATION_LETTERBOX) is called on the first present to set up letterbox scaling.
  7. Render: SDL_RenderTexture(renderer, texture, NULL, NULL).
  8. Present: SDL_RenderPresent exactly once.

Return values

DD_OKPresent complete (or skipped due to throttle/dirty check).
DDERR_UNSUPPORTEDCalled on a non-primary surface, or no renderer available.
DDERR_GENERICSDL texture creation failed.
IDirectDrawSurface::Lock method Implemented
HRESULT WINAPI Lock(
    LPRECT           lpDestRect,
    LPDDSURFACEDESC  lpDDSurfaceDesc,
    DWORD            dwFlags,
    HANDLE           hEvent
);

Provides direct CPU access to the surface's pixel buffer. Returns a pointer to the pixel data via lpDDSurfaceDesc->lpSurface. The lock is always immediately available — there is no GPU synchronization.

Parameters

ParameterTypeDirectionDescription
lpDestRectLPRECTin Accepted but ignored. In the original API, a partial lock returns a pointer offset into the buffer. free-direct always returns a pointer to the full buffer beginning regardless of lpDestRect.
lpDDSurfaceDescLPDDSURFACEDESCin/out Caller must fill dwSize = sizeof(DDSURFACEDESC) before calling. On success, the following fields are filled:
  • dwFlags: set to indicate valid fields.
  • dwWidth, dwHeight: surface dimensions.
  • lPitch: bytes per row = width × (bpp / 8).
  • lpSurface: pointer directly into the std::vector<uint8_t>.
  • ddsCaps.dwCaps: DDSCAPS_PRIMARYSURFACE or DDSCAPS_OFFSCREENPLAIN.
  • ddpfPixelFormat: bit count and format flags.
dwFlagsDWORDin Ignored. In the original API: DDLOCK_WAIT, DDLOCK_READONLY, DDLOCK_WRITEONLY. free-direct always returns the buffer immediately.
hEventHANDLEin Ignored. Pass NULL.

Return values

DD_OKLock successful; lpDDSurfaceDesc->lpSurface is valid.
DDERR_INVALIDPARAMSlpDDSurfaceDesc is NULL or dwSize is wrong.
Dirty flag note

Writing to the pixel buffer via the lpSurface pointer does not automatically mark the primary surface dirty. After modifying pixels directly, call a blit method (even a no-op blit) to trigger the dirty flag, or the changes may not appear until the next frame that is dirty for another reason.

IDirectDrawSurface::Unlock method Implemented
HRESULT WINAPI Unlock(LPVOID lpSurfaceData);

No-op. Always returns DD_OK. The lpSurfaceData parameter is ignored. There is no hardware lock to release and the pixel buffer pointer remains valid.

IDirectDrawSurface::GetSurfaceDesc method Implemented
HRESULT WINAPI GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc);

Fills a DDSURFACEDESC with the current surface properties. Caller must set dwSize = sizeof(DDSURFACEDESC) before calling. Returns the same information as Lock but without providing a pixel pointer for primary surfaces.

Parameters

ParameterTypeDirectionDescription
lpDDSurfaceDescLPDDSURFACEDESCout Must not be NULL. Must have dwSize = sizeof(DDSURFACEDESC). Fields filled: dwFlags, dwWidth, dwHeight, ddsCaps, ddpfPixelFormat. For offscreen surfaces: also lPitch and lpSurface.

Return values

DD_OKDescriptor filled.
DDERR_INVALIDPARAMSNULL pointer or wrong dwSize.
IDirectDrawSurface::SetColorKey method Partial
HRESULT WINAPI SetColorKey(DWORD dwFlags, LPDDCOLORKEY lpDDColorKey);

Sets the color key for transparent blits from this surface. Only source blit color keys are supported.

Parameters

ParameterTypeDirectionDescription
dwFlagsDWORDin Must be DDCKEY_SRCBLT (0x8). Any other value returns DDERR_UNSUPPORTED. Destination color keys and overlay color keys are not implemented.
lpDDColorKeyLPDDCOLORKEYin Pointer to a DDCOLORKEY structure defining the transparent range. If NULL, clears the color key (disables transparency).

Color key comparison semantics

Surface BPPComparison
8-bit The palette index byte is compared against dwColorSpaceLowValue and dwColorSpaceHighValue. Pixel is transparent if index >= low && index <= high.
32-bit Two comparisons are performed:
  1. Raw: packed 4-byte pixel value vs. key range.
  2. RGB-masked: alpha byte zeroed in both pixel and key, then compared.
Pixel is transparent if either comparison matches. This handles keys generated by the DDColorMatch pattern (GetDC/SetPixel/GetPixel).

Return values

DD_OKColor key stored.
DDERR_UNSUPPORTEDdwFlags is not DDCKEY_SRCBLT.
IDirectDrawSurface::SetPalette method Implemented
HRESULT WINAPI SetPalette(LPDIRECTDRAWPALETTE lpDDPalette);

Associates a palette with this surface. Reference-counted.

Parameters

ParameterTypeDirectionDescription
lpDDPaletteLPDIRECTDRAWPALETTEin The palette to attach. If non-NULL, AddRef() is called on it. The previous palette (if any) has Release() called. Pass NULL to detach the current palette.

Effect

  • On an 8-bit primary surface: the palette is used during PresentPrimary to expand indices to RGBA32. If no palette is set, a default 3:3:2 palette is used.
  • On an 8-bit offscreen surface: the palette is used during GetDC (expansion to RGBA32) and ReleaseDC (nearest-match quantization).
  • On 32-bit surfaces: the palette is stored but has no effect on rendering.

Return values

DD_OKAlways returned.
IDirectDrawSurface::SetClipper method Implemented
HRESULT WINAPI SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper);

Associates a clipper with this surface. Reference-counted.

Parameters

ParameterTypeDirectionDescription
lpDDClipperLPDIRECTDRAWCLIPPERin Clipper to attach. If non-NULL, AddRef() is called. Previous clipper is released. Pass NULL to detach.

Effect

The presence of a clipper on the primary surface activates windowed-mode coordinate adjustment in Blt: destination rectangles expressed in screen coordinates are translated to window-local coordinates by subtracting the SDL window's position.

Return values

DD_OKAlways returned.
IDirectDrawSurface::IsLost method Stub
HRESULT WINAPI IsLost();

Always returns DD_OK (not lost). Surfaces in free-direct are CPU-resident and never lose their content. Legacy game code that polls IsLost() in a loop will not spin.

IDirectDrawSurface::Restore method Stub
HRESULT WINAPI Restore();

Always returns DD_OK. No restoration is needed.

IDirectDrawSurface::GetDC method Partial
HRESULT WINAPI GetDC(HDC* lphDC);

Returns a GDI-compatible device context backed by the surface's pixel buffer. Needed by the DDColorMatch pattern: GetDCSetPixelLock → read index back → UnlockReleaseDC.

Parameters

ParameterTypeDirectionDescription
lphDCHDC*out Receives the HDC. Must not be NULL.

Behavior by surface format

FormatBehavior
32-bit DC is created directly over the CPU pixel buffer via FreeApiCreateSurfaceDC(pixels, w, h, pitch, 32). Modifications are immediately visible in the pixel buffer.
8-bit A temporary 32-bit RGBA buffer is allocated (dcTempBuffer_). The 256 palette entries are read, then each pixel index is expanded to RGBA. The DC is created over this temporary buffer. See ReleaseDC for how changes are written back.

Return values

DD_OKDC returned in *lphDC.
DDERR_INVALIDPARAMSlphDC is NULL.
DDERR_UNSUPPORTEDPixel buffer is empty.
DDERR_GENERICDC creation via free-api failed.
IDirectDrawSurface::ReleaseDC method Implemented
HRESULT WINAPI ReleaseDC(HDC hDC);

Releases the device context returned by GetDC. For 8-bit surfaces, converts the modified temporary RGBA buffer back to palette indices using nearest-match squared-RGB distance for each pixel, then frees the temporary buffer. Destroys the DC so a fresh one is created on the next GetDC call.

Parameters

ParameterTypeDirectionDescription
hDCHDCin Must be the HDC returned by the most recent GetDC on this surface. Returns DDERR_INVALIDPARAMS if it does not match.

Return values

DD_OKDC released.
DDERR_INVALIDPARAMSDC does not match the surface's attached DC.

IDirectDrawPalette interface

Holds a table of up to 256 PALETTEENTRY values. Obtained via IDirectDraw::CreatePalette and attached to surfaces via IDirectDrawSurface::SetPalette.

typedef struct IDirectDrawPalette* LPDIRECTDRAWPALETTE;
IDirectDrawPalette::AddRef / Release method Implemented
ULONG WINAPI AddRef();
ULONG WINAPI Release();

Standard reference counting. Release() to 0 frees the palette's 256-entry internal array.

IDirectDrawPalette::GetEntries method Implemented
HRESULT WINAPI GetEntries(
    DWORD           dwFlags,
    DWORD           dwBase,
    DWORD           dwNumEntries,
    LPPALETTEENTRY  lpEntries
);

Reads a contiguous range of palette entries into the caller-provided array.

Parameters

ParameterTypeDirectionDescription
dwFlagsDWORDin Ignored. Pass 0.
dwBaseDWORDin Index of the first entry to read (0–255).
dwNumEntriesDWORDin Number of entries to read. dwBase + dwNumEntries must be ≤ 256.
lpEntriesLPPALETTEENTRYout Caller-allocated array of at least dwNumEntries PALETTEENTRY structures.

Return values

DD_OKEntries copied.
DDERR_INVALIDPARAMSlpEntries is NULL or range out of bounds.
IDirectDrawPalette::SetEntries method Implemented
HRESULT WINAPI SetEntries(
    DWORD           dwFlags,
    DWORD           dwBase,
    DWORD           dwNumEntries,
    LPPALETTEENTRY  lpEntries
);

Writes a contiguous range of palette entries from the caller-provided array.

Parameters

ParameterTypeDirectionDescription
dwFlagsDWORDin Ignored. Pass 0.
dwBaseDWORDin Index of the first entry to write (0–255).
dwNumEntriesDWORDin Number of entries to write. dwBase + dwNumEntries must be ≤ 256.
lpEntriesLPPALETTEENTRYin Array of dwNumEntries entries to copy into the palette.

Return values

DD_OKEntries written.
DDERR_INVALIDPARAMSlpEntries is NULL or range out of bounds.

IDirectDrawClipper interface

Used in windowed mode to signal that blits to the primary surface should translate screen coordinates to window-local coordinates. Obtained via IDirectDraw::CreateClipper.

typedef struct IDirectDrawClipper* LPDIRECTDRAWCLIPPER;
IDirectDrawClipper::AddRef / Release method Implemented
ULONG WINAPI AddRef();
ULONG WINAPI Release();

Standard reference counting. Release() to 0 frees the clipper object.

IDirectDrawClipper::SetHWnd method Partial
HRESULT WINAPI SetHWnd(DWORD dwFlags, HWND hWnd);

Stores the HWND associated with this clipper.

Parameters

ParameterTypeDirectionDescription
dwFlagsDWORDin Ignored. Pass 0.
hWndHWNDin The window handle to associate. Stored internally as hwnd_. Not actively used for clip region management — only its presence on a surface matters for coordinate translation.

Return values

DD_OKAlways returned.

Limitation vs. original DirectX 3

In original DirectDraw, the clipper maintains a clip list (RGNDATA) based on the visible region of the HWND. free-direct does not maintain clip regions; it only uses the window position for coordinate translation.

Structs and types

DDSURFACEDESC

typedef struct _DDSURFACEDESC {
    DWORD        dwSize;              // [in] Must be sizeof(DDSURFACEDESC)
    DWORD        dwFlags;             // [in] Bitmask of DDSD_* flags indicating which fields are valid
    DWORD        dwHeight;            // [in/out] Surface height in pixels
    DWORD        dwWidth;             // [in/out] Surface width in pixels
    union {
        LONG     lPitch;              // [out] Bytes per scan line (stride)
        DWORD    dwLinearSize;        // Not used by free-direct
    };
    DWORD        dwBackBufferCount;   // Not used by free-direct
    union {
        DWORD    dwMipMapCount;       // Not used
        DWORD    dwZBufferBitDepth;   // Not used
        DWORD    dwRefreshRate;       // Not used
    };
    DWORD        dwAlphaBitDepth;     // Not used
    DWORD        dwReserved;          // Reserved, always 0
    LPVOID       lpSurface;           // [out] Pointer to pixel buffer (set by Lock/GetSurfaceDesc)
    DDCOLORKEY   ddckCKDestOverlay;   // Not used by free-direct
    DDCOLORKEY   ddckCKDestBlt;       // Not used by free-direct
    DDCOLORKEY   ddckCKSrcOverlay;    // Not used by free-direct
    DDCOLORKEY   ddckCKSrcBlt;        // Not used by free-direct
    DDPIXELFORMAT ddpfPixelFormat;    // [in] Pixel format for CreateSurface; [out] in Lock/GetSurfaceDesc
    DDSCAPS      ddsCaps;             // [in] Surface capability flags (DDSCAPS_*)
} DDSURFACEDESC, *LPDDSURFACEDESC;

Used as input to CreateSurface and as output from Lock and GetSurfaceDesc.

Field notes

FieldUsage contextNotes
dwSizeAll callsMust equal sizeof(DDSURFACEDESC) or the call fails.
dwFlagsCreateSurface (in)Bitmask of DDSD_* flags indicating which other fields contain valid input.
dwHeightCreateSurface (in), Lock/GetSurfaceDesc (out)Surface height in pixels. Required for offscreen surfaces (DDSD_HEIGHT must be set).
dwWidthCreateSurface (in), Lock/GetSurfaceDesc (out)Surface width in pixels. Required for offscreen surfaces (DDSD_WIDTH must be set).
lPitchLock/GetSurfaceDesc (out)Bytes per row = width × (bpp / 8). Use this value (not width × 4) to step between rows when accessing lpSurface.
lpSurfaceLock/GetSurfaceDesc (out)Direct pointer into the std::vector<uint8_t>. Valid until the surface is destroyed. For primary surfaces, only set by Lock, not by GetSurfaceDesc.
ddpfPixelFormatCreateSurface (in), Lock/GetSurfaceDesc (out)Pixel format description. Required with DDSD_PIXELFORMAT flag to select 8-bit vs 32-bit in CreateSurface.
ddsCapsCreateSurface (in), GetSurfaceDesc (out)Capability flags. The dwCaps member selects the surface type.

DDPIXELFORMAT

typedef struct _DDPIXELFORMAT {
    DWORD dwSize;            // [in] Must be sizeof(DDPIXELFORMAT)
    DWORD dwFlags;           // [in/out] DDPF_* flags
    DWORD dwFourCC;          // Not used by free-direct
    union {
        DWORD dwRGBBitCount; // Bits per pixel (8 or 32)
        DWORD dwYUVBitCount; // Not used
        DWORD dwZBufferBitDepth; // Not used
        DWORD dwAlphaBitDepth;   // Not used
    };
    union {
        DWORD dwRBitMask;    // [out] 0x00FF0000 for 32-bit RGB
        DWORD dwYBitMask;    // Not used
    };
    union {
        DWORD dwGBitMask;    // [out] 0x0000FF00 for 32-bit RGB
        DWORD dwUBitMask;    // Not used
    };
    union {
        DWORD dwBBitMask;    // [out] 0x000000FF for 32-bit RGB
        DWORD dwVBitMask;    // Not used
    };
    union {
        DWORD dwRGBAlphaBitMask; // Not used (alpha is always 0xFF internally)
        DWORD dwYUVAlphaBitMask; // Not used
    };
} DDPIXELFORMAT, *LPDDPIXELFORMAT;

Values written by GetSurfaceDesc / Lock

Surface typedwFlagsdwRGBBitCountdwRBitMask / G / B
8-bit paletted DDPF_PALETTEINDEXED8 (0x20) 8 0 / 0 / 0 (no RGB masks for indexed)
32-bit RGB DDPF_RGB (0x40) 32 0x00FF0000 / 0x0000FF00 / 0x000000FF

DDCOLORKEY

typedef struct _DDCOLORKEY {
    DWORD dwColorSpaceLowValue;   // Low end of the transparent color range (inclusive)
    DWORD dwColorSpaceHighValue;  // High end of the transparent color range (inclusive)
} DDCOLORKEY, *LPDDCOLORKEY;

Defines a range of pixel values to be treated as transparent in blits. Pixel p is transparent if dwColorSpaceLowValue <= p <= dwColorSpaceHighValue.

For a single-color key (the most common case), set both fields to the same value. Example for magenta on a 32-bit surface: {0x00FF00FF, 0x00FF00FF}. Example for palette index 0 on an 8-bit surface: {0, 0}.

DDSCAPS

typedef struct _DDSCAPS {
    DWORD dwCaps;  // Bitmask of DDSCAPS_* flags
} DDSCAPS, *LPDDSCAPS;

Simple wrapper around a capability bitmask. Used in DDSURFACEDESC.ddsCaps.

DDBLTFX

typedef struct _DDBLTFX {
    DWORD     dwSize;              // [in] Must be sizeof(DDBLTFX)
    DWORD     dwDDFX;              // Not used by free-direct
    DWORD     dwROP;               // Not used by free-direct
    DWORD     dwDDROP;             // Not used by free-direct
    DWORD     dwRotationAngle;     // Accepted but rotation NOT performed
    DWORD     dwZBufferDestConst;  // Not used
    DWORD     dwZBufferDestOverlap;// Not used
    DWORD     dwZBufferSrcConst;   // Not used
    DWORD     dwZBufferSrcOverlap; // Not used
    DWORD     dwYCbCrDestConst;    // Not used
    DWORD     dwYCbCrSrcConst;     // Not used
    DWORD     dwAlphaDestConst;    // Not used
    DWORD     dwAlphaSrcConst;     // Not used
    DWORD     dwFillColor;         // [in] Fill color for DDBLT_COLORFILL
    DDCOLORKEY ddckDestColorkey;   // Not used
    DDCOLORKEY ddckSrcColorkey;    // Not used (color key is stored on the surface, not here)
} DDBLTFX, *LPDDBLTFX;

Field notes

FieldNotes
dwSize Must equal sizeof(DDBLTFX).
dwFillColor Used only when DDBLT_COLORFILL is set in Blt.
32-bit surfaces: interpreted as 0x00RRGGBB. The alpha byte is forced to 255.
8-bit surfaces: the low byte (bits 0–7) is used as the palette index.
dwRotationAngle Accepted in the struct (can be set without error) but the rotation is never applied. The blit proceeds as a standard copy.

PALETTEENTRY

typedef struct tagPALETTEENTRY {
    BYTE peRed;    // Red component (0–255)
    BYTE peGreen;  // Green component (0–255)
    BYTE peBlue;   // Blue component (0–255)
    BYTE peFlags;  // Flags (ignored by free-direct; pass 0)
} PALETTEENTRY, *PPALETTEENTRY, *LPPALETTEENTRY;

One entry in a 256-color palette. peFlags is accepted but ignored. Used in arrays of 256 entries with CreatePalette, GetEntries, and SetEntries.

Flags reference

DDSCAPS_* surface capability flags

ConstantValueSupportDescription
DDSCAPS_PRIMARYSURFACE0x00000200Implemented Primary (displayed) surface. Size comes from SetDisplayMode or defaults to 640×480.
DDSCAPS_OFFSCREENPLAIN0x00000040Implemented Plain offscreen surface in system memory. Width and height required.
DDSCAPS_SYSTEMMEMORY0x00000800Implemented Explicitly system-memory surface. Treated identically to OFFSCREENPLAIN.

DDSD_* surface description flags

ConstantValueDescription
DDSD_CAPS0x00000001Indicates ddsCaps is valid. Always required for CreateSurface.
DDSD_HEIGHT0x00000002Indicates dwHeight is valid. Required for offscreen surfaces.
DDSD_WIDTH0x00000004Indicates dwWidth is valid. Required for offscreen surfaces.
DDSD_PITCH0x00000008Indicates lPitch is valid. Set in the output of Lock/GetSurfaceDesc for offscreen surfaces.
DDSD_LPSURFACE0x00000800Indicates lpSurface is valid. Set in the output of Lock/GetSurfaceDesc for offscreen surfaces.
DDSD_PIXELFORMAT0x00001000Indicates ddpfPixelFormat is valid. Set this in CreateSurface to specify 8-bit or 32-bit format explicitly.

DDBLT_* blit flags (used with Blt)

ConstantValueSupportDescription
DDBLT_COLORFILL0x00000400 Implemented Fill the destination rectangle with DDBLTFX.dwFillColor. Source surface must be NULL.
DDBLT_KEYSRC0x00008000 Implemented Apply the source surface's color key. Transparent pixels are not copied to the destination.
DDBLT_WAIT0x00000010 Stub Accepted; no-op. Original meaning: wait until hardware is ready rather than returning DDERR_WASSTILLDRAWING.
DDBLT_ROTATIONANGLE0x01000000 Not supported Accepted in the flags bitmask (does not cause an error). Rotation angle from DDBLTFX.dwRotationAngle is received but not applied. The blit proceeds without rotation.

DDBLTFAST_* fast-blit transparency flags (used with BltFast)

ConstantValueSupportDescription
DDBLTFAST_NOCOLORKEY0x00000000 Implemented Copy all pixels including those matching the color key. This is the default (value 0).
DDBLTFAST_SRCCOLORKEY0x00000001 Implemented Skip pixels that match the source surface's color key range.

DDCKEY_* color key type flags (used with SetColorKey)

ConstantValueSupportDescription
DDCKEY_SRCBLT0x00000008 Implemented Set the source blit color key. Used to define which pixel values are transparent when this surface is blitted onto another.

All other DDCKEY_* values (DDCKEY_DESTBLT, DDCKEY_SRCOVERLAY, DDCKEY_DESTOVERLAY) return DDERR_UNSUPPORTED.

DDSCL_* cooperative level flags (used with SetCooperativeLevel)

ConstantValueSupportDescription
DDSCL_FULLSCREEN0x00000001 Partial Request fullscreen mode. Calls FreeApiSetWindowFullscreen(true). Actual fullscreen depends on the free-api and SDL3 window support.
DDSCL_EXCLUSIVE0x00000010 Partial Accepted. In combination with DDSCL_FULLSCREEN indicates exclusive fullscreen. No additional effect in free-direct.
DDSCL_NORMAL0x00000008 Implemented Windowed (normal) mode. Calls FreeApiSetWindowFullscreen(false).

DDPCAPS_* palette capability flags (used with CreatePalette)

ConstantValueSupportDescription
DDPCAPS_8BIT0x00000004 Implemented 256-entry palette for 8-bit paletted surfaces. Always accepted; all palettes are 256 entries regardless.

DDPF_* pixel format flags (used in DDPIXELFORMAT.dwFlags)

ConstantValueSupportDescription
DDPF_RGB0x00000040 Implemented Surface contains raw RGB data. Use with dwRGBBitCount = 32 for 32-bit RGBA surfaces.
DDPF_PALETTEINDEXED80x00000020 Implemented Surface uses 8-bit palette indices. Each byte is an index into a 256-entry PALETTEENTRY table.

Result codes

Actively returned by the implementation

ConstantValueMeaning
DD_OK0x00000000Success.
DDERR_GENERIC0x88760000Unspecified failure (e.g. SDL renderer creation failed, SDL texture creation failed).
DDERR_INVALIDPARAMS0x88760064A required parameter was NULL, out of range, or had a wrong size field.
DDERR_OUTOFMEMORY0x8876017CHeap allocation failed (new returned nullptr).
DDERR_UNSUPPORTED0x88760032QueryInterface, unsupported DDCKEY flags, or unsupported Blt flag combination.

Defined for compile compatibility, not actively returned

All other DDERR_* constants (DDERR_ALREADYINITIALIZED, DDERR_SURFACELOST, DDERR_NOCOLORKEY, etc.) are defined in ddraw.h with unique HRESULT values so that game code that references them compiles without modification. The implementation does not return them.

Use the SUCCEEDED(hr) and FAILED(hr) macros to check results:

#define SUCCEEDED(hr)  (((HRESULT)(hr)) >= 0)
#define FAILED(hr)     (((HRESULT)(hr)) < 0)

Pointer typedefs

typedef struct IDirectDraw*         LPDIRECTDRAW;
typedef struct IDirectDrawSurface*  LPDIRECTDRAWSURFACE;
typedef struct IDirectDrawPalette*  LPDIRECTDRAWPALETTE;
typedef struct IDirectDrawClipper*  LPDIRECTDRAWCLIPPER;

These are plain pointer typedefs matching the legacy DirectX convention. They are compatible with the concrete implementation classes used internally (since the public interface classes are pure virtual bases).