Add wdrvScreenshot, auto-demo mode, palette fixes, and DAC width detection
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>
This commit is contained in:
parent
fbb1cce5c3
commit
5527130145
11 changed files with 4541 additions and 152 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -7,6 +7,9 @@ bin/
|
||||||
# Runtime logs
|
# Runtime logs
|
||||||
OUTPUT.LOG
|
OUTPUT.LOG
|
||||||
|
|
||||||
|
# Screenshots
|
||||||
|
screenshots/
|
||||||
|
|
||||||
# Editor backups
|
# Editor backups
|
||||||
*~
|
*~
|
||||||
*.swp
|
*.swp
|
||||||
|
|
|
||||||
66
CLAUDE.md
66
CLAUDE.md
|
|
@ -50,14 +50,37 @@ windriver/
|
||||||
AND driver is not VGA-class (1bpp/4planes).
|
AND driver is not VGA-class (1bpp/4planes).
|
||||||
- **Pattern scratch artifact**: S3 driver writes 8x8 dithered brush pattern to VRAM at fixed
|
- **Pattern scratch artifact**: S3 driver writes 8x8 dithered brush pattern to VRAM at fixed
|
||||||
position (~(144,1)-(151,8)) during accelerated pattern fills. Fixed by shifting CRTC display
|
position (~(144,1)-(151,8)) during accelerated pattern fills. Fixed by shifting CRTC display
|
||||||
start down 10 scanlines (`dispYOffset`) so the scratch area is off-screen.
|
start down 10 scanlines (`dispYOffset`) so the scratch area is off-screen. All drawing Y
|
||||||
|
coordinates are offset by dispYOffset. The full dpVertRes (600) is reported and usable —
|
||||||
|
the shift just consumes slightly more VRAM.
|
||||||
|
- **S3TRIO BitBlt source corruption**: S3TRIO's accelerated BitBlt corrupts source VRAM
|
||||||
|
during source-dependent ROP operations (SRCINVERT, NOTSRCCOPY, SRCAND, SRCPAINT).
|
||||||
|
In Windows 3.1, GDI uses intermediate off-screen bitmaps. Our direct DDI calls must
|
||||||
|
work around this by redrawing source rects after the ROP, or using separate source areas.
|
||||||
|
Off-screen VRAM (y >= screenH) is NOT usable — the driver clips to screen dimensions.
|
||||||
- **`-fno-gcse` required for windrv.c**: With -O2 GCSE, stack layout causes issues during
|
- **`-fno-gcse` required for windrv.c**: With -O2 GCSE, stack layout causes issues during
|
||||||
16-bit driver calls. Only windrv.c needs this. See `WINDRV_CFLAGS` in win31drv/Makefile.
|
16-bit driver calls. Only windrv.c needs this. See `WINDRV_CFLAGS` in win31drv/Makefile.
|
||||||
- Output DDI (polylines/rectangles) requires a **physical pen** from RealizeObject, not a
|
- Output DDI (polylines/rectangles) requires a **physical pen** from RealizeObject, not a
|
||||||
raw LogPen16T. The pen must be in DGROUP (same as brush, drawMode, PDEVICE).
|
raw LogPen16T. The pen must be in DGROUP (same as brush, drawMode, PDEVICE).
|
||||||
|
- **Curve primitives removed**: Ellipses, polygons, roundrects, arcs, and pies were removed
|
||||||
|
because DIB engine drivers (VBESVGA/ET4000) hang (expect GDI curve decomposition callback)
|
||||||
|
and S3TRIO only partially renders them. Only polyline is reliable via Output DDI.
|
||||||
|
- **OS_RECTANGLE crashes DIB engine drivers**: VBESVGA/ET4000 Output(OS_RECTANGLE) crashes
|
||||||
|
like curve primitives. `wdrvRectangleEx` draws rectangles as two 3-point polylines instead.
|
||||||
|
- **Output DDI lpClipRect**: DIB engine drivers (VBESVGA) dereference lpClipRect
|
||||||
|
unconditionally in polyline paths too. Always pass a valid clip rect (0,0,0x7FFF,0x7FFF).
|
||||||
- `wdrvUnloadDriver` does NOT auto-call Disable — caller must handle text mode restore
|
- `wdrvUnloadDriver` does NOT auto-call Disable — caller must handle text mode restore
|
||||||
- `sleep()` hangs under DOSBox-X because BIOS timer ticks don't advance without I/O
|
- `sleep()` hangs under DOSBox-X because BIOS timer ticks don't advance without I/O
|
||||||
- Debug output: `-d` flag enables verbose logging in neload, winstub, thunk, and windrv
|
- Debug output: `-d` flag enables verbose logging in neload, winstub, thunk, and windrv
|
||||||
|
- **SetPalette DDI vs VGA DAC**: VBESVGA's SetPalette DDI updates the driver's internal
|
||||||
|
color table (used by ColorInfo for RGB→index matching) but does NOT program the VGA
|
||||||
|
DAC hardware. In real Windows 3.1, GDI programs the DAC separately. `wdrvSetPalette`
|
||||||
|
works around this by also writing DAC registers directly (ports 0x3C8/0x3C9) after
|
||||||
|
the DDI call. This is idempotent on drivers like S3TRIO that already program the DAC.
|
||||||
|
- **DAC width**: S3TRIO uses 6-bit DAC (values 0-63), VBESVGA uses 8-bit DAC (values
|
||||||
|
0-255). Detected at Enable via VBE 4F08 subfunc 01. Both `wdrvSetPalette` (port write)
|
||||||
|
and `readDacPalette` (screenshot) use the detected width for correct shift amounts.
|
||||||
|
Wrong shift causes dark display (6-bit values in 8-bit DAC = 1/4 brightness).
|
||||||
- Known issue: mode mismatch HW=800x600 vs GDIINFO=640x480
|
- Known issue: mode mismatch HW=800x600 vs GDIINFO=640x480
|
||||||
|
|
||||||
## DGROUP Stack Management
|
## DGROUP Stack Management
|
||||||
|
|
@ -111,6 +134,11 @@ windriver/
|
||||||
- DOSBox-X machine type: `svga_et4000` for ET4000 hardware emulation
|
- DOSBox-X machine type: `svga_et4000` for ET4000 hardware emulation
|
||||||
- ET4000 is 640x480 8bpp, software-rendered (no accelerator engine in DOSBox-X)
|
- ET4000 is 640x480 8bpp, software-rendered (no accelerator engine in DOSBox-X)
|
||||||
- CR30=0x00 on ET4000 → isS3=false → no S3 engine wait, no display start shift
|
- CR30=0x00 on ET4000 → isS3=false → no S3 engine wait, no display start shift
|
||||||
|
- **GetPixel breaks ScanLR on ET4000**: The Pixel DDI with color=-1 (get mode) leaves
|
||||||
|
VGA hardware state (likely GR5 read mode) that causes ScanLR to not match the pixel
|
||||||
|
just read. GetPixel itself returns correct values; only the ScanLR interaction is
|
||||||
|
broken. Flood fill software path avoids GetPixel entirely, using ScanLR for all
|
||||||
|
pixel-color queries.
|
||||||
|
|
||||||
## Font Loading Notes
|
## Font Loading Notes
|
||||||
- .FON files are NE containers with RT_FONT (type 8) resources; each resource is raw .FNT data
|
- .FON files are NE containers with RT_FONT (type 8) resources; each resource is raw .FNT data
|
||||||
|
|
@ -133,6 +161,42 @@ windriver/
|
||||||
- Demo 4: Screen-to-screen blit (BitBlt SRCCOPY) — works
|
- Demo 4: Screen-to-screen blit (BitBlt SRCCOPY) — works
|
||||||
- Demo 5: ExtTextOut text rendering — works (VBESVGA.DRV)
|
- Demo 5: ExtTextOut text rendering — works (VBESVGA.DRV)
|
||||||
- Demo 7: TrueType font rendering at multiple sizes — works
|
- Demo 7: TrueType font rendering at multiple sizes — works
|
||||||
|
- Demo 8: Color text showcase (fg/bg colors, opaque/transparent, palette grid) — works
|
||||||
|
- Demo 9: ROP3 operations (DSTINVERT, SRCINVERT, NOTSRCCOPY, SRCAND, SRCPAINT) — works
|
||||||
|
- Demo 10: ScanLR + Flood Fill (FB or software fallback) — works on all drivers
|
||||||
|
- Demo 11: Text measurement (GetCharWidth DDI, wdrvMeasureText) — works
|
||||||
|
- Demo 12: Styled pen lines (software Bresenham, all drivers) — works
|
||||||
|
- Demo 13: Pixel buffer blit (FB or software fallback) — works on all drivers
|
||||||
|
- Demo 14: Hardware cursor (arrow, crosshair, ibeam, hand; animated circle) — works
|
||||||
|
- Demo 15: Screen save/restore (screen-to-screen BitBlt stash/restore) — works
|
||||||
- VGA.DRV: 640x480 4-plane 16-color mode; limited color palette but functional
|
- VGA.DRV: 640x480 4-plane 16-color mode; limited color palette but functional
|
||||||
- ET4000.DRV: 640x480 8bpp on svga_et4000; software-only, no hw acceleration
|
- ET4000.DRV: 640x480 8bpp on svga_et4000; software-only, no hw acceleration
|
||||||
- Drivers stored in `drivers/` directory, copied to `bin/` during build
|
- Drivers stored in `drivers/` directory, copied to `bin/` during build
|
||||||
|
|
||||||
|
## Software Rendering Fallbacks
|
||||||
|
- **Styled pens**: Always software-rendered via Bresenham + Pixel DDI (PS_SOLID uses HW Output DDI).
|
||||||
|
S3TRIO silently accepts styled pens but doesn't render them; software path gives identical output everywhere.
|
||||||
|
- **Flood fill**: Uses direct FB when available, falls back to ScanLR DDI + FillRect.
|
||||||
|
Cannot use GetPixel — ET4000 DIB engine's Pixel DDI (color=-1) corrupts VRAM,
|
||||||
|
causing subsequent ScanLR to not match the read pixel. Seed color is determined by
|
||||||
|
probing ScanLR with each palette index until a match is found.
|
||||||
|
- **Pixel blit**: Uses direct FB memcpy when available, falls back to per-pixel SetPixel with PALETTEINDEX.
|
||||||
|
- All four drivers (S3TRIO, VBESVGA, ET4000, VGA) now have identical feature sets.
|
||||||
|
|
||||||
|
## New API Functions (added with demos 9-15)
|
||||||
|
- `wdrvScanLR(handle, x, y, color, style)` — ScanLR DDI wrapper (ordinal 12)
|
||||||
|
- `wdrvFloodFill(handle, x, y, fillColor)` — scanline flood fill (FB or software)
|
||||||
|
- `wdrvGetCharWidths(handle, font, firstChar, lastChar, widths)` — GetCharWidth DDI
|
||||||
|
- `wdrvMeasureText(handle, font, text, length)` — sum char widths for string
|
||||||
|
- `wdrvPolylineEx(handle, points, count, color, penStyle)` — polyline with pen style
|
||||||
|
- `wdrvRectangleEx(handle, x, y, w, h, color, penStyle)` — rectangle with pen style
|
||||||
|
- `wdrvBlitPixels(handle, x, y, w, h, pixels, srcPitch)` — pixel blit (FB or software)
|
||||||
|
- `wdrvBlitBmp(handle, x, y, bmpPath, setPalette)` — load+display 8bpp BMP
|
||||||
|
- `wdrvSetCursor(handle, shape)` — built-in cursor shapes (arrow/crosshair/ibeam/hand/none)
|
||||||
|
- `wdrvSetCursorCustom(handle, hotX, hotY, andMask, xorMask)` — custom 32x32 mono cursor
|
||||||
|
- `wdrvMoveCursor(handle, x, y)` — move hardware cursor
|
||||||
|
- `wdrvCreateBitmap(handle, width, height)` — CreateBitmap DDI
|
||||||
|
- `wdrvDeleteBitmap(handle, bitmap)` — DeleteBitmap DDI
|
||||||
|
- `wdrvBitmapSetPixels/GetPixels(handle, bitmap, data, size)` — BitmapBits DDI
|
||||||
|
- `wdrvBitBltFromBitmap/ToBitmap(handle, bitmap, ...)` — BitBlt with bitmap PDEVICE
|
||||||
|
- `wdrvScreenshot(handle, filename)` — capture screen to PNG (FB or DDI fallback)
|
||||||
|
|
|
||||||
885
demo.c
885
demo.c
|
|
@ -102,13 +102,7 @@ int main(int argc, char *argv[])
|
||||||
// Run drawing demos
|
// Run drawing demos
|
||||||
demoDrawing(drv);
|
demoDrawing(drv);
|
||||||
|
|
||||||
logMsg("Drawing complete. Press any key...\n");
|
logMsg("Drawing complete.\n");
|
||||||
|
|
||||||
// Wait for a keypress so we can see the output
|
|
||||||
while (!kbhit()) {
|
|
||||||
// Busy-wait; kbhit() does keyboard I/O which keeps DOSBox-X responsive
|
|
||||||
}
|
|
||||||
(void)getkey(); // consume the key
|
|
||||||
|
|
||||||
// Disable the driver (restore text mode)
|
// Disable the driver (restore text mode)
|
||||||
logMsg("Calling wdrvDisable...\n");
|
logMsg("Calling wdrvDisable...\n");
|
||||||
|
|
@ -162,6 +156,10 @@ static void printDriverInfo(WdrvHandleT drv)
|
||||||
logMsg(" ExtTextOut: %s\n", info.hasExtTextOut ? "yes" : "no");
|
logMsg(" ExtTextOut: %s\n", info.hasExtTextOut ? "yes" : "no");
|
||||||
logMsg(" SetPalette: %s\n", info.hasSetPalette ? "yes" : "no");
|
logMsg(" SetPalette: %s\n", info.hasSetPalette ? "yes" : "no");
|
||||||
logMsg(" SetCursor: %s\n", info.hasSetCursor ? "yes" : "no");
|
logMsg(" SetCursor: %s\n", info.hasSetCursor ? "yes" : "no");
|
||||||
|
logMsg(" MoveCursor: %s\n", info.hasMoveCursor ? "yes" : "no");
|
||||||
|
logMsg(" ScanLR: %s\n", info.hasScanLR ? "yes" : "no");
|
||||||
|
logMsg(" GetCharWidth:%s\n", info.hasGetCharWidth ? "yes" : "no");
|
||||||
|
logMsg(" CreateBitmap:%s\n", info.hasCreateBitmap ? "yes" : "no");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -225,6 +223,7 @@ static void demoDrawing(WdrvHandleT drv)
|
||||||
}
|
}
|
||||||
|
|
||||||
logMsg(" Drew %d colored rectangles\n", 16);
|
logMsg(" Drew %d colored rectangles\n", 16);
|
||||||
|
wdrvScreenshot(drv, "DEMO01.PNG");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo 2: Draw pixel patterns
|
// Demo 2: Draw pixel patterns
|
||||||
|
|
@ -241,6 +240,7 @@ static void demoDrawing(WdrvHandleT drv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logMsg(" Drew %d pixels\n", pixCount);
|
logMsg(" Drew %d pixels\n", pixCount);
|
||||||
|
wdrvScreenshot(drv, "DEMO02.PNG");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo 3: Draw lines using Output (polyline with realized pen)
|
// Demo 3: Draw lines using Output (polyline with realized pen)
|
||||||
|
|
@ -290,6 +290,7 @@ static void demoDrawing(WdrvHandleT drv)
|
||||||
lineCount++;
|
lineCount++;
|
||||||
}
|
}
|
||||||
logMsg(" Drew %d lines\n", lineCount);
|
logMsg(" Drew %d lines\n", lineCount);
|
||||||
|
wdrvScreenshot(drv, "DEMO03.PNG");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo 4: Screen-to-screen blit test
|
// Demo 4: Screen-to-screen blit test
|
||||||
|
|
@ -307,6 +308,7 @@ static void demoDrawing(WdrvHandleT drv)
|
||||||
bp.rop3 = SRCCOPY;
|
bp.rop3 = SRCCOPY;
|
||||||
wdrvBitBlt(drv, &bp);
|
wdrvBitBlt(drv, &bp);
|
||||||
logMsg(" Screen blit done\n");
|
logMsg(" Screen blit done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO04.PNG");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo 5: Text output using ExtTextOut
|
// Demo 5: Text output using ExtTextOut
|
||||||
|
|
@ -340,6 +342,7 @@ static void demoDrawing(WdrvHandleT drv)
|
||||||
logMsg(" msg4 ret=%" PRId32 "\n", ret);
|
logMsg(" msg4 ret=%" PRId32 "\n", ret);
|
||||||
|
|
||||||
logMsg(" Text output done\n");
|
logMsg(" Text output done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO05.PNG");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo 6: Multiple loaded fonts
|
// Demo 6: Multiple loaded fonts
|
||||||
|
|
@ -394,6 +397,7 @@ static void demoDrawing(WdrvHandleT drv)
|
||||||
wdrvUnloadFont(sansFont);
|
wdrvUnloadFont(sansFont);
|
||||||
wdrvUnloadFont(sysFont);
|
wdrvUnloadFont(sysFont);
|
||||||
logMsg(" Font demo done\n");
|
logMsg(" Font demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO06.PNG");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demo 7: TrueType font rendering
|
// Demo 7: TrueType font rendering
|
||||||
|
|
@ -440,17 +444,872 @@ static void demoDrawing(WdrvHandleT drv)
|
||||||
wdrvUnloadFont(ttfMedium);
|
wdrvUnloadFont(ttfMedium);
|
||||||
wdrvUnloadFont(ttfLarge);
|
wdrvUnloadFont(ttfLarge);
|
||||||
logMsg(" TTF demo done\n");
|
logMsg(" TTF demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO07.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 8: Color text showcase
|
||||||
|
if (info.hasBitBlt && info.hasExtTextOut) {
|
||||||
|
logMsg("Demo 8: Color text showcase\n");
|
||||||
|
int32_t ret;
|
||||||
|
|
||||||
|
// Clear screen to black
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
// Load fonts for this demo
|
||||||
|
WdrvFontT ttfSans20 = wdrvLoadFontTtf("LIBSANS.TTF", 20);
|
||||||
|
WdrvFontT ttfSans16 = wdrvLoadFontTtf("LIBSANS.TTF", 16);
|
||||||
|
WdrvFontT courFont = wdrvLoadFontFon("COURE.FON", 1);
|
||||||
|
WdrvFontT sansFont = wdrvLoadFontFon("SSERIFE.FON", 0);
|
||||||
|
WdrvFontT ttfSerif16 = wdrvLoadFontTtf("LIBSERIF.TTF", 16);
|
||||||
|
|
||||||
|
// --- Title row (y=10) ---
|
||||||
|
if (ttfSans20) {
|
||||||
|
const char *title = "Color Text Demo";
|
||||||
|
ret = wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, ttfSans20);
|
||||||
|
logMsg(" title ret=%" PRId32 "\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Foreground color row (y=40) ---
|
||||||
|
if (ttfSans16) {
|
||||||
|
static const struct { const char *text; uint32_t color; } fgItems[] = {
|
||||||
|
{ "Red", MAKE_RGB(255, 0, 0) },
|
||||||
|
{ "Green", MAKE_RGB( 0, 255, 0) },
|
||||||
|
{ "Blue", MAKE_RGB( 0, 128, 255) },
|
||||||
|
{ "Yellow", MAKE_RGB(255, 255, 0) },
|
||||||
|
{ "Cyan", MAKE_RGB( 0, 255, 255) },
|
||||||
|
{ "Magenta", MAKE_RGB(255, 0, 255) },
|
||||||
|
{ "White", MAKE_RGB(255, 255, 255) },
|
||||||
|
};
|
||||||
|
int16_t fx = 10;
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
ret = wdrvExtTextOut(drv, fx, 40, fgItems[i].text, (int16_t)strlen(fgItems[i].text),
|
||||||
|
fgItems[i].color, MAKE_RGB(0, 0, 0), false, ttfSans16);
|
||||||
|
logMsg(" fg[%d] ret=%" PRId32 "\n", i, ret);
|
||||||
|
fx += (int16_t)(strlen(fgItems[i].text) * 10 + 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Opaque background row (y=65) ---
|
||||||
|
if (ttfSans16) {
|
||||||
|
static const struct { const char *text; uint32_t fg; uint32_t bg; } bgItems[] = {
|
||||||
|
{ "White on Blue", MAKE_RGB(255, 255, 255), MAKE_RGB( 0, 0, 200) },
|
||||||
|
{ "Black on Yellow", MAKE_RGB( 0, 0, 0), MAKE_RGB(255, 255, 0) },
|
||||||
|
{ "White on Red", MAKE_RGB(255, 255, 255), MAKE_RGB(200, 0, 0) },
|
||||||
|
{ "Black on Green", MAKE_RGB( 0, 0, 0), MAKE_RGB( 0, 200, 0) },
|
||||||
|
{ "Yellow on Magenta", MAKE_RGB(255, 255, 0), MAKE_RGB(180, 0, 180) },
|
||||||
|
{ "Black on Cyan", MAKE_RGB( 0, 0, 0), MAKE_RGB( 0, 200, 200) },
|
||||||
|
};
|
||||||
|
int16_t bx = 10;
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
ret = wdrvExtTextOut(drv, bx, 65, bgItems[i].text, (int16_t)strlen(bgItems[i].text),
|
||||||
|
bgItems[i].fg, bgItems[i].bg, true, ttfSans16);
|
||||||
|
logMsg(" bg[%d] ret=%" PRId32 "\n", i, ret);
|
||||||
|
bx += (int16_t)(strlen(bgItems[i].text) * 9 + 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Transparent over colored rectangles (y=95) ---
|
||||||
|
// Dark blue strip
|
||||||
|
wdrvFillRect(drv, 10, 95, 600, 25, MAKE_RGB(0, 0, 128));
|
||||||
|
if (ttfSans16) {
|
||||||
|
const char *msg = "Transparent text over dark blue rectangle";
|
||||||
|
ret = wdrvExtTextOut(drv, 20, 98, msg, (int16_t)strlen(msg),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, ttfSans16);
|
||||||
|
logMsg(" trans1 ret=%" PRId32 "\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dark green strip
|
||||||
|
wdrvFillRect(drv, 10, 125, 600, 25, MAKE_RGB(0, 128, 0));
|
||||||
|
if (ttfSans16) {
|
||||||
|
const char *msg = "Yellow text over dark green rectangle";
|
||||||
|
ret = wdrvExtTextOut(drv, 20, 128, msg, (int16_t)strlen(msg),
|
||||||
|
MAKE_RGB(255, 255, 0), MAKE_RGB(0, 0, 0), false, ttfSans16);
|
||||||
|
logMsg(" trans2 ret=%" PRId32 "\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Multiple fonts in color (y=160) ---
|
||||||
|
{
|
||||||
|
int16_t fy = 160;
|
||||||
|
|
||||||
|
const char *fontMsg = "The quick brown fox jumps over the lazy dog";
|
||||||
|
int16_t fontLen = (int16_t)strlen(fontMsg);
|
||||||
|
|
||||||
|
// Built-in: white on dark red
|
||||||
|
ret = wdrvExtTextOut(drv, 10, fy, fontMsg, fontLen,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(170, 0, 0), true, NULL);
|
||||||
|
logMsg(" font-builtin ret=%" PRId32 "\n", ret);
|
||||||
|
fy += 20;
|
||||||
|
|
||||||
|
// Courier .FON: cyan on black
|
||||||
|
if (courFont) {
|
||||||
|
ret = wdrvExtTextOut(drv, 10, fy, fontMsg, fontLen,
|
||||||
|
MAKE_RGB(0, 255, 255), MAKE_RGB(0, 0, 0), true, courFont);
|
||||||
|
logMsg(" font-cour ret=%" PRId32 "\n", ret);
|
||||||
|
fy += 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sans .FON: yellow on dark blue
|
||||||
|
if (sansFont) {
|
||||||
|
ret = wdrvExtTextOut(drv, 10, fy, fontMsg, fontLen,
|
||||||
|
MAKE_RGB(255, 255, 0), MAKE_RGB(0, 0, 128), true, sansFont);
|
||||||
|
logMsg(" font-sans ret=%" PRId32 "\n", ret);
|
||||||
|
fy += 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TTF Sans: green on dark gray
|
||||||
|
if (ttfSans16) {
|
||||||
|
ret = wdrvExtTextOut(drv, 10, fy, fontMsg, fontLen,
|
||||||
|
MAKE_RGB(0, 255, 0), MAKE_RGB(64, 64, 64), true, ttfSans16);
|
||||||
|
logMsg(" font-ttfsans ret=%" PRId32 "\n", ret);
|
||||||
|
fy += 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TTF Serif: magenta on dark green
|
||||||
|
if (ttfSerif16) {
|
||||||
|
ret = wdrvExtTextOut(drv, 10, fy, fontMsg, fontLen,
|
||||||
|
MAKE_RGB(255, 0, 255), MAKE_RGB(0, 100, 0), true, ttfSerif16);
|
||||||
|
logMsg(" font-ttfserif ret=%" PRId32 "\n", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Color palette grid (y=280) ---
|
||||||
|
{
|
||||||
|
static const struct { const char *name; uint32_t color; } fgPal[] = {
|
||||||
|
{ "Bk", MAKE_RGB( 0, 0, 0) },
|
||||||
|
{ "Rd", MAKE_RGB(255, 0, 0) },
|
||||||
|
{ "Gn", MAKE_RGB( 0, 255, 0) },
|
||||||
|
{ "Bl", MAKE_RGB( 0, 128, 255) },
|
||||||
|
{ "Yw", MAKE_RGB(255, 255, 0) },
|
||||||
|
{ "Cn", MAKE_RGB( 0, 255, 255) },
|
||||||
|
{ "Mg", MAKE_RGB(255, 0, 255) },
|
||||||
|
{ "Wh", MAKE_RGB(255, 255, 255) },
|
||||||
|
};
|
||||||
|
static const struct { const char *name; uint32_t color; } bgPal[] = {
|
||||||
|
{ "Black", MAKE_RGB( 0, 0, 0) },
|
||||||
|
{ "Blue", MAKE_RGB( 0, 0, 200) },
|
||||||
|
{ "Red", MAKE_RGB(200, 0, 0) },
|
||||||
|
{ "White", MAKE_RGB(255, 255, 255) },
|
||||||
|
};
|
||||||
|
|
||||||
|
int16_t gy = 280;
|
||||||
|
|
||||||
|
// Column headers (background names)
|
||||||
|
int16_t hdrX = 10 + 30; // offset past row labels
|
||||||
|
for (int bg = 0; bg < 4; bg++) {
|
||||||
|
ret = wdrvExtTextOut(drv, (int16_t)(hdrX + bg * 75), gy,
|
||||||
|
bgPal[bg].name, (int16_t)strlen(bgPal[bg].name),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
gy += 18;
|
||||||
|
|
||||||
|
// Grid cells
|
||||||
|
for (int fg = 0; fg < 8; fg++) {
|
||||||
|
// Row label
|
||||||
|
ret = wdrvExtTextOut(drv, 10, gy,
|
||||||
|
fgPal[fg].name, (int16_t)strlen(fgPal[fg].name),
|
||||||
|
MAKE_RGB(170, 170, 170), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
|
||||||
|
for (int bg = 0; bg < 4; bg++) {
|
||||||
|
ret = wdrvExtTextOut(drv, (int16_t)(40 + bg * 75), gy,
|
||||||
|
"Aa", 2,
|
||||||
|
fgPal[fg].color, bgPal[bg].color, true, NULL);
|
||||||
|
}
|
||||||
|
gy += 18;
|
||||||
|
}
|
||||||
|
logMsg(" palette grid done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
wdrvUnloadFont(ttfSans20);
|
||||||
|
wdrvUnloadFont(ttfSans16);
|
||||||
|
wdrvUnloadFont(courFont);
|
||||||
|
wdrvUnloadFont(sansFont);
|
||||||
|
wdrvUnloadFont(ttfSerif16);
|
||||||
|
logMsg(" Color text demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO08.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 9: ROP3 Operations
|
||||||
|
if (info.hasBitBlt) {
|
||||||
|
logMsg("Demo 9: ROP3 Operations\n");
|
||||||
|
int32_t ret;
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
// Title
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
const char *title = "Demo 9: ROP3 Operations";
|
||||||
|
wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout: 5 columns, 3 rows
|
||||||
|
// Row 1 (r1): source color A (also used as BitBlt source)
|
||||||
|
// Row 2 (r2): operand color B
|
||||||
|
// Row 3 (r3): ROP result
|
||||||
|
// S3TRIO's accelerated BitBlt corrupts source VRAM during source-
|
||||||
|
// dependent ROPs, so each source rect is redrawn after the ROP.
|
||||||
|
int16_t bx = 20;
|
||||||
|
int16_t by = 40;
|
||||||
|
int16_t bw = 100;
|
||||||
|
int16_t bh = 50;
|
||||||
|
int16_t gap = 5;
|
||||||
|
int16_t col = bw + 20;
|
||||||
|
int16_t r1 = by;
|
||||||
|
int16_t r2 = by + bh + gap;
|
||||||
|
int16_t r3 = by + 2 * (bh + gap);
|
||||||
|
|
||||||
|
// Column 0: DSTINVERT (no source needed)
|
||||||
|
wdrvFillRect(drv, bx, r1, bw, bh, MAKE_RGB(255, 0, 0));
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.dstX = bx + 10;
|
||||||
|
bp.dstY = r1 + 10;
|
||||||
|
bp.width = bw - 20;
|
||||||
|
bp.height = bh - 20;
|
||||||
|
bp.rop3 = DSTINVERT;
|
||||||
|
ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" DSTINVERT ret=%" PRId32 "\n", ret);
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, bx, r3 + bh + 5, "DSTINVERT", 9,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column 1: SRCINVERT (green XOR yellow)
|
||||||
|
// Fill source (r1) with green, copy to result (r3) via SRCCOPY
|
||||||
|
wdrvFillRect(drv, bx + col, r1, bw, bh, MAKE_RGB(0, 255, 0));
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = bx + col;
|
||||||
|
bp.srcY = r1;
|
||||||
|
bp.dstX = bx + col;
|
||||||
|
bp.dstY = r3;
|
||||||
|
bp.width = bw;
|
||||||
|
bp.height = bh;
|
||||||
|
bp.rop3 = SRCCOPY;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
wdrvFillRect(drv, bx + col, r1, bw, bh, MAKE_RGB(0, 255, 0));
|
||||||
|
// Fill source (r1) with yellow, SRCINVERT into result (r3)
|
||||||
|
wdrvFillRect(drv, bx + col, r1, bw, bh, MAKE_RGB(255, 255, 0));
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = bx + col;
|
||||||
|
bp.srcY = r1;
|
||||||
|
bp.dstX = bx + col;
|
||||||
|
bp.dstY = r3;
|
||||||
|
bp.width = bw;
|
||||||
|
bp.height = bh;
|
||||||
|
bp.rop3 = SRCINVERT;
|
||||||
|
ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" SRCINVERT ret=%" PRId32 "\n", ret);
|
||||||
|
// Redraw display rows (source may be corrupted by S3TRIO)
|
||||||
|
wdrvFillRect(drv, bx + col, r1, bw, bh, MAKE_RGB(0, 255, 0));
|
||||||
|
wdrvFillRect(drv, bx + col, r2, bw, bh, MAKE_RGB(255, 255, 0));
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, bx + col, r3 + bh + 5, "SRCINVERT", 9,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column 2: NOTSRCCOPY (NOT blue)
|
||||||
|
wdrvFillRect(drv, bx + 2 * col, r1, bw, bh, MAKE_RGB(0, 0, 255));
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = bx + 2 * col;
|
||||||
|
bp.srcY = r1;
|
||||||
|
bp.dstX = bx + 2 * col;
|
||||||
|
bp.dstY = r3;
|
||||||
|
bp.width = bw;
|
||||||
|
bp.height = bh;
|
||||||
|
bp.rop3 = NOTSRCCOPY;
|
||||||
|
ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" NOTSRCCOPY ret=%" PRId32 "\n", ret);
|
||||||
|
// Redraw source display
|
||||||
|
wdrvFillRect(drv, bx + 2 * col, r1, bw, bh, MAKE_RGB(0, 0, 255));
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, bx + 2 * col, r3 + bh + 5, "NOTSRCCOPY", 10,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column 3: SRCAND (yellow AND cyan)
|
||||||
|
// Fill result (r3) with cyan, fill source (r1) with yellow, SRCAND
|
||||||
|
wdrvFillRect(drv, bx + 3 * col, r3, bw, bh, MAKE_RGB(0, 255, 255));
|
||||||
|
wdrvFillRect(drv, bx + 3 * col, r1, bw, bh, MAKE_RGB(255, 255, 0));
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = bx + 3 * col;
|
||||||
|
bp.srcY = r1;
|
||||||
|
bp.dstX = bx + 3 * col;
|
||||||
|
bp.dstY = r3;
|
||||||
|
bp.width = bw;
|
||||||
|
bp.height = bh;
|
||||||
|
bp.rop3 = SRCAND;
|
||||||
|
ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" SRCAND ret=%" PRId32 "\n", ret);
|
||||||
|
// Redraw display rows
|
||||||
|
wdrvFillRect(drv, bx + 3 * col, r1, bw, bh, MAKE_RGB(255, 255, 0));
|
||||||
|
wdrvFillRect(drv, bx + 3 * col, r2, bw, bh, MAKE_RGB(0, 255, 255));
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, bx + 3 * col, r3 + bh + 5, "SRCAND", 6,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Column 4: SRCPAINT (red OR blue)
|
||||||
|
// Fill result (r3) with blue, fill source (r1) with red, SRCPAINT
|
||||||
|
wdrvFillRect(drv, bx + 4 * col, r3, bw, bh, MAKE_RGB(0, 0, 255));
|
||||||
|
wdrvFillRect(drv, bx + 4 * col, r1, bw, bh, MAKE_RGB(255, 0, 0));
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = bx + 4 * col;
|
||||||
|
bp.srcY = r1;
|
||||||
|
bp.dstX = bx + 4 * col;
|
||||||
|
bp.dstY = r3;
|
||||||
|
bp.width = bw;
|
||||||
|
bp.height = bh;
|
||||||
|
bp.rop3 = SRCPAINT;
|
||||||
|
ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" SRCPAINT ret=%" PRId32 "\n", ret);
|
||||||
|
// Redraw display rows
|
||||||
|
wdrvFillRect(drv, bx + 4 * col, r1, bw, bh, MAKE_RGB(255, 0, 0));
|
||||||
|
wdrvFillRect(drv, bx + 4 * col, r2, bw, bh, MAKE_RGB(0, 0, 255));
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, bx + 4 * col, r3 + bh + 5, "SRCPAINT", 8,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
logMsg(" ROP3 demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO09.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 10: ScanLR + Flood Fill
|
||||||
|
if (info.hasBitBlt) {
|
||||||
|
logMsg("Demo 10: ScanLR + Flood Fill\n");
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
const char *title = "Demo 10: ScanLR + Flood Fill";
|
||||||
|
wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw outlined shapes using wdrvRectangle
|
||||||
|
if (info.hasOutput) {
|
||||||
|
wdrvRectangle(drv, 50, 50, 150, 100, MAKE_RGB(255, 255, 255));
|
||||||
|
wdrvRectangle(drv, 250, 50, 150, 100, MAKE_RGB(255, 255, 0));
|
||||||
|
wdrvRectangle(drv, 450, 50, 150, 100, MAKE_RGB(0, 255, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try flood fill (FB-based, skips multi-plane VGA)
|
||||||
|
int32_t ret = wdrvFloodFill(drv, 125, 100, MAKE_RGB(255, 0, 0));
|
||||||
|
logMsg(" FloodFill rect1 ret=%" PRId32 "\n", ret);
|
||||||
|
|
||||||
|
ret = wdrvFloodFill(drv, 325, 100, MAKE_RGB(0, 255, 0));
|
||||||
|
logMsg(" FloodFill rect2 ret=%" PRId32 "\n", ret);
|
||||||
|
|
||||||
|
ret = wdrvFloodFill(drv, 525, 100, MAKE_RGB(0, 0, 255));
|
||||||
|
logMsg(" FloodFill rect3 ret=%" PRId32 "\n", ret);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, 80, 155, "Red Fill", 8,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
wdrvExtTextOut(drv, 280, 155, "Green Fill", 10,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
wdrvExtTextOut(drv, 480, 155, "Blue Fill", 9,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test ScanLR if available
|
||||||
|
if (info.hasScanLR) {
|
||||||
|
int16_t leftX = wdrvScanLR(drv, 125, 100, MAKE_RGB(255, 0, 0), WDRV_SCAN_LEFT);
|
||||||
|
int16_t rightX = wdrvScanLR(drv, 125, 100, MAKE_RGB(255, 0, 0), WDRV_SCAN_RIGHT);
|
||||||
|
logMsg(" ScanLR at (125,100): left=%d right=%d\n", leftX, rightX);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
char buf[64];
|
||||||
|
int len = sprintf(buf, "ScanLR: L=%d R=%d", leftX, rightX);
|
||||||
|
wdrvExtTextOut(drv, 10, 200, buf, (int16_t)len,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logMsg(" Flood fill demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO10.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 11: Text Measurement
|
||||||
|
if (info.hasExtTextOut && info.hasGetCharWidth) {
|
||||||
|
logMsg("Demo 11: Text Measurement\n");
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
const char *title = "Demo 11: Text Measurement";
|
||||||
|
wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t ty = 40;
|
||||||
|
|
||||||
|
// Measure built-in font
|
||||||
|
const char *testStr = "Hello, World!";
|
||||||
|
int16_t testLen = (int16_t)strlen(testStr);
|
||||||
|
int32_t measuredW = wdrvMeasureText(drv, NULL, testStr, testLen);
|
||||||
|
logMsg(" Built-in '%s' width=%" PRId32 "\n", testStr, measuredW);
|
||||||
|
|
||||||
|
wdrvExtTextOut(drv, 10, ty, testStr, testLen,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 128), true, NULL);
|
||||||
|
// Draw underline at measured width
|
||||||
|
if (info.hasOutput) {
|
||||||
|
Point16T pts[2];
|
||||||
|
pts[0].x = 10;
|
||||||
|
pts[0].y = ty + 18;
|
||||||
|
pts[1].x = 10 + (int16_t)measuredW;
|
||||||
|
pts[1].y = ty + 18;
|
||||||
|
wdrvPolyline(drv, pts, 2, MAKE_RGB(255, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[80];
|
||||||
|
int len = sprintf(buf, "Width = %" PRId32 " pixels", measuredW);
|
||||||
|
wdrvExtTextOut(drv, 10 + (int16_t)measuredW + 10, ty,
|
||||||
|
buf, (int16_t)len,
|
||||||
|
MAKE_RGB(255, 255, 0), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
ty += 30;
|
||||||
|
|
||||||
|
// Measure TTF font
|
||||||
|
WdrvFontT ttfFont = wdrvLoadFontTtf("LIBSANS.TTF", 16);
|
||||||
|
if (ttfFont) {
|
||||||
|
const char *ttfStr = "TrueType measurement test";
|
||||||
|
int16_t ttfLen = (int16_t)strlen(ttfStr);
|
||||||
|
int32_t ttfW = wdrvMeasureText(drv, ttfFont, ttfStr, ttfLen);
|
||||||
|
logMsg(" TTF '%s' width=%" PRId32 "\n", ttfStr, ttfW);
|
||||||
|
|
||||||
|
wdrvExtTextOut(drv, 10, ty, ttfStr, ttfLen,
|
||||||
|
MAKE_RGB(0, 255, 255), MAKE_RGB(0, 64, 64), true, ttfFont);
|
||||||
|
if (info.hasOutput) {
|
||||||
|
Point16T pts[2];
|
||||||
|
pts[0].x = 10;
|
||||||
|
pts[0].y = ty + 20;
|
||||||
|
pts[1].x = 10 + (int16_t)ttfW;
|
||||||
|
pts[1].y = ty + 20;
|
||||||
|
wdrvPolyline(drv, pts, 2, MAKE_RGB(255, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
len = sprintf(buf, "Width = %" PRId32 " pixels", ttfW);
|
||||||
|
wdrvExtTextOut(drv, 10 + (int16_t)ttfW + 10, ty,
|
||||||
|
buf, (int16_t)len,
|
||||||
|
MAKE_RGB(255, 255, 0), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
ty += 30;
|
||||||
|
|
||||||
|
wdrvUnloadFont(ttfFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show individual char widths
|
||||||
|
int16_t charWidths[26];
|
||||||
|
int32_t ret = wdrvGetCharWidths(drv, NULL, 'A', 'Z', charWidths);
|
||||||
|
if (ret == WDRV_OK) {
|
||||||
|
int16_t cx = 10;
|
||||||
|
for (int ci = 0; ci < 26; ci++) {
|
||||||
|
char ch[2] = { (char)('A' + ci), 0 };
|
||||||
|
wdrvExtTextOut(drv, cx, ty, ch, 1,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
cx += charWidths[ci];
|
||||||
|
}
|
||||||
|
ty += 20;
|
||||||
|
|
||||||
|
len = sprintf(buf, "Char widths A-Z from GetCharWidth DDI");
|
||||||
|
wdrvExtTextOut(drv, 10, ty, buf, (int16_t)len,
|
||||||
|
MAKE_RGB(170, 170, 170), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
logMsg(" Text measurement demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO11.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 12: Styled Pen Lines
|
||||||
|
if (info.hasOutput) {
|
||||||
|
logMsg("Demo 12: Styled Pen Lines\n");
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
const char *title = "Demo 12: Styled Pen Lines";
|
||||||
|
wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct { const char *name; int16_t style; } penStyles[] = {
|
||||||
|
{ "SOLID", WDRV_PEN_SOLID },
|
||||||
|
{ "DASH", WDRV_PEN_DASH },
|
||||||
|
{ "DOT", WDRV_PEN_DOT },
|
||||||
|
{ "DASHDOT", WDRV_PEN_DASHDOT },
|
||||||
|
{ "DASHDOTDOT", WDRV_PEN_DASHDOTDOT },
|
||||||
|
};
|
||||||
|
|
||||||
|
int16_t ly = 40;
|
||||||
|
for (int si = 0; si < 5; si++) {
|
||||||
|
// Draw horizontal line
|
||||||
|
Point16T pts[2];
|
||||||
|
pts[0].x = 120;
|
||||||
|
pts[0].y = ly + 8;
|
||||||
|
pts[1].x = screenW - 20;
|
||||||
|
pts[1].y = ly + 8;
|
||||||
|
int32_t ret = wdrvPolylineEx(drv, pts, 2, MAKE_RGB(255, 255, 255), penStyles[si].style);
|
||||||
|
logMsg(" %s ret=%" PRId32 "\n", penStyles[si].name, ret);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, 10, ly, penStyles[si].name, (int16_t)strlen(penStyles[si].name),
|
||||||
|
MAKE_RGB(255, 255, 0), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
ly += 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw styled rectangles
|
||||||
|
ly += 10;
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, 10, ly, "Styled Rectangles:", 18,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
ly += 20;
|
||||||
|
|
||||||
|
int16_t rx = 20;
|
||||||
|
for (int si = 0; si < 5; si++) {
|
||||||
|
wdrvRectangleEx(drv, rx, ly, 100, 60, MAKE_RGB(0, 255, 255), penStyles[si].style);
|
||||||
|
rx += 120;
|
||||||
|
}
|
||||||
|
|
||||||
|
logMsg(" Styled pen demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO12.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 13: Pixel Buffer Blit
|
||||||
|
if (info.hasBitBlt) {
|
||||||
|
logMsg("Demo 13: Pixel Buffer Blit\n");
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
const char *title = "Demo 13: Pixel Buffer Blit";
|
||||||
|
wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a 256-color gradient pattern
|
||||||
|
int16_t patW = 256;
|
||||||
|
int16_t patH = 200;
|
||||||
|
uint8_t *pattern = (uint8_t *)malloc(patW * patH);
|
||||||
|
|
||||||
|
if (pattern) {
|
||||||
|
for (int16_t py = 0; py < patH; py++) {
|
||||||
|
for (int16_t px = 0; px < patW; px++) {
|
||||||
|
pattern[py * patW + px] = (uint8_t)((px + py) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ret = wdrvBlitPixels(drv, 20, 40, patW, patH, pattern, patW);
|
||||||
|
logMsg(" BlitPixels gradient ret=%" PRId32 "\n", ret);
|
||||||
|
free(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a color bars pattern
|
||||||
|
int16_t barW = 256;
|
||||||
|
int16_t barH = 100;
|
||||||
|
uint8_t *bars = (uint8_t *)malloc(barW * barH);
|
||||||
|
|
||||||
|
if (bars) {
|
||||||
|
for (int16_t py = 0; py < barH; py++) {
|
||||||
|
for (int16_t px = 0; px < barW; px++) {
|
||||||
|
bars[py * barW + px] = (uint8_t)(px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ret = wdrvBlitPixels(drv, 300, 40, barW, barH, bars, barW);
|
||||||
|
logMsg(" BlitPixels bars ret=%" PRId32 "\n", ret);
|
||||||
|
free(bars);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, 20, 250, "Gradient pattern", 16,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
wdrvExtTextOut(drv, 300, 250, "Color bars", 10,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
logMsg(" Pixel blit demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO13.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 14: Hardware Cursor
|
||||||
|
if (info.hasSetCursor && info.hasMoveCursor) {
|
||||||
|
logMsg("Demo 14: Hardware Cursor\n");
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
const char *title = "Demo 14: Hardware Cursor";
|
||||||
|
wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
wdrvExtTextOut(drv, 10, 30, "Cursor shapes cycling automatically.", 36,
|
||||||
|
MAKE_RGB(170, 170, 170), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw some background content
|
||||||
|
wdrvFillRect(drv, 100, 100, 200, 200, MAKE_RGB(0, 0, 128));
|
||||||
|
wdrvFillRect(drv, 350, 100, 200, 200, MAKE_RGB(0, 128, 0));
|
||||||
|
|
||||||
|
static const WdrvCursorShapeE shapes[] = {
|
||||||
|
WDRV_CURSOR_ARROW,
|
||||||
|
WDRV_CURSOR_CROSSHAIR,
|
||||||
|
WDRV_CURSOR_IBEAM,
|
||||||
|
WDRV_CURSOR_HAND,
|
||||||
|
};
|
||||||
|
static const char *shapeNames[] = {
|
||||||
|
"Arrow", "Crosshair", "I-Beam", "Hand",
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int si = 0; si < 4; si++) {
|
||||||
|
int32_t ret = wdrvSetCursor(drv, shapes[si]);
|
||||||
|
logMsg(" SetCursor(%s) ret=%" PRId32 "\n", shapeNames[si], ret);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
// Clear label area
|
||||||
|
wdrvFillRect(drv, 10, 50, 400, 20, MAKE_RGB(0, 0, 0));
|
||||||
|
char buf[64];
|
||||||
|
int len = sprintf(buf, "Cursor: %s", shapeNames[si]);
|
||||||
|
wdrvExtTextOut(drv, 10, 50, buf, (int16_t)len,
|
||||||
|
MAKE_RGB(255, 255, 0), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animate cursor in a circle
|
||||||
|
int16_t cx = screenW / 2;
|
||||||
|
int16_t cy = screenH / 2;
|
||||||
|
int16_t radius = 120;
|
||||||
|
|
||||||
|
for (int angle = 0; angle < 360; angle += 5) {
|
||||||
|
int a = angle % 360;
|
||||||
|
int qa = a % 90;
|
||||||
|
int32_t s = (int32_t)qa * radius / 90;
|
||||||
|
int32_t c = (int32_t)(90 - qa) * radius / 90;
|
||||||
|
int16_t mx = cx;
|
||||||
|
int16_t my = cy;
|
||||||
|
|
||||||
|
if (a < 90) {
|
||||||
|
mx = (int16_t)(cx + s);
|
||||||
|
my = (int16_t)(cy - c);
|
||||||
|
} else if (a < 180) {
|
||||||
|
mx = (int16_t)(cx + c);
|
||||||
|
my = (int16_t)(cy + s);
|
||||||
|
} else if (a < 270) {
|
||||||
|
mx = (int16_t)(cx - s);
|
||||||
|
my = (int16_t)(cy + c);
|
||||||
|
} else {
|
||||||
|
mx = (int16_t)(cx - c);
|
||||||
|
my = (int16_t)(cy - s);
|
||||||
|
}
|
||||||
|
|
||||||
|
wdrvMoveCursor(drv, mx, my);
|
||||||
|
|
||||||
|
// Small delay via port I/O
|
||||||
|
for (int d = 0; d < 500; d++) {
|
||||||
|
(void)inportb(0x80);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide cursor
|
||||||
|
wdrvSetCursor(drv, WDRV_CURSOR_NONE);
|
||||||
|
logMsg(" Cursor demo done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO14.PNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo 15: Screen Save/Restore (via screen-to-screen BitBlt)
|
||||||
|
if (info.hasBitBlt) {
|
||||||
|
logMsg("Demo 15: Screen Save/Restore\n");
|
||||||
|
WdrvBitBltParamsT bp;
|
||||||
|
|
||||||
|
// Clear screen
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.width = screenW;
|
||||||
|
bp.height = screenH;
|
||||||
|
bp.rop3 = BLACKNESS;
|
||||||
|
wdrvBitBlt(drv, &bp);
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
const char *title = "Demo 15: Screen Save/Restore";
|
||||||
|
wdrvExtTextOut(drv, 10, 10, title, (int16_t)strlen(title),
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw source content at (20,40)
|
||||||
|
int16_t saveX = 20;
|
||||||
|
int16_t saveY = 40;
|
||||||
|
int16_t saveW = 100;
|
||||||
|
int16_t saveH = 80;
|
||||||
|
|
||||||
|
wdrvFillRect(drv, saveX, saveY, saveW, saveH, MAKE_RGB(255, 0, 0));
|
||||||
|
wdrvFillRect(drv, saveX + 20, saveY + 10, 60, 60, MAKE_RGB(0, 255, 0));
|
||||||
|
wdrvFillRect(drv, saveX + 30, saveY + 20, 40, 30, MAKE_RGB(0, 0, 255));
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, saveX, saveY + saveH + 5, "Source", 6,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save: blit source region to a hidden screen area (bottom of screen)
|
||||||
|
int16_t stashY = screenH - saveH - 1;
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = saveX;
|
||||||
|
bp.srcY = saveY;
|
||||||
|
bp.dstX = 0;
|
||||||
|
bp.dstY = stashY;
|
||||||
|
bp.width = saveW;
|
||||||
|
bp.height = saveH;
|
||||||
|
bp.rop3 = SRCCOPY;
|
||||||
|
int32_t ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" Save to stash(%d,%d) ret=%" PRId32 "\n", 0, stashY, ret);
|
||||||
|
|
||||||
|
// Overwrite the source area
|
||||||
|
wdrvFillRect(drv, saveX, saveY, saveW, saveH, MAKE_RGB(64, 64, 64));
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, saveX + 5, saveY + 35, "Cleared", 7,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(64, 64, 64), true, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore: blit from stash to two different positions
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = 0;
|
||||||
|
bp.srcY = stashY;
|
||||||
|
bp.dstX = 200;
|
||||||
|
bp.dstY = saveY;
|
||||||
|
bp.width = saveW;
|
||||||
|
bp.height = saveH;
|
||||||
|
bp.rop3 = SRCCOPY;
|
||||||
|
ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" Restore copy1 ret=%" PRId32 "\n", ret);
|
||||||
|
|
||||||
|
memset(&bp, 0, sizeof(bp));
|
||||||
|
bp.srcX = 0;
|
||||||
|
bp.srcY = stashY;
|
||||||
|
bp.dstX = 350;
|
||||||
|
bp.dstY = saveY;
|
||||||
|
bp.width = saveW;
|
||||||
|
bp.height = saveH;
|
||||||
|
bp.rop3 = SRCCOPY;
|
||||||
|
ret = wdrvBitBlt(drv, &bp);
|
||||||
|
logMsg(" Restore copy2 ret=%" PRId32 "\n", ret);
|
||||||
|
|
||||||
|
// Clear the stash area
|
||||||
|
wdrvFillRect(drv, 0, stashY, saveW, saveH, MAKE_RGB(0, 0, 0));
|
||||||
|
|
||||||
|
if (info.hasExtTextOut) {
|
||||||
|
wdrvExtTextOut(drv, 200, saveY + saveH + 5, "Copy 1", 6,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
wdrvExtTextOut(drv, 350, saveY + saveH + 5, "Copy 2", 6,
|
||||||
|
MAKE_RGB(255, 255, 255), MAKE_RGB(0, 0, 0), false, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
logMsg(" Screen save/restore done\n");
|
||||||
|
wdrvScreenshot(drv, "DEMO15.PNG");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void setupPalette(WdrvHandleT drv)
|
static void setupPalette(WdrvHandleT drv)
|
||||||
{
|
{
|
||||||
// The driver sets up its own palette during Enable (via VBE 4F09)
|
// Set the standard Windows 3.1 default 256-color palette.
|
||||||
// and stores an internal color table that RealizeObject uses for
|
// This is an 8R x 8G x 4B color cube with the 20 static system
|
||||||
// color matching. We leave the palette as-is so the DAC and the
|
// colors overwriting indices 0-9 and 246-255.
|
||||||
// internal table stay in sync. RealizeObject will find the best
|
// Using a consistent palette ensures identical output across all
|
||||||
// matching index, and the DAC will display the correct color.
|
// drivers regardless of their built-in default palettes.
|
||||||
(void)drv;
|
uint8_t pal[1024]; // 256 entries x 4 bytes (R, G, B, flags)
|
||||||
|
|
||||||
|
// Generate 8R x 8G x 4B color cube
|
||||||
|
for (int32_t b = 0; b < 4; b++) {
|
||||||
|
for (int32_t g = 0; g < 8; g++) {
|
||||||
|
for (int32_t r = 0; r < 8; r++) {
|
||||||
|
int32_t idx = b * 64 + g * 8 + r;
|
||||||
|
pal[idx * 4 + 0] = (uint8_t)(r * 0x20);
|
||||||
|
pal[idx * 4 + 1] = (uint8_t)(g * 0x20);
|
||||||
|
pal[idx * 4 + 2] = (uint8_t)(b * 0x40);
|
||||||
|
pal[idx * 4 + 3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite first 10 entries with static system colors
|
||||||
|
static const uint8_t sysFirst[10][3] = {
|
||||||
|
{ 0x00, 0x00, 0x00 }, // 0: Black
|
||||||
|
{ 0x80, 0x00, 0x00 }, // 1: Dark Red
|
||||||
|
{ 0x00, 0x80, 0x00 }, // 2: Dark Green
|
||||||
|
{ 0x80, 0x80, 0x00 }, // 3: Dark Yellow
|
||||||
|
{ 0x00, 0x00, 0x80 }, // 4: Dark Blue
|
||||||
|
{ 0x80, 0x00, 0x80 }, // 5: Dark Magenta
|
||||||
|
{ 0x00, 0x80, 0x80 }, // 6: Dark Cyan
|
||||||
|
{ 0xC0, 0xC0, 0xC0 }, // 7: Light Gray
|
||||||
|
{ 0xC0, 0xDC, 0xC0 }, // 8: Money Green
|
||||||
|
{ 0xA6, 0xCA, 0xF0 }, // 9: Sky Blue
|
||||||
|
};
|
||||||
|
for (int32_t i = 0; i < 10; i++) {
|
||||||
|
pal[i * 4 + 0] = sysFirst[i][0];
|
||||||
|
pal[i * 4 + 1] = sysFirst[i][1];
|
||||||
|
pal[i * 4 + 2] = sysFirst[i][2];
|
||||||
|
pal[i * 4 + 3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite last 10 entries (246-255) with static system colors
|
||||||
|
static const uint8_t sysLast[10][3] = {
|
||||||
|
{ 0xFF, 0xFB, 0xF0 }, // 246: Cream
|
||||||
|
{ 0xA0, 0xA0, 0xA4 }, // 247: Medium Gray
|
||||||
|
{ 0x80, 0x80, 0x80 }, // 248: Dark Gray
|
||||||
|
{ 0xFF, 0x00, 0x00 }, // 249: Red
|
||||||
|
{ 0x00, 0xFF, 0x00 }, // 250: Green
|
||||||
|
{ 0xFF, 0xFF, 0x00 }, // 251: Yellow
|
||||||
|
{ 0x00, 0x00, 0xFF }, // 252: Blue
|
||||||
|
{ 0xFF, 0x00, 0xFF }, // 253: Magenta
|
||||||
|
{ 0x00, 0xFF, 0xFF }, // 254: Cyan
|
||||||
|
{ 0xFF, 0xFF, 0xFF }, // 255: White
|
||||||
|
};
|
||||||
|
for (int32_t i = 0; i < 10; i++) {
|
||||||
|
pal[(246 + i) * 4 + 0] = sysLast[i][0];
|
||||||
|
pal[(246 + i) * 4 + 1] = sysLast[i][1];
|
||||||
|
pal[(246 + i) * 4 + 2] = sysLast[i][2];
|
||||||
|
pal[(246 + i) * 4 + 3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wdrvSetPalette(drv, 0, 256, pal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
37
dosbox-et4000.conf
Normal file
37
dosbox-et4000.conf
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# DOSBox-X config for ET4000.DRV testing
|
||||||
|
[sdl]
|
||||||
|
output = surface
|
||||||
|
windowresolution = 1024x768
|
||||||
|
|
||||||
|
[dosbox]
|
||||||
|
machine = svga_et4000
|
||||||
|
memsize = 64
|
||||||
|
quit warning = false
|
||||||
|
|
||||||
|
[cpu]
|
||||||
|
core = normal
|
||||||
|
cputype = pentium
|
||||||
|
cycles = max
|
||||||
|
|
||||||
|
[render]
|
||||||
|
aspect = true
|
||||||
|
scaler = none
|
||||||
|
|
||||||
|
[video]
|
||||||
|
vmemsize = 8
|
||||||
|
vmemsizekb = 0
|
||||||
|
vesa oldvbe = false
|
||||||
|
vesa oldvbe10 = false
|
||||||
|
|
||||||
|
[dos]
|
||||||
|
umb = true
|
||||||
|
xms = true
|
||||||
|
ems = true
|
||||||
|
|
||||||
|
[autoexec]
|
||||||
|
@echo off
|
||||||
|
mount c /home/scott/claude/windriver
|
||||||
|
c:
|
||||||
|
cd bin
|
||||||
|
DEMO.EXE ET4000.DRV
|
||||||
|
exit
|
||||||
37
dosbox-s3trio.conf
Normal file
37
dosbox-s3trio.conf
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# DOSBox-X config for S3TRIO.DRV testing
|
||||||
|
[sdl]
|
||||||
|
output = surface
|
||||||
|
windowresolution = 1024x768
|
||||||
|
|
||||||
|
[dosbox]
|
||||||
|
machine = svga_s3trio64
|
||||||
|
memsize = 64
|
||||||
|
quit warning = false
|
||||||
|
|
||||||
|
[cpu]
|
||||||
|
core = normal
|
||||||
|
cputype = pentium
|
||||||
|
cycles = max
|
||||||
|
|
||||||
|
[render]
|
||||||
|
aspect = true
|
||||||
|
scaler = none
|
||||||
|
|
||||||
|
[video]
|
||||||
|
vmemsize = 8
|
||||||
|
vmemsizekb = 0
|
||||||
|
vesa oldvbe = false
|
||||||
|
vesa oldvbe10 = false
|
||||||
|
|
||||||
|
[dos]
|
||||||
|
umb = true
|
||||||
|
xms = true
|
||||||
|
ems = true
|
||||||
|
|
||||||
|
[autoexec]
|
||||||
|
@echo off
|
||||||
|
mount c /home/scott/claude/windriver
|
||||||
|
c:
|
||||||
|
cd bin
|
||||||
|
DEMO.EXE S3TRIO.DRV
|
||||||
|
exit
|
||||||
37
dosbox-vbesvga.conf
Normal file
37
dosbox-vbesvga.conf
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# DOSBox-X config for VBESVGA.DRV testing
|
||||||
|
[sdl]
|
||||||
|
output = surface
|
||||||
|
windowresolution = 1024x768
|
||||||
|
|
||||||
|
[dosbox]
|
||||||
|
machine = svga_s3trio64
|
||||||
|
memsize = 64
|
||||||
|
quit warning = false
|
||||||
|
|
||||||
|
[cpu]
|
||||||
|
core = normal
|
||||||
|
cputype = pentium
|
||||||
|
cycles = max
|
||||||
|
|
||||||
|
[render]
|
||||||
|
aspect = true
|
||||||
|
scaler = none
|
||||||
|
|
||||||
|
[video]
|
||||||
|
vmemsize = 8
|
||||||
|
vmemsizekb = 0
|
||||||
|
vesa oldvbe = false
|
||||||
|
vesa oldvbe10 = false
|
||||||
|
|
||||||
|
[dos]
|
||||||
|
umb = true
|
||||||
|
xms = true
|
||||||
|
ems = true
|
||||||
|
|
||||||
|
[autoexec]
|
||||||
|
@echo off
|
||||||
|
mount c /home/scott/claude/windriver
|
||||||
|
c:
|
||||||
|
cd bin
|
||||||
|
DEMO.EXE VBESVGA.DRV
|
||||||
|
exit
|
||||||
37
dosbox-vga.conf
Normal file
37
dosbox-vga.conf
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# DOSBox-X config for VGA.DRV testing
|
||||||
|
[sdl]
|
||||||
|
output = surface
|
||||||
|
windowresolution = 1024x768
|
||||||
|
|
||||||
|
[dosbox]
|
||||||
|
machine = svga_s3trio64
|
||||||
|
memsize = 64
|
||||||
|
quit warning = false
|
||||||
|
|
||||||
|
[cpu]
|
||||||
|
core = normal
|
||||||
|
cputype = pentium
|
||||||
|
cycles = max
|
||||||
|
|
||||||
|
[render]
|
||||||
|
aspect = true
|
||||||
|
scaler = none
|
||||||
|
|
||||||
|
[video]
|
||||||
|
vmemsize = 8
|
||||||
|
vmemsizekb = 0
|
||||||
|
vesa oldvbe = false
|
||||||
|
vesa oldvbe10 = false
|
||||||
|
|
||||||
|
[dos]
|
||||||
|
umb = true
|
||||||
|
xms = true
|
||||||
|
ems = true
|
||||||
|
|
||||||
|
[autoexec]
|
||||||
|
@echo off
|
||||||
|
mount c /home/scott/claude/windriver
|
||||||
|
c:
|
||||||
|
cd bin
|
||||||
|
DEMO.EXE VGA.DRV
|
||||||
|
exit
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# S3 Trio64 SVGA with VESA support
|
# S3 Trio64 SVGA with VESA support
|
||||||
|
|
||||||
[sdl]
|
[sdl]
|
||||||
output = opengl
|
output = surface
|
||||||
windowresolution = 1024x768
|
windowresolution = 1024x768
|
||||||
|
|
||||||
[dosbox]
|
[dosbox]
|
||||||
|
|
@ -31,10 +31,4 @@ xms = true
|
||||||
ems = true
|
ems = true
|
||||||
|
|
||||||
[autoexec]
|
[autoexec]
|
||||||
@echo off
|
|
||||||
mount c /home/scott/claude/windriver
|
|
||||||
c:
|
|
||||||
cd bin
|
|
||||||
DEMO.EXE S3TRIO.DRV
|
|
||||||
rem exit
|
|
||||||
|
|
||||||
|
|
|
||||||
1724
win31drv/stb_image_write.h
Normal file
1724
win31drv/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load diff
1725
win31drv/windrv.c
1725
win31drv/windrv.c
File diff suppressed because it is too large
Load diff
|
|
@ -73,6 +73,10 @@ typedef struct {
|
||||||
bool hasExtTextOut; // Driver exports ExtTextOut
|
bool hasExtTextOut; // Driver exports ExtTextOut
|
||||||
bool hasSetPalette; // Driver exports SetPalette
|
bool hasSetPalette; // Driver exports SetPalette
|
||||||
bool hasSetCursor; // Driver exports SetCursor
|
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;
|
} WdrvInfoT;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -150,6 +154,12 @@ int32_t wdrvPolyline(WdrvHandleT handle, Point16T *points, int16_t count, uint32
|
||||||
// Draw a rectangle outline.
|
// Draw a rectangle outline.
|
||||||
int32_t wdrvRectangle(WdrvHandleT handle, int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color);
|
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.
|
// Draw text using the ExtTextOut DDI function.
|
||||||
// Pass NULL for font to use the built-in 8x16 VGA bitmap font.
|
// Pass NULL for font to use the built-in 8x16 VGA bitmap font.
|
||||||
int32_t wdrvExtTextOut(WdrvHandleT handle, int16_t x, int16_t y,
|
int32_t wdrvExtTextOut(WdrvHandleT handle, int16_t x, int16_t y,
|
||||||
|
|
@ -157,6 +167,104 @@ int32_t wdrvExtTextOut(WdrvHandleT handle, int16_t x, int16_t y,
|
||||||
uint32_t fgColor, uint32_t bgColor,
|
uint32_t fgColor, uint32_t bgColor,
|
||||||
bool opaque, WdrvFontT font);
|
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
|
// Font loading
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -201,6 +309,10 @@ void *wdrvGetFramebuffer(WdrvHandleT handle);
|
||||||
// Get the framebuffer pitch (bytes per scanline).
|
// Get the framebuffer pitch (bytes per scanline).
|
||||||
int32_t wdrvGetPitch(WdrvHandleT handle);
|
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
|
// Error reporting
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue