Screenshot API added.
This commit is contained in:
parent
b5488a6a9e
commit
d2b90bd83e
2 changed files with 103 additions and 0 deletions
97
dvx/dvxApp.c
97
dvx/dvxApp.c
|
|
@ -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
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue