More cleanups.

Added more languages.
Updated SCAT machines (for the Asian demo machines.)
Fixed VC project files.
Started integrating building of language DLL's into mainline.
Added the Award 8088 XT Clone machine.
This commit is contained in:
waltje
2018-06-16 18:38:02 -04:00
parent eb5a5d6b71
commit 162afde8b8
35 changed files with 3597 additions and 4369 deletions

View File

@@ -8,15 +8,12 @@
*
* Rendering module for Microsoft DirectDraw 9.
*
* NOTES: This code should be re-merged into a single init() with a
* 'fullscreen' argument, indicating FS mode is requested.
*
* If configured with USE_LIBPNG, we try to load the external
* PNG library and use that if found. Otherwise, we fall back
* the original mode, which uses the Windows/DDraw built-in BMP
* format.
*
* Version: @(#)win_ddraw.cpp 1.0.13 2018/05/24
* Version: @(#)win_ddraw.cpp 1.0.15 2018/06/11
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -91,6 +88,8 @@ png_structp (*PNG_create_write_struct)(png_const_charp user_png_ver,
png_voidp error_ptr,
png_error_ptr error_fn,
png_error_ptr warn_fn);
void (*PNG_destroy_write_struct)(png_structpp png_ptr_ptr,
png_infopp info_ptr_ptr);
png_infop (*PNG_create_info_struct)(png_const_structrp png_ptr);
void (*PNG_init_io)(png_structrp png_ptr, png_FILE_p fp);
void (*PNG_set_IHDR)(png_const_structrp png_ptr,
@@ -112,6 +111,7 @@ void (*PNG_write_end)(png_structrp png_ptr,
static const dllimp_t png_imports[] = {
{ "png_create_write_struct", &PNG_create_write_struct },
{ "png_destroy_write_struct", &PNG_destroy_write_struct },
{ "png_create_info_struct", &PNG_create_info_struct },
{ "png_init_io", &PNG_init_io },
{ "png_set_IHDR", &PNG_set_IHDR },
@@ -211,288 +211,6 @@ GetError(HRESULT hr)
}
static HBITMAP
CopySurface(IDirectDrawSurface4 *pDDSurface)
{
HBITMAP hbmp, hbmprev;
DDSURFACEDESC2 ddsd;
HDC hdc, hmemdc;
pDDSurface->GetDC(&hdc);
hmemdc = CreateCompatibleDC(hdc);
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
pDDSurface->GetSurfaceDesc(&ddsd);
hbmp = CreateCompatibleBitmap(hdc, xs, ys);
hbmprev = (HBITMAP)SelectObject(hmemdc, hbmp);
BitBlt(hmemdc, 0, 0, xs, ys, hdc, 0, 0, SRCCOPY);
SelectObject(hmemdc, hbmprev);
DeleteDC(hmemdc);
pDDSurface->ReleaseDC(hdc);
return(hbmp);
}
static void
DoubleLines(uint8_t *dst, uint8_t *src)
{
int i = 0;
for (i = 0; i < ys; i++) {
memcpy(dst + (i * xs * 8), src + (i * xs * 4), xs * 4);
memcpy(dst + ((i * xs * 8) + (xs * 4)), src + (i * xs * 4), xs * 4);
}
}
#ifdef USE_LIBPNG
static void
bgra_to_rgb(png_bytep *b_rgb, uint8_t *bgra, int width, int height)
{
int i, j;
uint8_t *r, *b;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
r = &b_rgb[(height - 1) - i][j * 3];
b = &bgra[((i * width) + j) * 4];
r[0] = b[2];
r[1] = b[1];
r[2] = b[0];
}
}
}
/* Not strictly needed, but hey.. */
static void
png_error_handler(png_structp arg, const char *str)
{
pclog("DDraw: PNG error '%08lx'\n", str);
}
/* Not strictly needed, but hey.. */
static void
png_warning_handler(png_structp arg, const char *str)
{
pclog("DDraw: PNG warning '%08lx'\n", str);
}
static void
SavePNG(const wchar_t *fn, HBITMAP hBitmap)
{
wchar_t temp[512];
BITMAPINFO bmpInfo;
HDC hdc;
LPVOID pBuf = NULL;
LPVOID pBuf2 = NULL;
png_bytep *b_rgb = NULL;
png_infop info_ptr;
png_structp png_ptr;
FILE *fp;
int i;
/* Create file. */
fp = plat_fopen(fn, L"wb");
if (fp == NULL) {
pclog("[SavePNG] File %ls could not be opened for writing!\n", fn);
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
/* Initialize PNG stuff. */
png_ptr = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, (char *)1234,
png_error_handler, png_warning_handler);
if (png_ptr == NULL) {
(void)fclose(fp);
pclog("[SavePNG] png_create_write_struct failed!\n");
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
info_ptr = PNGFUNC(create_info_struct)(png_ptr);
if (info_ptr == NULL) {
// PNGFUNC(destroy_write_struct)(&png_ptr, NULL, NULL);
(void)fclose(fp);
pclog("[SavePNG] png_create_info_struct failed!\n");
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
PNGFUNC(init_io)(png_ptr, fp);
hdc = GetDC(NULL);
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
if (bmpInfo.bmiHeader.biSizeImage <= 0)
bmpInfo.bmiHeader.biSizeImage =
bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) {
// PNGFUNC(destroy_write_struct)(&png_ptr, &info_ptr, NULL);
(void)fclose(fp);
pclog("[SavePNG] Unable to allocate bitmap memory!\n");
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
if (ys2 <= 250) {
bmpInfo.bmiHeader.biSizeImage <<= 1;
if ((pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) {
// PNGFUNC(destroy_write_struct)(&png_ptr, &info_ptr, NULL);
(void)fclose(fp);
free(pBuf);
pclog("[SavePNG] Unable to allocate secondary bitmap memory!\n");
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
bmpInfo.bmiHeader.biHeight <<= 1;
}
#if 1
pclog("save png w=%i h=%i\n",
bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight);
#endif
bmpInfo.bmiHeader.biCompression = BI_RGB;
GetDIBits(hdc, hBitmap, 0,
bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS);
PNGFUNC(set_IHDR)(png_ptr, info_ptr,
bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight,
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
b_rgb = (png_bytep *)malloc(sizeof(png_bytep)*bmpInfo.bmiHeader.biHeight);
if (b_rgb == NULL) {
// PNGFUNC(destroy_write_struct)(&png_ptr, NULL, NULL);
(void)fclose(fp);
free(pBuf);
free(pBuf2);
pclog("[SavePNG] Unable to allocate RGB bitmap memory!\n");
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++)
b_rgb[i] = (png_byte *)malloc(PNGFUNC(get_rowbytes)(png_ptr, info_ptr));
if (pBuf2) {
DoubleLines((uint8_t *)pBuf2, (uint8_t *)pBuf);
bgra_to_rgb(b_rgb, (uint8_t *)pBuf2,
bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight);
} else
bgra_to_rgb(b_rgb, (uint8_t *)pBuf,
bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight);
PNGFUNC(write_info)(png_ptr, info_ptr);
PNGFUNC(write_image)(png_ptr, b_rgb);
PNGFUNC(write_end)(png_ptr, NULL);
/* Clean up. */
if (fp != NULL) fclose(fp);
// PNGFUNC(destroy_write_struct)(&png_ptr, &info_ptr, NULL);
if (hdc) ReleaseDC(NULL, hdc);
if (b_rgb != NULL) {
for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++)
free(b_rgb[i]);
free(b_rgb);
}
if (pBuf != NULL) free(pBuf);
if (pBuf2 != NULL) free(pBuf2);
}
#endif
static void
SaveBMP(const wchar_t *fn, HBITMAP hBitmap)
{
wchar_t temp[512];
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFO bmpInfo;
HDC hdc;
FILE *fp = NULL;
LPVOID pBuf = NULL;
LPVOID pBuf2 = NULL;
hdc = GetDC(NULL);
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
if (bmpInfo.bmiHeader.biSizeImage <= 0)
bmpInfo.bmiHeader.biSizeImage =
bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) {
pclog("[SaveBMP] Unable to allocate bitmap memory!\n");
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
if (ys2 <= 250)
pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage * 2);
bmpInfo.bmiHeader.biCompression = BI_RGB;
GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight,
pBuf, &bmpInfo, DIB_RGB_COLORS);
if ((fp = plat_fopen(fn, L"wb")) == NULL) {
pclog("[SaveBMP] File %ls could not be opened for writing!\n", fn);
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
return;
}
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
if (pBuf2) {
bmpInfo.bmiHeader.biSizeImage <<= 1;
bmpInfo.bmiHeader.biHeight <<= 1;
}
bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHeader.bfType=0x4D42;
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
(void)fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
(void)fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
if (pBuf2) {
DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf);
(void)fwrite(pBuf2,bmpInfo.bmiHeader.biSizeImage,1,fp);
} else {
(void)fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
}
/* Clean up. */
if (fp != NULL) fclose(fp);
if (hdc != NULL) ReleaseDC(NULL, hdc);
if (pBuf2 != NULL) free(pBuf2);
if (pBuf != NULL) free(pBuf);
}
static void
ddraw_fs_size_default(RECT w_rect, RECT *r_dest)
{
@@ -735,23 +453,23 @@ ddraw_close(void)
video_setblit(NULL);
if (lpdds_back2) {
if (lpdds_back2 != NULL) {
lpdds_back2->Release();
lpdds_back2 = NULL;
}
if (lpdds_back) {
if (lpdds_back != NULL) {
lpdds_back->Release();
lpdds_back = NULL;
}
if (lpdds_pri) {
if (lpdds_pri != NULL) {
lpdds_pri->Release();
lpdds_pri = NULL;
}
if (lpdd_clipper) {
if (lpdd_clipper != NULL) {
lpdd_clipper->Release();
lpdd_clipper = NULL;
}
if (lpdd4) {
if (lpdd4 != NULL) {
lpdd4->Release();
lpdd4 = NULL;
}
@@ -766,66 +484,6 @@ ddraw_close(void)
}
#if 0
int
ddraw_init_fs(HWND h)
{
ddraw_w = GetSystemMetrics(SM_CXSCREEN);
ddraw_h = GetSystemMetrics(SM_CYSCREEN);
cgapal_rebuild();
if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) return 0;
if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) return 0;
lpdd->Release();
lpdd = NULL;
atexit(ddraw_close);
if (FAILED(lpdd4->SetCooperativeLevel(h,
DDSCL_SETFOCUSWINDOW | \
DDSCL_CREATEDEVICEWINDOW | \
DDSCL_EXCLUSIVE | \
DDSCL_FULLSCREEN | \
DDSCL_ALLOWREBOOT))) return 0;
if (FAILED(lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) return 0;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.dwBackBufferCount = 1;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) return 0;
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
if (FAILED(lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2))) return 0;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) {
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) return 0;
}
ddraw_hwnd = h;
video_setblit(ddraw_blit_fs);
return(1);
}
#endif
static int
ddraw_init(int fs)
{
@@ -844,7 +502,6 @@ ddraw_init(int fs)
pclog("DDRAW: cannot create an instance (%s)\n", GetError(hr));
return(0);
}
hr = lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4);
if (FAILED(hr)) {
pclog("DDRAW: no interfaces found (%s)\n", GetError(hr));
@@ -868,50 +525,107 @@ ddraw_init(int fs)
return(0);
}
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
if (fs) {
ddraw_w = GetSystemMetrics(SM_CXSCREEN);
ddraw_h = GetSystemMetrics(SM_CYSCREEN);
hr = lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0, 0);
if (FAILED(hr)) {
pclog("DDRAW: SetDisplayMode failed (%s)\n", GetError(hr));
return(0);
}
}
memset(&ddsd, 0x00, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) return(0);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) {
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL)))
fatal("CreateSurface back failed\n");
if (fs) {
ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps |= (DDSCAPS_COMPLEX | DDSCAPS_FLIP);
ddsd.dwBackBufferCount = 1;
}
hr = lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateSurface failed (%s)\n", GetError(hr));
return(0);
}
memset(&ddsd, 0, sizeof(ddsd));
if (fs) {
memset(&ddsd, 0x00, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
hr = lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2);
if (FAILED(hr)) {
pclog("DDRAW: GetAttachedSurface failed (%s)\n", GetError(hr));
return(0);
}
}
memset(&ddsd, 0x00, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) {
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL);
if (FAILED(hr)) {
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL)))
fatal("CreateSurface back failed\n");
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateSurface(back) failed (%s)\n", GetError(hr));
return(0);
}
}
if (FAILED(lpdd4->CreateClipper(0, &lpdd_clipper, NULL))) return(0);
if (! fs) {
memset(&ddsd, 0x00, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL);
if (FAILED(hr)) {
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateSurface(back2) failed (%s)\n", GetError(hr));
return(0);
}
}
if (FAILED(lpdd_clipper->SetHWnd(0, h))) return(0);
hr = lpdd4->CreateClipper(0, &lpdd_clipper, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateClipper failed (%s)\n", GetError(hr));
return(0);
}
if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) return(0);
hr = lpdd_clipper->SetHWnd(0, h);
if (FAILED(hr)) {
pclog("DDRAW: SetHWnd failed (%s)\n", GetError(hr));
return(0);
}
hr = lpdds_pri->SetClipper(lpdd_clipper);
if (FAILED(hr)) {
pclog("DDRAW: SetClipper failed (%s)\n", GetError(hr));
return(0);
}
}
ddraw_hwnd = h;
video_setblit(ddraw_blit);
if (fs)
video_setblit(ddraw_blit_fs);
else
video_setblit(ddraw_blit);
#ifdef USE_LIBPNG
# if USE_LIBPNG == 2
@@ -929,11 +643,197 @@ ddraw_init(int fs)
}
#ifdef USE_LIBPNG
static void
bgra_to_rgb(png_bytep *b_rgb, uint8_t *bgra, int width, int height)
{
int h, w;
uint8_t *r, *b;
for (h = 0; h < height; h++) {
for (w = 0; w < width; w++) {
/* Get pointer to pixel in bitmap data. */
b = &bgra[((h * width) + w) * 4];
/* Get pointer to png row data. */
r = &b_rgb[(height - 1) - h][w * 3];
/* Copy the pixel data. */
r[0] = b[2];
r[1] = b[1];
r[2] = b[0];
}
}
}
static void
error_handler(png_structp arg, const char *str)
{
pclog("PNG: stream 0x%08lx error '%s'\n", arg, str);
}
static void
warning_handler(png_structp arg, const char *str)
{
pclog("PNG: stream 0x%08lx warning '%s'\n", arg, str);
}
static int
SavePNG(const wchar_t *fn, BITMAPINFO *bmi, uint8_t *pixels)
{
png_structp png = NULL;
png_infop info = NULL;
uint8_t *r, *b;
png_bytep row;
FILE *fp;
int h, w;
/* Create the image file. */
fp = plat_fopen(fn, L"wb");
if (fp == NULL) {
pclog("[SavePNG] File %ls could not be opened for writing!\n", fn);
error:
if (png != NULL)
PNGFUNC(destroy_write_struct)(&png, &info);
if (fp != NULL)
(void)fclose(fp);
return(0);
}
/* Initialize PNG stuff. */
png = PNGFUNC(create_write_struct)(PNG_LIBPNG_VER_STRING, NULL,
error_handler, warning_handler);
if (png == NULL) {
pclog("[SavePNG] create_write_struct failed!\n");
goto error;
}
info = PNGFUNC(create_info_struct)(png);
if (info == NULL) {
pclog("[SavePNG] create_info_struct failed!\n");
goto error;
}
PNGFUNC(init_io)(png, fp);
PNGFUNC(set_IHDR)(png, info,
bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
pclog("PNG: write_info\n");
PNGFUNC(write_info)(png, info);
/* Create a buffer for one scanline of pixels. */
row = (png_bytep)malloc(PNGFUNC(get_rowbytes)(png, info));
/* Process all scanlines in the image. */
pclog("PNG: convert\n");
for (h = 0; h < bmi->bmiHeader.biHeight; h++) {
r = row;
for (w = 0; w < bmi->bmiHeader.biWidth; w++) {
/* Get pointer to pixel in bitmap data. */
b = &pixels[((h * bmi->bmiHeader.biWidth) + w) * 4];
/* Copy the pixel data. */
r[0] = b[2];
r[1] = b[1];
r[2] = b[0];
/* Next pixel on scanline. */
r += 3;
}
/* Write this row to the file. */
// png_write_row(png, row);
}
/* No longer need the row buffer. */
free(row);
#if 0
pclog("PNG: write_end\n");
PNGFUNC(write_end)(png, NULL);
#endif
pclog("PNG: destroy\n");
PNGFUNC(destroy_write_struct)(&png, &info);
/* Clean up. */
pclog("PNG: fclose\n");
(void)fclose(fp);
pclog("PNG: done!\n");
return(1);
}
#endif
static int
SaveBMP(const wchar_t *fn, BITMAPINFO *bmi, uint8_t *pixels)
{
BITMAPFILEHEADER bmpHdr;
FILE *fp;
if ((fp = plat_fopen(fn, L"wb")) == NULL) {
pclog("[SaveBMP] File %ls could not be opened for writing!\n", fn);
return(0);
}
memset(&bmpHdr, 0x00, sizeof(BITMAPFILEHEADER));
bmpHdr.bfSize = sizeof(BITMAPFILEHEADER) + \
sizeof(BITMAPINFOHEADER) + bmi->bmiHeader.biSizeImage;
bmpHdr.bfType = 0x4D42;
bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
(void)fwrite(&bmpHdr, sizeof(BITMAPFILEHEADER), 1, fp);
(void)fwrite(&bmi->bmiHeader, sizeof(BITMAPINFOHEADER), 1, fp);
(void)fwrite(pixels, bmi->bmiHeader.biSizeImage, 1, fp);
/* Clean up. */
(void)fclose(fp);
return(1);
}
static HBITMAP
CopySurface(IDirectDrawSurface4 *pDDSurface)
{
HBITMAP hBmp, hOldBmp;
DDSURFACEDESC2 ddsd;
HDC hDC, hMemDC;
pDDSurface->GetDC(&hDC);
hMemDC = CreateCompatibleDC(hDC);
memset(&ddsd, 0x00, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
pDDSurface->GetSurfaceDesc(&ddsd);
hBmp = CreateCompatibleBitmap(hDC, xs, ys);
hOldBmp = (HBITMAP)SelectObject(hMemDC, hBmp);
BitBlt(hMemDC, 0, 0, xs, ys, hDC, 0, 0, SRCCOPY);
SelectObject(hMemDC, hOldBmp);
DeleteDC(hMemDC);
pDDSurface->ReleaseDC(hDC);
return(hBmp);
}
static void
ddraw_screenshot(const wchar_t *fn)
{
wchar_t path[512];
wchar_t temp[512];
HBITMAP hbmp;
BITMAPINFO bmi;
uint8_t *pixels;
uint8_t *pix2;
HBITMAP hBmp;
HDC hDC;
int i;
#if 0
xs = xsize;
@@ -962,24 +862,95 @@ ddraw_screenshot(const wchar_t *fn)
ys2 >>= 1;
}
hbmp = CopySurface(lpdds_back2);
/* Create a surface copy and store it as a bitmap. */
hBmp = CopySurface(lpdds_back);
/* Create a compatible DC. */
hDC = GetDC(NULL);
/* Request the size info from the bitmap. */
memset(&bmi, 0x00, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(hDC, hBmp, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
if (bmi.bmiHeader.biSizeImage <= 0) {
bmi.bmiHeader.biSizeImage = bmi.bmiHeader.biWidth * abs(bmi.bmiHeader.biHeight) * (bmi.bmiHeader.biBitCount + 7) / 8;
}
/* Allocate a buffer for the pixel data. */
if ((pixels = (uint8_t *)malloc(bmi.bmiHeader.biSizeImage)) == NULL) {
pclog("DDraw: unable to allocate bitmap memory!\n");
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), fn);
ui_msgbox(MBX_ERROR, temp);
ReleaseDC(NULL, hDC);
return;
}
/* Now get the actual pixel data from the bitmap. */
bmi.bmiHeader.biCompression = BI_RGB;
GetDIBits(hDC, hBmp, 0, bmi.bmiHeader.biHeight,
pixels, &bmi, DIB_RGB_COLORS);
/* No longer need the DC. */
ReleaseDC(NULL, hDC);
/*
* For some CGA modes (320x200, 640x200 etc) we double-up
* the image height so it looks a little better. We simply
* copy each real scanline.
*/
if (ys <= 250) {
/* Save current buffer. */
pix2 = pixels;
/* Update bitmap image size. */
bmi.bmiHeader.biHeight <<= 1;
bmi.bmiHeader.biSizeImage <<= 1;
/* Allocate new buffer, doubled-up. */
pixels = (uint8_t *)malloc(bmi.bmiHeader.biSizeImage);
/* Copy scanlines. */
for (i = 0; i < ys; i++) {
/* Copy original line. */
memcpy(pixels + (i * xs * 8),
pix2 + (i * xs * 4), xs * 4);
/* And copy it once more, doubling it. */
memcpy(pixels + ((i * xs * 8) + (xs * 4)),
pix2 + (i * xs * 4), xs * 4);
}
/* No longer need original buffer. */
free(pix2);
}
/* Save filename. */
wcscpy(path, fn);
#ifdef USE_LIBPNG
/* Save the screenshot, using PNG if available. */
if (png_handle != NULL) {
/* Use the PNG library. */
SavePNG(fn, hbmp);
i = SavePNG(path, &bmi, pixels);
} else {
#endif
/* Use BMP, so fix the file name. */
wcscpy(temp, fn);
temp[wcslen(temp)-3] = L'b';
temp[wcslen(temp)-2] = L'm';
temp[wcslen(temp)-1] = L'p';
SaveBMP(temp, hbmp);
path[wcslen(path)-3] = L'b';
path[wcslen(path)-2] = L'm';
path[wcslen(path)-1] = L'p';
i = SaveBMP(path, &bmi, pixels);
#ifdef USE_LIBPNG
}
#endif
/* Release pixel buffer. */
free(pixels);
/* Show error message if needed. */
if (i == 0) {
_swprintf(temp, get_string(IDS_ERR_SCRSHOT), path);
ui_msgbox(MBX_ERROR, temp);
}
}
@@ -994,114 +965,3 @@ const vidapi_t ddraw_vidapi = {
ddraw_screenshot,
NULL
};
#if 0
@@@@@
if (fs) {
ddraw_w = GetSystemMetrics(SM_CXSCREEN);
ddraw_h = GetSystemMetrics(SM_CYSCREEN);
hr = lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0, 0);
if (FAILED(hr)) {
pclog("DDRAW: SetDisplayMode failed (%s)\n", GetError(hr));
return(0);
}
}
memset(&ddsd, 0x00, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if (fs) {
ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps |= (DDSCAPS_COMPLEX | DDSCAPS_FLIP);
ddsd.dwBackBufferCount = 1;
}
hr = lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateSurface failed (%s)\n", GetError(hr));
return(0);
}
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL);
if (FAILED(hr)) {
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateSurface back failed (%s)\n", GetError(hr));
return(0);
}
}
if (fs) {
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
hr = lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2);
if (FAILED(hr)) {
pclog("DDRAW: GetAttachedSurface failed (%s)\n", GetError(hr));
return(0);
}
}
memset(&ddsd, 0x00, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
if (fs)
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL);
else
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL);
if (FAILED(hr)) {
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 2048;
ddsd.dwHeight = 2048;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
if (fs)
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL);
else
hr = lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateSurface(back) failed (%s)\n", GetError(hr));
return(0);
}
}
if (! fs) {
hr = lpdd4->CreateClipper(0, &lpdd_clipper, NULL);
if (FAILED(hr)) {
pclog("DDRAW: CreateClipper failed (%s)\n", GetError(hr));
return(0);
}
hr = lpdd_clipper->SetHWnd(0, h);
if (FAILED(hr)) {
pclog("DDRAW: SetHWnd failed (%s)\n", GetError(hr));
return(0);
}
hr = lpdds_pri->SetClipper(lpdd_clipper);
if (FAILED(hr)) {
pclog("DDRAW: SetClipper failed (%s)\n", GetError(hr));
return(0);
}
}
ddraw_hwnd = h;
if (fs)
video_setblit(ddraw_blit_fs);
else
video_setblit(ddraw_blit);
return(1);
}
#endif