357 lines
10 KiB
C
357 lines
10 KiB
C
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include "drawdibi.h"
|
|
#include "dither.h"
|
|
|
|
//#define GRAY_SCALE
|
|
|
|
extern BOOL gf286;
|
|
extern UINT gwRasterCaps;
|
|
|
|
void FAR PASCAL Map16to24(LPBITMAPINFOHEADER,LPVOID,int,int,int,int,LPBITMAPINFOHEADER,LPVOID,int,int,LPVOID);
|
|
|
|
extern LPVOID glpDitherTable;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DitherInit()
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
LPVOID VFWAPI
|
|
DitherInit(LPBITMAPINFOHEADER lpbiIn,
|
|
LPBITMAPINFOHEADER lpbiOut,
|
|
DITHERPROC FAR * lpDitherProc,
|
|
LPVOID lpDitherTable)
|
|
{
|
|
switch ((int)lpbiOut->biBitCount)
|
|
{
|
|
case 8:
|
|
if ((int)lpbiIn->biBitCount == 8 && (gwRasterCaps & RC_PALETTE))
|
|
return Dither8Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
|
|
|
|
if ((int)lpbiIn->biBitCount == 8 && !(gwRasterCaps & RC_PALETTE))
|
|
return DitherDeviceInit(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
|
|
|
|
if ((int)lpbiIn->biBitCount == 16)
|
|
return Dither16Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
|
|
|
|
if ((int)lpbiIn->biBitCount == 24)
|
|
return Dither24Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
|
|
|
|
if ((int)lpbiIn->biBitCount == 32)
|
|
return Dither32Init(lpbiIn, lpbiOut, lpDitherProc, lpDitherTable);
|
|
|
|
return (LPVOID)-1;
|
|
|
|
case 24:
|
|
#ifndef _WIN32
|
|
if (!gf286)
|
|
#endif
|
|
{
|
|
if (lpbiIn->biBitCount == 16) {
|
|
*lpDitherProc = Map16to24;
|
|
return NULL;
|
|
} else if (lpbiIn->biBitCount == 32) {
|
|
*lpDitherProc = Map32to24;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return (LPVOID)-1;
|
|
|
|
default:
|
|
return (LPVOID)-1;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DitherTerm()
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void VFWAPI
|
|
DitherTerm(LPVOID lpDitherTable)
|
|
{
|
|
if (lpDitherTable == glpDitherTable)
|
|
Dither16Term(lpDitherTable);
|
|
else
|
|
Dither8Term(lpDitherTable);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DitherDeviceInit() - dither to the colors of the display driver
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
LPVOID FAR PASCAL DitherDeviceInit(LPBITMAPINFOHEADER lpbi, LPBITMAPINFOHEADER lpbiOut, DITHERPROC FAR *lpDitherProc, LPVOID lpDitherTable)
|
|
{
|
|
HBRUSH hbr;
|
|
HDC hdcMem;
|
|
HDC hdc;
|
|
HBITMAP hbm;
|
|
HBITMAP hbmT;
|
|
int i;
|
|
int nColors;
|
|
LPRGBQUAD prgb;
|
|
BITMAPINFOHEADER biSave = *lpbiOut;
|
|
|
|
//
|
|
// we dont need to re-init the dither table, unless it is not ours then
|
|
// we should free it.
|
|
//
|
|
if (lpDitherTable == glpDitherTable)
|
|
{
|
|
DitherTerm(lpDitherTable);
|
|
lpDitherTable = NULL;
|
|
}
|
|
|
|
if (lpDitherTable == NULL)
|
|
{
|
|
lpDitherTable = GlobalAllocPtr(GHND, 256*8*8);
|
|
}
|
|
|
|
if (lpDitherTable == NULL)
|
|
return (LPVOID)-1;
|
|
|
|
hdc = GetDC(NULL);
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
|
|
hbm = CreateCompatibleBitmap(hdc, 256*8, 8);
|
|
hbmT = SelectObject(hdcMem, hbm);
|
|
|
|
if ((nColors = (int)lpbi->biClrUsed) == 0)
|
|
nColors = 1 << (int)lpbi->biBitCount;
|
|
|
|
prgb = (LPRGBQUAD)(lpbi+1);
|
|
|
|
for (i=0; i<nColors; i++)
|
|
{
|
|
hbr = CreateSolidBrush(RGB(prgb[i].rgbRed,prgb[i].rgbGreen,prgb[i].rgbBlue));
|
|
hbr = SelectObject(hdcMem, hbr);
|
|
PatBlt(hdcMem, i*8, 0, 8, 8, PATCOPY);
|
|
hbr = SelectObject(hdcMem, hbr);
|
|
DeleteObject(hbr);
|
|
}
|
|
|
|
#ifdef XDEBUG
|
|
for (i=0; i<16; i++)
|
|
BitBlt(hdc,0,i*8,16*8,8,hdcMem,i*(16*8),0,SRCCOPY);
|
|
#endif
|
|
|
|
SelectObject(hdcMem, hbmT);
|
|
DeleteDC(hdcMem);
|
|
|
|
lpbiOut->biSize = sizeof(BITMAPINFOHEADER);
|
|
lpbiOut->biPlanes = 1;
|
|
lpbiOut->biBitCount = 8;
|
|
lpbiOut->biWidth = 256*8;
|
|
lpbiOut->biHeight = 8;
|
|
lpbiOut->biCompression = BI_RGB;
|
|
lpbiOut->biSizeImage = 256*8*8;
|
|
lpbiOut->biXPelsPerMeter = 0;
|
|
lpbiOut->biYPelsPerMeter = 0;
|
|
lpbiOut->biClrUsed = 0;
|
|
lpbiOut->biClrImportant = 0;
|
|
GetDIBits(hdc, hbm, 0, 8, lpDitherTable, (LPBITMAPINFO)lpbiOut, DIB_RGB_COLORS);
|
|
|
|
i = (int)lpbiOut->biClrUsed;
|
|
*lpbiOut = biSave;
|
|
lpbiOut->biClrUsed = i;
|
|
|
|
DeleteObject(hbm);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
*lpDitherProc = Dither8;
|
|
|
|
return (LPVOID)lpDitherTable;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DitherTerm()
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
void FAR PASCAL Dither8Term(LPVOID lpDitherTable)
|
|
{
|
|
if (lpDitherTable)
|
|
GlobalFreePtr(lpDitherTable);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
|
|
//
|
|
// call this to actually do the dither.
|
|
//
|
|
void FAR PASCAL Dither8(
|
|
LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of the dest
|
|
LPVOID lpDst, // --> to destination bits
|
|
int DstX, // Destination origin - x coordinate
|
|
int DstY, // Destination origin - y coordinate
|
|
int DstXE, // x extent of the BLT
|
|
int DstYE, // y extent of the BLT
|
|
LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of the source
|
|
LPVOID lpSrc, // --> to source bits
|
|
int SrcX, // Source origin - x coordinate
|
|
int SrcY, // Source origin - y coordinate
|
|
LPVOID lpDitherTable) // dither table.
|
|
{
|
|
int x,y;
|
|
UINT wWidthSrc;
|
|
UINT wWidthDst;
|
|
BYTE _huge *pbS;
|
|
BYTE _huge *pbD;
|
|
DWORD dw;
|
|
|
|
if (biDst->biBitCount != 8 || biSrc->biBitCount != 8)
|
|
return;
|
|
|
|
// tomor -- A little help! seems initialization is not done yet.
|
|
if(!lpDitherTable)
|
|
return;
|
|
|
|
wWidthSrc = ((UINT)biSrc->biWidth+3)&~3;
|
|
wWidthDst = ((UINT)biDst->biWidth+3)&~3;
|
|
|
|
pbD = (BYTE _huge *)lpDst + DstX + DstY * wWidthDst;
|
|
pbS = (BYTE _huge *)lpSrc + SrcX + SrcY * wWidthSrc;
|
|
|
|
wWidthSrc -= DstXE;
|
|
wWidthDst -= DstXE;
|
|
|
|
#define DODITH8(px, x, y) ((LPBYTE)lpDitherTable)[((y) & 7) * 256 * 8 + (px) * 8 + (x & 7)]
|
|
|
|
for (y=0; y<DstYE; y++) {
|
|
/* write two DWORDs (one dither cell horizontally) at once */
|
|
for (x=0; x <= (DstXE - 8); x += 8) {
|
|
|
|
dw = DODITH8(*pbS++, 0, y);
|
|
dw |= (DODITH8(*pbS++, 1, y) << 8);
|
|
dw |= (DODITH8(*pbS++, 2, y) << 16);
|
|
dw |= (DODITH8(*pbS++, 3, y) << 24);
|
|
* ( (DWORD _huge UNALIGNED *) pbD)++ = dw;
|
|
|
|
dw = DODITH8(*pbS++, 4, y);
|
|
dw |= (DODITH8(*pbS++, 5, y) << 8);
|
|
dw |= (DODITH8(*pbS++, 6, y) << 16);
|
|
dw |= (DODITH8(*pbS++, 7, y) << 24);
|
|
* ( (DWORD _huge UNALIGNED *) pbD)++ = dw;
|
|
}
|
|
|
|
/* clean up remainder (less than 8 bytes per row) */
|
|
for ( ; x < DstXE; x++) {
|
|
*pbD++ = DODITH8(*pbS++, x, y);
|
|
}
|
|
|
|
pbS += wWidthSrc;
|
|
pbD += wWidthDst;
|
|
}
|
|
#undef DODITH8
|
|
}
|
|
|
|
/*
|
|
* C version of 16->24 mapping (in asm for win16)
|
|
*/
|
|
extern void FAR PASCAL Map16to24(
|
|
LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of the dest
|
|
LPVOID lpDst, // --> to destination bits
|
|
int DstX, // Destination origin - x coordinate
|
|
int DstY, // Destination origin - y coordinate
|
|
int DstXE, // x extent of the BLT
|
|
int DstYE, // y extent of the BLT
|
|
LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of the source
|
|
LPVOID lpSrc, // --> to source bits
|
|
int SrcX, // Source origin - x coordinate
|
|
int SrcY, // Source origin - y coordinate
|
|
LPVOID lpDitherTable) // dither table.
|
|
{
|
|
|
|
int x,y;
|
|
UINT wWidthSrc;
|
|
UINT wWidthDst;
|
|
BYTE _huge *pbS;
|
|
BYTE _huge *pbD;
|
|
WORD wRGB;
|
|
|
|
if (biDst->biBitCount != 24 || biSrc->biBitCount != 16)
|
|
return;
|
|
|
|
/* width of one row is nr pixels * size of pixel rounded to 4-bytes */
|
|
wWidthSrc = ((UINT) (biSrc->biWidth * 2) +3)&~3;
|
|
wWidthDst = ((UINT) (biDst->biWidth * 3) +3)&~3;
|
|
|
|
/* advance to start of source, dest rect within DIB */
|
|
pbD = (BYTE _huge *)lpDst + (DstX * 3) + DstY * wWidthDst;
|
|
pbS = (BYTE _huge *)lpSrc + (SrcX * 2) + SrcY * wWidthSrc;
|
|
|
|
/* amount to advance pointer to next line from end of source, dest rect */
|
|
wWidthSrc -= (DstXE * 2);
|
|
wWidthDst -= (DstXE * 3);
|
|
|
|
for (y=0; y<DstYE; y++) {
|
|
for (x=0; x<DstXE; x++) {
|
|
wRGB = *((LPWORD)pbS)++;
|
|
*pbD++ = (wRGB << 3) & 0xf8;
|
|
*pbD++ = (wRGB >> 2) & 0xf8;
|
|
*pbD++ = (wRGB >> 7) & 0xf8;
|
|
}
|
|
|
|
pbS += wWidthSrc;
|
|
pbD += wWidthDst;
|
|
}
|
|
}
|
|
|
|
void FAR PASCAL Map32to24(
|
|
LPBITMAPINFOHEADER biDst, // --> BITMAPINFO of the dest
|
|
LPVOID lpDst, // --> to destination bits
|
|
int DstX, // Destination origin - x coordinate
|
|
int DstY, // Destination origin - y coordinate
|
|
int DstXE, // x extent of the BLT
|
|
int DstYE, // y extent of the BLT
|
|
LPBITMAPINFOHEADER biSrc, // --> BITMAPINFO of the source
|
|
LPVOID lpSrc, // --> to source bits
|
|
int SrcX, // Source origin - x coordinate
|
|
int SrcY, // Source origin - y coordinate
|
|
LPVOID lpDitherTable) // dither table.
|
|
{
|
|
int x,y;
|
|
UINT wWidthSrc;
|
|
UINT wWidthDst;
|
|
BYTE _huge *pbS;
|
|
BYTE _huge *pbD;
|
|
|
|
if (biDst->biBitCount != 24 || biSrc->biBitCount != 32)
|
|
return;
|
|
|
|
/* width of one row is nr pixels * size of pixel rounded to 4-bytes */
|
|
//wWidthSrc = ((UINT) (biSrc->biWidth * 4) +3)&~3;
|
|
// Multiplying by 4 ensures it is rounded to 4 bytes...
|
|
wWidthSrc = (UINT) (biSrc->biWidth * 4);
|
|
wWidthDst = ((UINT) (biDst->biWidth * 3) +3)&~3;
|
|
|
|
/* advance to start of source, dest rect within DIB */
|
|
pbD = (BYTE _huge *)lpDst + (DstX * 3) + DstY * wWidthDst;
|
|
pbS = (BYTE _huge *)lpSrc + (SrcX * 4) + SrcY * wWidthSrc;
|
|
|
|
/* amount to advance pointer to next line from end of source, dest rect */
|
|
wWidthSrc -= (DstXE * 4);
|
|
wWidthDst -= (DstXE * 3);
|
|
|
|
for (y=0; y<DstYE; y++) {
|
|
for (x=0; x<DstXE; x++) {
|
|
*pbD++ = *pbS++;
|
|
*pbD++ = *pbS++;
|
|
*pbD++ = *pbS++;
|
|
pbS++;
|
|
}
|
|
|
|
pbS += wWidthSrc;
|
|
pbD += wWidthDst;
|
|
}
|
|
}
|
|
#endif
|