Screenshot API added.

This commit is contained in:
Scott Duensing 2026-03-16 18:10:10 -05:00
parent b5488a6a9e
commit d2b90bd83e
2 changed files with 103 additions and 0 deletions

View file

@ -12,6 +12,8 @@
#include <dpmi.h>
#include <signal.h>
#include "thirdparty/stb_image_write.h"
#define DBLCLICK_THRESHOLD (CLOCKS_PER_SEC / 2)
#define ICON_REFRESH_INTERVAL 8
#define KB_MOVE_STEP 8
@ -24,6 +26,7 @@
// Prototypes
// ============================================================
static uint8_t *bufferToRgb(const DisplayT *d, const uint8_t *buf, int32_t w, int32_t h, int32_t pitch);
static void calcPopupSize(const AppContextT *ctx, const MenuT *menu, int32_t *pw, int32_t *ph);
static bool checkAccelTable(AppContextT *ctx, WindowT *win, int32_t key, int32_t modifiers);
static void clickMenuCheckRadio(MenuT *menu, int32_t itemIdx);
@ -78,6 +81,52 @@ static const char sAltScanToAscii[256] = {
// calcPopupSize — compute popup width and height for a menu
// ============================================================
static uint8_t *bufferToRgb(const DisplayT *d, const uint8_t *buf, int32_t w, int32_t h, int32_t pitch) {
uint8_t *rgb = (uint8_t *)malloc((size_t)w * h * 3);
if (!rgb) {
return NULL;
}
int32_t bpp = d->format.bytesPerPixel;
uint8_t *dst = rgb;
for (int32_t y = 0; y < h; y++) {
const uint8_t *row = buf + y * pitch;
for (int32_t x = 0; x < w; x++) {
uint32_t pixel;
if (bpp == 1) {
pixel = row[x];
} else if (bpp == 2) {
pixel = ((const uint16_t *)row)[x];
} else {
pixel = ((const uint32_t *)row)[x];
}
if (d->format.bitsPerPixel == 8) {
int32_t idx = pixel & 0xFF;
dst[0] = d->palette[idx * 3 + 0];
dst[1] = d->palette[idx * 3 + 1];
dst[2] = d->palette[idx * 3 + 2];
} else {
uint32_t rv = (pixel >> d->format.redShift) & ((1u << d->format.redBits) - 1);
uint32_t gv = (pixel >> d->format.greenShift) & ((1u << d->format.greenBits) - 1);
uint32_t bv = (pixel >> d->format.blueShift) & ((1u << d->format.blueBits) - 1);
dst[0] = (uint8_t)(rv << (8 - d->format.redBits));
dst[1] = (uint8_t)(gv << (8 - d->format.greenBits));
dst[2] = (uint8_t)(bv << (8 - d->format.blueBits));
}
dst += 3;
}
}
return rgb;
}
static void calcPopupSize(const AppContextT *ctx, const MenuT *menu, int32_t *pw, int32_t *ph) {
int32_t maxW = 0;
bool hasSub = false;
@ -1389,6 +1438,28 @@ bool dvxUpdate(AppContextT *ctx) {
}
// ============================================================
// dvxScreenshot
// ============================================================
//
// Save the entire screen (backbuffer) to a PNG file.
int32_t dvxScreenshot(AppContextT *ctx, const char *path) {
DisplayT *d = &ctx->display;
uint8_t *rgb = bufferToRgb(d, d->backBuf, d->width, d->height, d->pitch);
if (!rgb) {
return -1;
}
int32_t result = stbi_write_png(path, d->width, d->height, 3, rgb, d->width * 3) ? 0 : -1;
free(rgb);
return result;
}
// ============================================================
// dvxShutdown
// ============================================================
@ -1421,6 +1492,32 @@ int32_t dvxSetWindowIcon(AppContextT *ctx, WindowT *win, const char *path) {
}
// ============================================================
// dvxWindowScreenshot
// ============================================================
//
// Save a window's content buffer to a PNG file. This captures the
// full content area regardless of whether the window is occluded.
int32_t dvxWindowScreenshot(AppContextT *ctx, WindowT *win, const char *path) {
if (!win || !win->contentBuf) {
return -1;
}
uint8_t *rgb = bufferToRgb(&ctx->display, win->contentBuf, win->contentW, win->contentH, win->contentPitch);
if (!rgb) {
return -1;
}
int32_t result = stbi_write_png(path, win->contentW, win->contentH, 3, rgb, win->contentW * 3) ? 0 : -1;
free(rgb);
return result;
}
// ============================================================
// dvxTileWindows
// ============================================================

View file

@ -91,6 +91,9 @@ void dvxMaximizeWindow(AppContextT *ctx, WindowT *win);
// Request exit from main loop
void dvxQuit(AppContextT *ctx);
// Save the entire screen to a PNG file (returns 0 on success, -1 on failure)
int32_t dvxScreenshot(AppContextT *ctx, const char *path);
// Set window title
void dvxSetTitle(AppContextT *ctx, WindowT *win, const char *title);
@ -109,6 +112,9 @@ const BlitOpsT *dvxGetBlitOps(const AppContextT *ctx);
// Load an icon for a window from an image file
int32_t dvxSetWindowIcon(AppContextT *ctx, WindowT *win, const char *path);
// Save a window's content to a PNG file (returns 0 on success, -1 on failure)
int32_t dvxWindowScreenshot(AppContextT *ctx, WindowT *win, const char *path);
// Create an accelerator table (caller must free with dvxFreeAccelTable)
AccelTableT *dvxCreateAccelTable(void);