📄 dibdisplay.c
字号:
/****************************************************************************************/
/* DIBDisplay.C */
/* */
/* Author: Mike Sandige */
/* Description: display surface manager for windows with a DIB as the frame buffer */
/* Code fragments contributed by John Miles */
/* */
/* The contents of this file are subject to the Genesis3D Public License */
/* Version 1.0 (the "License"); you may not use this file except in */
/* compliance with the License. You may obtain a copy of the License at */
/* http://www.genesis3d.com */
/* */
/* Software distributed under the License is distributed on an "AS IS" */
/* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See */
/* the License for the specific language governing rights and limitations */
/* under the License. */
/* */
/* The Original Code is Genesis3D, released March 25, 1999. */
/* Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved */
/* */
/****************************************************************************************/
#define WIN32_LEAN_AND_MEAN
#pragma warning(disable : 4201 4214 4115)
#include <windows.h>
#pragma warning(default : 4201 4214 4115; disable : 4514)
#include "DIBDisplay.h"
#include <assert.h>
#include <stdio.h> // vsprintf()
#include <malloc.h> // malloc(),free()
#include "errorlog.h"
static const char * DIBDISPLAY_DESCRIPTION_STRING = "Window DIB ";
typedef struct
{
uint r;
uint g;
uint b;
int alpha;
}
DIBDisplay_RGB32;
// data needed for DIB section (and some cached info about bitmasks
typedef struct
{
uint DIB_R_bitmask; // DIB high-color pixel format
uint DIB_G_bitmask;
uint DIB_B_bitmask;
BITMAPINFO *pbmi; // BITMAPINFO structure
HBITMAP hDIB; // Handle returned from CreateDIBSection
ubyte *lpDIBBuffer; // DIB image buffer
} DIBDisplay_DIBInfo;
typedef struct DIBDisplay
{
HWND hWnd; // Handle to application window
bool Locked; // is display 'locked'
int BitsPerPixel; // Mode info set by last call to
int Pitch; // (BitsPerPixel/8) * Size_X
int Size_X; // size of window rounded up to the nearest multiple of 4
int Size_Y;
uint Flags; // display flags (currently unused)
DIBDisplay_DIBInfo DIBInfo;
} DIBDisplay;
void DIBDisplay_GetDisplayFormat( const DIBDisplay *D,
int *Width,
int *Height,
int *BitsPerPixel,
uint *Flags)
{
assert( D != NULL );
assert( Width != NULL );
assert( Height != NULL );
assert( BitsPerPixel != NULL );
assert( Flags != NULL );
*Width = D->Size_X;
*Height = D->Size_Y;
*BitsPerPixel = D->BitsPerPixel;
*Flags = D->Flags;
}
bool DIBDisplay_GetDisplayInfo( char *DescriptionString,
unsigned int DescriptionStringMaxLength,
DisplayModeInfo *Info)
{
int BitsPerPixel;
assert( Info != NULL );
assert( DescriptionString != NULL );
assert( DescriptionStringMaxLength > 0 );
if (strlen(DIBDISPLAY_DESCRIPTION_STRING) >= DescriptionStringMaxLength)
{
geErrorLog_AddString(GE_ERR_BAD_PARAMETER,"DIBDisplay_GetDescriptionString: description string too short",NULL);
return false;
}
strcpy(DescriptionString,DIBDISPLAY_DESCRIPTION_STRING);
// if ( CPUInfo_TestFor3DNow()==true)
// BitsPerPixel = 32;
// else
BitsPerPixel = 16;
if (DisplayModeInfo_AddEntry(Info,-1,-1,BitsPerPixel,0)==false)
{
geErrorLog_AddString(GE_ERR_SUBSYSTEM_FAILURE,"DIBDisplay_GetDescriptionString: unable to add mode entry",NULL);
return false;
}
return true;
}
//------------------------------------------------
static void DIBDisplay_DebugPrintf(char *fmt, ...)
{
static char work_string[4096];
if ((fmt == NULL) || (strlen(fmt) > sizeof(work_string)))
{
strcpy(work_string, "(String missing or too large)");
}
else
{
va_list ap;
va_start(ap,fmt);
vsprintf(work_string, fmt, ap);
va_end (ap);
}
#if 0 // log to file
{
FILE *log;
log = fopen("DEBUG.LOG","a+t");
if (log != NULL)
{
fprintf(log,"%s\n",work_string);
fclose(log);
}
}
#endif
OutputDebugString(work_string);
}
//------------------------------------------------
#ifndef NDEBUG
static bool DIBDisplay_IsValid(const DIBDisplay *D)
{
if (D == NULL)
return false;
if (D->DIBInfo.pbmi == NULL)
return false;
if (D->DIBInfo.hDIB == NULL)
return false;
if (D->DIBInfo.lpDIBBuffer == NULL)
return false;
return true;
}
#endif
//------------------------------------------------
static bool DIBDisplay_FindDesktopRGBMasks( HDC hdc,
int desktop_bpp,
uint *desktop_R_bitmask,
uint *desktop_G_bitmask,
uint *desktop_B_bitmask)
{
assert( hdc != NULL );
assert( desktop_R_bitmask != NULL );
assert( desktop_G_bitmask != NULL );
assert( desktop_B_bitmask != NULL );
if(desktop_bpp > 8)
{
COLORREF color,save;
HBITMAP TempBmp;
OSVERSIONINFO WinVer;
memset(&WinVer, 0, sizeof(OSVERSIONINFO));
WinVer.dwOSVersionInfoSize =sizeof(OSVERSIONINFO);
GetVersionEx(&WinVer);
if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
TempBmp =CreateCompatibleBitmap(hdc, 8, 8);
if(TempBmp)
{
BITMAPINFO *TempInfo;
int HeaderSize = sizeof(BITMAPINFO) + sizeof(RGBQUAD)*2;
TempInfo = malloc(HeaderSize);
if (TempInfo == NULL)
{
geErrorLog_Add(DIBDisplay_FindDesktopRGBMasks,"Failed to allocate header for NT mask test");
DeleteObject(TempBmp);
return false;
}
memset(TempInfo, 0, HeaderSize);
TempInfo->bmiHeader.biSize =sizeof(BITMAPINFO);
TempInfo->bmiHeader.biBitCount =(uint16)desktop_bpp;
TempInfo->bmiHeader.biCompression =BI_BITFIELDS;
if(GetDIBits(hdc, TempBmp, 0, 0, NULL, TempInfo, DIB_RGB_COLORS))
{
*desktop_R_bitmask =*((uint *)&TempInfo->bmiColors[0]);
*desktop_G_bitmask =*((uint *)&TempInfo->bmiColors[1]);
*desktop_B_bitmask =*((uint *)&TempInfo->bmiColors[2]);
DIBDisplay_DebugPrintf("(%x-%x-%x)\n", *desktop_R_bitmask, *desktop_G_bitmask, *desktop_B_bitmask);
}
else
{
free(TempInfo);
DeleteObject(TempBmp);
geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to get bit format from desktop compatible bitmap",NULL);
return false;
}
free(TempInfo);
DeleteObject(TempBmp);
}
else
{
geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to create desktop compatible bitmap",NULL);
return false;
}
// detect failure (Win2000 only?)
if (((*desktop_R_bitmask | *desktop_G_bitmask | *desktop_B_bitmask)&0x7FFF) != 0x7FFF)
{
SetLastError(0);
geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: GetDIBits didn't return proper masking information.",NULL);
return false;
}
}
else
{
HDC hdc2;
hdc2 = CreateDC("Display", NULL, NULL,NULL);
if (hdc2==NULL)
{
geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to create compatible hdc",NULL);
return false;
}
save = GetPixel(hdc2,0,0);
if ( save == CLR_INVALID )
{
geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to get pixel from desktop",NULL);
DeleteDC(hdc2);
return false;
}
if (SetPixel(hdc2,0,0,RGB(0x08,0x08,0x08))==-1)
{
geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to select bitmap",NULL);
DeleteDC(hdc2);
return false;
}
color = GetPixel(hdc2,0,0) & 0xffffff;
if ( color == CLR_INVALID )
{
geErrorLog_AddString(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_FindDesktopRGBMasks: Unable to get test pixel from desktop",NULL);
DeleteDC(hdc2);
return false;
}
SetPixel(hdc,0,0,save); // ignore an error here.
DeleteDC(hdc2);
DIBDisplay_DebugPrintf("DIBDisplay: Desktop pixel format = 0x%X ",color);
switch (color)
{
case 0x000000: // 0x000000 = 5-5-5
DIBDisplay_DebugPrintf("(5-5-5)\n");
*desktop_R_bitmask = 0x007c00;
*desktop_G_bitmask = 0x0003e0;
*desktop_B_bitmask = 0x00001f;
break;
case 0x000800: // 0x000800 = 5-6-5
DIBDisplay_DebugPrintf("(5-6-5)\n");
*desktop_R_bitmask = 0x00f800;
*desktop_G_bitmask = 0x0007e0;
*desktop_B_bitmask = 0x00001f;
break;
case 0x080808: // 0x080808 = 8-8-8
DIBDisplay_DebugPrintf("(8-8-8)\n");
*desktop_R_bitmask = 0xff0000;
*desktop_G_bitmask = 0x00ff00;
*desktop_B_bitmask = 0x0000ff;
break;
default:
DIBDisplay_DebugPrintf("(Unsupported, using 5-6-5)\n");
if ((desktop_bpp == 15) || (desktop_bpp == 16))
{
*desktop_R_bitmask = 0x00f800;
*desktop_G_bitmask = 0x0007e0;
*desktop_B_bitmask = 0x00001f;
}
else
{
geErrorLog_AddString(GE_ERR_DISPLAY_RESOURCE,"DIBDisplay_FindDesktopRGBMasks: Unsupported desktop format.",NULL);
return false;
}
break;
}
}
}
return true;
}
//------------------------------------------------
static void DIBDisplay_DestroyDIB(DIBDisplay_DIBInfo *DI)
{
assert( DI != NULL );
if (DI->pbmi != NULL)
{
free(DI->pbmi);
DI->pbmi = NULL;
}
if (DI->hDIB != NULL)
{
DeleteObject(DI->hDIB);
DI->hDIB = NULL;
}
}
//------------------------------------------------
static bool DIBDisplay_CreateDIB(
int display_size_X,
int display_size_Y,
int display_bpp,
HWND hWnd,
DIBDisplay_DIBInfo *DI)
{
HDC hdc;
BITMAPINFOHEADER *pbmih; // Pointer to pbmi header
uint desktop_R_bitmask; // Desktop high-color pixel format
uint desktop_G_bitmask;
uint desktop_B_bitmask;
int desktop_bpp; // Windows video mode BPP
assert( display_size_X > 0 );
assert( display_size_Y > 0 );
assert( (display_bpp == 16) || (display_bpp == 24));
assert( DI != NULL );
DI->hDIB = NULL;
DI->lpDIBBuffer = NULL;
DI->pbmi = (BITMAPINFO *)
malloc(sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256));
if (DI->pbmi == NULL)
{
geErrorLog_Add(GE_ERR_MEMORY_RESOURCE,"DIBDisplay_CreateDIB: failed to allocate bitmap header");
return false;
}
memset(DI->pbmi, 0, sizeof (BITMAPINFOHEADER) + (sizeof (RGBQUAD) * 256));
pbmih = &(DI->pbmi->bmiHeader);
pbmih->biSize = sizeof(BITMAPINFOHEADER);
pbmih->biWidth = display_size_X;
pbmih->biHeight = -(display_size_Y);
pbmih->biPlanes = 1;
pbmih->biBitCount = (uint16) display_bpp;
pbmih->biSizeImage = 0;
pbmih->biXPelsPerMeter = 0;
pbmih->biYPelsPerMeter = 0;
pbmih->biClrUsed = 0;
pbmih->biClrImportant = 0;
//
// Get Windows desktop display format (and masks, in high-color modes)
//
hdc = GetDC(hWnd);
if ( hdc == NULL )
{
geErrorLog_Add(GE_ERR_WINDOWS_API_FAILURE,"DIBDisplay_CreateDIB: unable to get desktop HDC");
return false;
}
desktop_bpp = GetDeviceCaps(hdc, BITSPIXEL) *
GetDeviceCaps(hdc, PLANES);
DIBDisplay_DebugPrintf("DIBDisplay: Desktop %d BPP\n", desktop_bpp);
if (DIBDisplay_FindDesktopRGBMasks( hdc,
desktop_bpp,
&desktop_R_bitmask,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -