Add wdrvScreenshot() to capture the screen to PNG via stb_image_write.h, reading the framebuffer (or DDI bitmap fallback) and VGA DAC palette. Convert demo.c to non-interactive mode with automatic screenshots after each demo (DEMO01-15.PNG) and no keypress waits, plus per-driver DOSBox-X configs for automated testing. Set a standard Windows 3.1 256-color palette (8R x 8G x 4B color cube with 20 static system colors) to ensure consistent output across drivers. Fix wdrvSetPalette to also program the VGA DAC directly, since VBESVGA's SetPalette DDI updates its internal color table but not the hardware. Detect DAC width via VBE 4F08 (S3TRIO=6-bit, VBESVGA=8-bit) and use correct shift in both DAC writes and reads — fixes dark display on VBESVGA where 6-bit values in 8-bit DAC produced 1/4 brightness. Fix S3 dispYOffset: extend PDEVICE deHeight by the offset so the driver's internal clipping allows the full 600-row logical screen, rather than incorrectly reducing dpVertRes to 590. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
336 lines
15 KiB
C
336 lines
15 KiB
C
#ifndef WINDRV_H
|
|
#define WINDRV_H
|
|
|
|
// ============================================================================
|
|
// windrv.h - Public API for using Windows 3.x display drivers from DOS
|
|
//
|
|
// This library loads Windows 3.x accelerated display drivers (16-bit NE
|
|
// format DLLs) and provides a clean 32-bit C API for DOS programs compiled
|
|
// with DJGPP to use their hardware-accelerated drawing functions.
|
|
//
|
|
// The library handles:
|
|
// - NE executable loading with segment relocation
|
|
// - 32-bit to 16-bit protected mode thunking via DPMI
|
|
// - Windows API stub functions that drivers import
|
|
// - DDI (Device Driver Interface) function wrappers
|
|
//
|
|
// Usage:
|
|
// 1. Call wdrvInit() to initialize the library
|
|
// 2. Call wdrvLoadDriver() with path to a .DRV file
|
|
// 3. Call wdrvEnable() to set a video mode
|
|
// 4. Use drawing functions (wdrvBitBlt, wdrvLine, etc.)
|
|
// 5. Call wdrvDisable() to restore text mode
|
|
// 6. Call wdrvUnloadDriver() and wdrvShutdown() to clean up
|
|
// ============================================================================
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "wintypes.h"
|
|
|
|
// ============================================================================
|
|
// Error codes
|
|
// ============================================================================
|
|
|
|
#define WDRV_OK 0
|
|
#define WDRV_ERR_INIT -1 // Initialization failed
|
|
#define WDRV_ERR_NO_DPMI -2 // DPMI not available or insufficient
|
|
#define WDRV_ERR_FILE_NOT_FOUND -3 // Driver file not found
|
|
#define WDRV_ERR_BAD_FORMAT -4 // Not a valid NE executable
|
|
#define WDRV_ERR_LOAD_FAILED -5 // Failed to load driver segments
|
|
#define WDRV_ERR_NO_MEMORY -6 // Out of memory (conventional or extended)
|
|
#define WDRV_ERR_RELOC_FAILED -7 // Relocation processing failed
|
|
#define WDRV_ERR_NO_ENTRY -8 // Required DDI entry point not found
|
|
#define WDRV_ERR_ENABLE_FAILED -9 // Driver Enable() call failed
|
|
#define WDRV_ERR_THUNK_FAILED -10 // Thunk setup failed
|
|
#define WDRV_ERR_NOT_LOADED -11 // No driver loaded
|
|
#define WDRV_ERR_NOT_ENABLED -12 // Driver not enabled
|
|
#define WDRV_ERR_UNSUPPORTED -13 // Operation not supported by driver
|
|
#define WDRV_ERR_BAD_FONT -14 // Invalid font file or data
|
|
|
|
// ============================================================================
|
|
// Opaque driver handle
|
|
// ============================================================================
|
|
|
|
typedef struct WdrvDriverS *WdrvHandleT;
|
|
typedef struct WdrvFontS *WdrvFontT;
|
|
|
|
// ============================================================================
|
|
// Driver information (returned by wdrvGetInfo)
|
|
// ============================================================================
|
|
|
|
typedef struct {
|
|
char driverName[64]; // Module name from NE header
|
|
uint16_t driverVersion; // Driver version number
|
|
int32_t maxWidth; // Maximum supported width
|
|
int32_t maxHeight; // Maximum supported height
|
|
int32_t maxBpp; // Maximum bits per pixel
|
|
int32_t numColors; // Number of colors
|
|
uint32_t rasterCaps; // Raster capability bits (RC_*)
|
|
bool hasBitBlt; // Driver exports BitBlt
|
|
bool hasOutput; // Driver exports Output (lines, shapes)
|
|
bool hasPixel; // Driver exports Pixel
|
|
bool hasStretchBlt; // Driver exports StretchBlt
|
|
bool hasExtTextOut; // Driver exports ExtTextOut
|
|
bool hasSetPalette; // Driver exports SetPalette
|
|
bool hasSetCursor; // Driver exports SetCursor
|
|
bool hasMoveCursor; // Driver exports MoveCursor
|
|
bool hasScanLR; // Driver exports ScanLR
|
|
bool hasGetCharWidth; // Driver exports GetCharWidth
|
|
bool hasCreateBitmap; // Driver exports CreateBitmap
|
|
} WdrvInfoT;
|
|
|
|
// ============================================================================
|
|
// BitBlt parameters
|
|
// ============================================================================
|
|
|
|
typedef struct {
|
|
int16_t dstX;
|
|
int16_t dstY;
|
|
int16_t srcX;
|
|
int16_t srcY;
|
|
int16_t width;
|
|
int16_t height;
|
|
uint32_t rop3; // Raster operation (SRCCOPY, PATCOPY, etc.)
|
|
} WdrvBitBltParamsT;
|
|
|
|
// ============================================================================
|
|
// Library initialization / shutdown
|
|
// ============================================================================
|
|
|
|
// Initialize the library. Must be called before any other functions.
|
|
// Sets up DPMI descriptors, thunk infrastructure, and API stubs.
|
|
int32_t wdrvInit(void);
|
|
|
|
// Shut down the library and free all resources.
|
|
void wdrvShutdown(void);
|
|
|
|
// ============================================================================
|
|
// Driver loading
|
|
// ============================================================================
|
|
|
|
// Load a Windows 3.x display driver (.DRV file).
|
|
// Returns a driver handle on success, NULL on failure.
|
|
// Call wdrvGetLastError() for details on failure.
|
|
WdrvHandleT wdrvLoadDriver(const char *driverPath);
|
|
|
|
// Unload a previously loaded driver.
|
|
void wdrvUnloadDriver(WdrvHandleT handle);
|
|
|
|
// Get information about a loaded driver.
|
|
// The driver must be loaded but need not be enabled.
|
|
int32_t wdrvGetInfo(WdrvHandleT handle, WdrvInfoT *info);
|
|
|
|
// ============================================================================
|
|
// Mode setting
|
|
// ============================================================================
|
|
|
|
// Enable the driver (set video mode and initialize hardware).
|
|
// width/height/bpp are the requested mode; the driver may adjust.
|
|
// Pass 0 for defaults (driver's preferred resolution).
|
|
int32_t wdrvEnable(WdrvHandleT handle, int32_t width, int32_t height, int32_t bpp);
|
|
|
|
// Disable the driver (restore text mode, release hardware).
|
|
int32_t wdrvDisable(WdrvHandleT handle);
|
|
|
|
// ============================================================================
|
|
// Drawing operations
|
|
// ============================================================================
|
|
|
|
// Block transfer (hardware-accelerated if supported).
|
|
int32_t wdrvBitBlt(WdrvHandleT handle, WdrvBitBltParamsT *params);
|
|
|
|
// Solid rectangle fill using PatBlt with a solid brush.
|
|
int32_t wdrvFillRect(WdrvHandleT handle, int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color);
|
|
|
|
// Set a single pixel.
|
|
int32_t wdrvSetPixel(WdrvHandleT handle, int16_t x, int16_t y, uint32_t color);
|
|
|
|
// Get a single pixel's color.
|
|
uint32_t wdrvGetPixel(WdrvHandleT handle, int16_t x, int16_t y);
|
|
|
|
// Draw a polyline using the Output DDI function.
|
|
int32_t wdrvPolyline(WdrvHandleT handle, Point16T *points, int16_t count, uint32_t color);
|
|
|
|
// Draw a rectangle outline.
|
|
int32_t wdrvRectangle(WdrvHandleT handle, int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color);
|
|
|
|
// Draw a polyline with a specific pen style.
|
|
int32_t wdrvPolylineEx(WdrvHandleT handle, Point16T *points, int16_t count, uint32_t color, int16_t penStyle);
|
|
|
|
// Draw a rectangle outline with a specific pen style.
|
|
int32_t wdrvRectangleEx(WdrvHandleT handle, int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color, int16_t penStyle);
|
|
|
|
// Draw text using the ExtTextOut DDI function.
|
|
// Pass NULL for font to use the built-in 8x16 VGA bitmap font.
|
|
int32_t wdrvExtTextOut(WdrvHandleT handle, int16_t x, int16_t y,
|
|
const char *text, int16_t length,
|
|
uint32_t fgColor, uint32_t bgColor,
|
|
bool opaque, WdrvFontT font);
|
|
|
|
// ============================================================================
|
|
// Pen styles (for wdrvPolylineEx / wdrvRectangleEx)
|
|
// ============================================================================
|
|
|
|
#define WDRV_PEN_SOLID 0
|
|
#define WDRV_PEN_DASH 1
|
|
#define WDRV_PEN_DOT 2
|
|
#define WDRV_PEN_DASHDOT 3
|
|
#define WDRV_PEN_DASHDOTDOT 4
|
|
|
|
// ============================================================================
|
|
// ScanLR and Flood Fill
|
|
// ============================================================================
|
|
|
|
// ScanLR style bits
|
|
#define WDRV_SCAN_RIGHT 0x00 // Scan right, find not-matching
|
|
#define WDRV_SCAN_RIGHT_MATCH 0x01 // Scan right, find matching
|
|
#define WDRV_SCAN_LEFT 0x02 // Scan left, find not-matching
|
|
#define WDRV_SCAN_LEFT_MATCH 0x03 // Scan left, find matching
|
|
|
|
// Scan left or right from (x,y) for color match/non-match.
|
|
// style is a bitfield: bit 0=FIND_COLOR (match), bit 1=STEP_LEFT.
|
|
// Returns X where scan stopped, or -1/screenW if not found.
|
|
int16_t wdrvScanLR(WdrvHandleT handle, int16_t x, int16_t y, uint32_t color, int16_t style);
|
|
|
|
// Flood fill starting at (x,y) with fillColor.
|
|
// Uses framebuffer when available, falls back to ScanLR + FillRect.
|
|
int32_t wdrvFloodFill(WdrvHandleT handle, int16_t x, int16_t y, uint32_t fillColor);
|
|
|
|
// ============================================================================
|
|
// Text measurement
|
|
// ============================================================================
|
|
|
|
// Get character widths for a range of characters.
|
|
// widths array must have room for (lastChar - firstChar + 1) entries.
|
|
int32_t wdrvGetCharWidths(WdrvHandleT handle, WdrvFontT font, uint8_t firstChar, uint8_t lastChar, int16_t *widths);
|
|
|
|
// Measure total pixel width of a text string.
|
|
int32_t wdrvMeasureText(WdrvHandleT handle, WdrvFontT font, const char *text, int16_t length);
|
|
|
|
// ============================================================================
|
|
// Pixel buffer blitting (direct framebuffer)
|
|
// ============================================================================
|
|
|
|
// Blit an 8bpp pixel buffer to the screen.
|
|
// Uses framebuffer when available, falls back to Pixel DDI per pixel.
|
|
int32_t wdrvBlitPixels(WdrvHandleT handle, int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t *pixels, int32_t srcPitch);
|
|
|
|
// Load and display a BMP file at (x,y). If setPalette is true, applies
|
|
// the BMP's palette via wdrvSetPalette.
|
|
int32_t wdrvBlitBmp(WdrvHandleT handle, int16_t x, int16_t y, const char *bmpPath, bool setPalette);
|
|
|
|
// ============================================================================
|
|
// Hardware cursor
|
|
// ============================================================================
|
|
|
|
typedef enum {
|
|
WDRV_CURSOR_ARROW,
|
|
WDRV_CURSOR_CROSSHAIR,
|
|
WDRV_CURSOR_IBEAM,
|
|
WDRV_CURSOR_HAND,
|
|
WDRV_CURSOR_NONE
|
|
} WdrvCursorShapeE;
|
|
|
|
// Set cursor to a built-in shape. WDRV_CURSOR_NONE hides the cursor.
|
|
int32_t wdrvSetCursor(WdrvHandleT handle, WdrvCursorShapeE shape);
|
|
|
|
// Set cursor to a custom 32x32 mono bitmap.
|
|
// andMask and xorMask are each 128 bytes (32 rows x 4 bytes/row).
|
|
int32_t wdrvSetCursorCustom(WdrvHandleT handle, int16_t hotX, int16_t hotY, const uint8_t *andMask, const uint8_t *xorMask);
|
|
|
|
// Move the hardware cursor to screen position (x,y).
|
|
int32_t wdrvMoveCursor(WdrvHandleT handle, int16_t x, int16_t y);
|
|
|
|
// ============================================================================
|
|
// Off-screen bitmaps
|
|
// ============================================================================
|
|
|
|
typedef struct WdrvBitmapS *WdrvBitmapT;
|
|
|
|
// Create an off-screen bitmap via the driver's CreateBitmap DDI.
|
|
WdrvBitmapT wdrvCreateBitmap(WdrvHandleT handle, int16_t width, int16_t height);
|
|
|
|
// Delete an off-screen bitmap.
|
|
void wdrvDeleteBitmap(WdrvHandleT handle, WdrvBitmapT bitmap);
|
|
|
|
// Set bitmap pixel data via BitmapBits DDI.
|
|
int32_t wdrvBitmapSetPixels(WdrvHandleT handle, WdrvBitmapT bitmap, const uint8_t *data, uint32_t dataSize);
|
|
|
|
// Get bitmap pixel data via BitmapBits DDI.
|
|
int32_t wdrvBitmapGetPixels(WdrvHandleT handle, WdrvBitmapT bitmap, uint8_t *data, uint32_t dataSize);
|
|
|
|
// BitBlt from an off-screen bitmap to the screen.
|
|
int32_t wdrvBitBltFromBitmap(WdrvHandleT handle, WdrvBitmapT srcBitmap, int16_t srcX, int16_t srcY, int16_t dstX, int16_t dstY, int16_t w, int16_t h, uint32_t rop3);
|
|
|
|
// BitBlt from the screen to an off-screen bitmap.
|
|
int32_t wdrvBitBltToBitmap(WdrvHandleT handle, WdrvBitmapT dstBitmap, int16_t srcX, int16_t srcY, int16_t dstX, int16_t dstY, int16_t w, int16_t h, uint32_t rop3);
|
|
|
|
// ============================================================================
|
|
// Font loading
|
|
// ============================================================================
|
|
|
|
// Load a font from a .FON file (NE container with FONT resources).
|
|
// fontIndex selects which font resource (0-based).
|
|
// Returns NULL on failure (call wdrvGetLastError for details).
|
|
WdrvFontT wdrvLoadFontFon(const char *fonPath, int32_t fontIndex);
|
|
|
|
// Load a font from a raw .FNT file.
|
|
// Returns NULL on failure.
|
|
WdrvFontT wdrvLoadFontFnt(const char *fntPath);
|
|
|
|
// Get a handle to the built-in VGA 8x16 font (lazy-initialized).
|
|
// The returned handle must NOT be passed to wdrvUnloadFont.
|
|
WdrvFontT wdrvLoadFontBuiltin(void);
|
|
|
|
// Load a font from a TrueType (.TTF) file at the given point size.
|
|
// Rasterizes glyphs to 1-bit bitmaps and packs into .FNT v3 format.
|
|
// Returns NULL on failure (call wdrvGetLastError for details).
|
|
WdrvFontT wdrvLoadFontTtf(const char *ttfPath, int32_t pointSize);
|
|
|
|
// Unload a font previously loaded with wdrvLoadFontFon, wdrvLoadFontFnt,
|
|
// or wdrvLoadFontTtf. Silently ignores NULL and the built-in font.
|
|
void wdrvUnloadFont(WdrvFontT font);
|
|
|
|
// ============================================================================
|
|
// Palette operations (for 8bpp modes)
|
|
// ============================================================================
|
|
|
|
// Set palette entries. colors is an array of RGBQUAD (R,G,B,flags).
|
|
int32_t wdrvSetPalette(WdrvHandleT handle, int32_t startIndex, int32_t count, const uint8_t *colors);
|
|
|
|
// ============================================================================
|
|
// Direct framebuffer access
|
|
// ============================================================================
|
|
|
|
// Get a near pointer to the linear framebuffer (if available).
|
|
// Returns NULL if the driver doesn't provide linear access.
|
|
void *wdrvGetFramebuffer(WdrvHandleT handle);
|
|
|
|
// Get the framebuffer pitch (bytes per scanline).
|
|
int32_t wdrvGetPitch(WdrvHandleT handle);
|
|
|
|
// Save the current screen to a PNG file.
|
|
// Reads the framebuffer (or uses DDI fallback) and DAC palette.
|
|
int32_t wdrvScreenshot(WdrvHandleT handle, const char *filename);
|
|
|
|
// ============================================================================
|
|
// Error reporting
|
|
// ============================================================================
|
|
|
|
// Get the last error code.
|
|
int32_t wdrvGetLastError(void);
|
|
|
|
// Get a human-readable description of the last error.
|
|
const char *wdrvGetLastErrorString(void);
|
|
|
|
// ============================================================================
|
|
// Debugging
|
|
// ============================================================================
|
|
|
|
// Enable/disable verbose debug output to stderr.
|
|
void wdrvSetDebug(bool enable);
|
|
|
|
// Dump all segment base addresses for debugging.
|
|
void wdrvDumpSegmentBases(WdrvHandleT handle);
|
|
|
|
#endif // WINDRV_H
|