/** ** fd_win32.c - the Win32-API color frame driver ** ** Author: Gernot Graeff ** E-mail: gernot.graeff@t-online.de ** Date: 21.08.98 ** ** This file is part of the GRX graphics library. ** ** The GRX graphics library is free software; you can redistribute it ** and/or modify it under some conditions; see the "copying.grx" file ** for details. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ** ** Contributions by Josu Onandia (jonandia@fagorautomation.es) 21/02/2001 ** - Some bugs fixed ** - All the pixel reads (GetPixel) are done with in-memory ** bitmaps, because when done with on-screen bitmaps, and if the ** window is partially hidden or out of screen, then GetPixel fails. ** - Loops optimized in bitmap operations ** - Color handling optimized. By storing the last color used ** (index, rgb value) if the next color is the same, there is ** not need to call _GetColor, which is time consuming. ** - 24 bpp driver. ** - WARNINGS: - The colors returned by GetPixel have to be the SAME that ** colors in the ColorList. Unfortunately, Windows doesn't ** use the RGB color you asked for, but an aproximation. Then ** when a pixel is read, its color index it's not found ** (_GetColIndex). It is the responsability of the function ** that loads colors in the ColorList to guarantee that ** those colors will actually be used by Windows 'as-is'. ** - The driver for 4 bits per pixel doesn't work. ** ** Contributions by Mariano Alvarez Fernandez (malfer@terra.es) 27/03/2001 ** - drawpattern implemented ** - bltr2v_24 implemented ** ** TO DO: Support for logical operations in drawpixel, drawblock ** and putscanline ** Implement getiscanline for 8 and 24 bpp ** Implement bltv2r for 24 bpp ** Logical operations for 8 bpp are wrong implemented, they ** must operate with color indices ** Drawline must paint the last point **/ #include #include #include "libgrx.h" #include "libwin32.h" #include "grdriver.h" extern HWND hGRXWnd; extern HDC hDCMem; static COLORREF (*fGetColor)(unsigned int nIndex) = NULL; static long (*fGetColIndex)(COLORREF color) = NULL; static COLORREF _GetColor_palette ( unsigned int nIndex ) { COLORREF color; SColorList *cl; color = RGB ( 0, 0, 0 ); cl = ColorList; while ( cl != NULL ) { if ( cl -> nIndex == nIndex ) { color = cl -> color; break; } cl = cl -> pNext; } return color; } static long _GetColIndex_palette ( COLORREF color ) { long lRet = -1; SColorList *cl; cl = ColorList; while ( cl != NULL ) { if ( cl -> color == color ) { lRet = cl -> nIndex; break; } cl = cl -> pNext; } return lRet; } static COLORREF _GetColor_RGB ( unsigned int nIndex ) { return((COLORREF) nIndex); } static long _GetColIndex_RGB ( COLORREF color ) { return((long)color); } static GrColor i_readpixel(GrFrame *c,int x, int y) { COLORREF color; color = GetPixel ( hDCMem, x, y ); return fGetColIndex ( color ); } static void i_drawpixel(int x,int y,GrColor c) { HDC hDC; COLORREF color; color = fGetColor ( GrColorValue(c) ); hDC = GetDC ( hGRXWnd ); SetPixelV ( hDC, x, y, color ); SetPixelV ( hDCMem, x, y, color ); ReleaseDC ( hGRXWnd, hDC ); } // NOTE: Only handles GrWRITE and GrIMAGE static void i_putscanline(int x,int y,int w, const GrColor *scl, GrColor op ) { GrColor skipc; HDC hDC; COLORREF color; int xx, xend; GRX_ENTER(); skipc = op ^ GrIMAGE; op &= GrCMODEMASK; hDC = GetDC ( hGRXWnd ); xend = x + w; for ( xx = x; xx < xend; xx++) { GrColor c = *(scl++); if (c != skipc) { color = fGetColor ( c ); // Lot more speed if only draw the in-memory bitmap, and then // do an BitBlt from memory to screen. // SetPixelV ( hDC, x, y, color ); SetPixelV ( hDCMem, xx, y, color ); } } BitBlt ( hDC, x, y, w, 1, hDCMem, x, y, SRCCOPY ); ReleaseDC ( hGRXWnd, hDC ); GRX_LEAVE(); } static void i_drawline(int x,int y,int dx,int dy,GrColor c) { HDC hDC; HPEN hPen; HGDIOBJ oldPen; int r2mode; if(c == GrNOCOLOR) return; hDC = GetDC ( hGRXWnd ); hPen = CreatePen ( PS_SOLID, 1, fGetColor ( GrColorValue(c) ) ); switch(C_OPER(c)) { case C_XOR: r2mode = R2_XORPEN; break; case C_OR: r2mode = R2_MERGEPEN; break; case C_AND: r2mode = R2_MASKPEN; break; default: r2mode = R2_COPYPEN; break; } oldPen = SelectObject ( hDC, hPen ); SetROP2(hDC, r2mode); MoveToEx ( hDC, x, y, NULL ); LineTo ( hDC, x + dx, y + dy ); SelectObject ( hDC, oldPen ); SetROP2(hDC, R2_COPYPEN); ReleaseDC ( hGRXWnd, hDC ); oldPen = SelectObject ( hDCMem, hPen ); SetROP2(hDCMem, r2mode); MoveToEx ( hDCMem, x, y, NULL ); LineTo ( hDCMem, x + dx, y + dy ); SelectObject ( hDCMem, oldPen ); SetROP2(hDCMem, R2_COPYPEN); DeleteObject(hPen); } static void i_drawhline(int x,int y,int w,GrColor c) { i_drawline(x, y, w, 0, c); } static void i_drawvline(int x,int y,int h,GrColor c) { i_drawline ( x, y, 0, h, c ); } static void i_drawblock(int x,int y,int w,int h,GrColor c) { HBRUSH hBrush; HDC hDC; RECT rect; hDC = GetDC ( hGRXWnd ); SetRect ( &rect, x, y, x+w, y+h ); hBrush = CreateSolidBrush ( fGetColor ( GrColorValue(c) ) ); FillRect ( hDC, &rect, hBrush ); FillRect ( hDCMem, &rect, hBrush ); ReleaseDC ( hGRXWnd, hDC ); DeleteObject ( hBrush ); } static void i_drawbitmap(int x,int y,int w,int h,char far *bmp,int pitch, int start,GrColor fg,GrColor bg) { HDC hDC; int i, j; COLORREF fgColor=0, bgColor=0; hDC = GetDC ( hGRXWnd ); if(fg != GrNOCOLOR) fgColor = fGetColor ( GrColorValue(fg) ); if(bg != GrNOCOLOR) bgColor = fGetColor ( GrColorValue(bg) ); bmp += start >> 3; start &= 7; for ( i = 0; i < h; i++ ) { unsigned char *bitp = (unsigned char *)bmp; unsigned char bits = *bitp; unsigned char mask = 0x80 >> start; for ( j = 0; j < w; j++ ) { if(bits & mask) { if(fg != GrNOCOLOR) SetPixelV ( hDCMem, x+j, y+i, fgColor ); } else { if(bg != GrNOCOLOR) SetPixelV ( hDCMem, x+j, y+i, bgColor ); } if((mask >>= 1) == 0) { bits = *++bitp; mask = 0x80;} } bmp += pitch; } BitBlt ( hDC, x, y, w, h, hDCMem, x, y, SRCCOPY ); ReleaseDC ( hGRXWnd, hDC ); } static void drawpattern(int x,int y,int w,char patt,GrColor fg,GrColor bg) { HDC hDC; COLORREF fgcolor, bgcolor; GR_int8u mask; GRX_ENTER(); mask = 0x80; w += x; fgcolor = fGetColor ( GrColorValue(fg) ); bgcolor = fGetColor ( GrColorValue(bg) ); hDC = GetDC ( hGRXWnd ); do { SetPixelV ( hDC, x, y, (patt & mask) ? fgcolor : bgcolor ); SetPixelV ( hDCMem, x, y, (patt & mask) ? fgcolor : bgcolor ); if((mask >>= 1) == 0) mask = 0x80; } while(++x != w); ReleaseDC ( hGRXWnd, hDC ); GRX_LEAVE(); } static void bitblt(GrFrame *dst,int dx,int dy,GrFrame *src,int x,int y,int w, int h,GrColor op) { HDC hDC; DWORD dwRop; switch ( op ) { case GrWRITE : case GrIMAGE : dwRop = SRCCOPY; break; case GrXOR : dwRop = SRCINVERT; break; case GrOR : dwRop = SRCPAINT; break; case GrAND : dwRop = SRCAND; //SRCERASE; break; default: dwRop = SRCCOPY; break; } hDC = GetDC ( hGRXWnd ); BitBlt ( hDC, dx, dy, w, h, hDCMem, x, y, dwRop ); BitBlt ( hDCMem, dx, dy, w, h, hDCMem, x, y, dwRop ); ReleaseDC ( hGRXWnd, hDC ); } static void bltv2r_8(GrFrame *dst,int dx,int dy,GrFrame *src,int sx,int sy, int w,int h,GrColor op) { HDC hDC, hDCFrom, hDCAux = 0; int y, x; COLORREF color; DWORD dwRop; HGDIOBJ oldBitmapAux = 0, hBitmapAux = 0; unsigned char *pdst; int lastIndex; COLORREF lastColor; switch ( op ) { case GrWRITE : case GrIMAGE : dwRop = SRCCOPY; break; case GrXOR : dwRop = SRCINVERT; break; case GrOR : dwRop = SRCPAINT; break; case GrAND : dwRop = SRCAND; //SRCERASE; break; default: dwRop = SRCCOPY; break; } hDC = GetDC ( hGRXWnd ); if(dwRop != SRCCOPY) { hDCAux = CreateCompatibleDC ( hDC ); hBitmapAux = CreateCompatibleBitmap ( hDC, w, h ); oldBitmapAux = SelectObject ( hDCAux, hBitmapAux ); BitBlt ( hDCAux, 0, 0, w, h, hDCMem, sx, sy, dwRop ); sx = sy = 0; hDCFrom = hDCAux; } else hDCFrom = hDCMem; ReleaseDC ( hGRXWnd, hDC ); pdst = (unsigned char *)dst->gf_baseaddr[0]; pdst += dx + (dy * dst->gf_lineoffset); lastIndex = 0; lastColor = _GetColor_palette(lastIndex); for ( y = 0; y < h; y++ ) { unsigned char *pbmpdst = pdst; for ( x = 0; x < w; x++ ) { color = GetPixel ( hDCFrom, sx+x, sy+y ); if(color != lastColor) { lastColor = color; lastIndex = _GetColIndex_palette(color); } *pbmpdst++ = (unsigned char)lastIndex; } pdst += dst->gf_lineoffset; } if(dwRop != SRCCOPY) { SelectObject ( hDCAux, oldBitmapAux ); DeleteDC ( hDCAux ); DeleteObject ( hBitmapAux ); } } static void bltr2v_8(GrFrame *dst,int dx,int dy,GrFrame *src,int sx,int sy, int w,int h,GrColor op) { HDC hDC, hDCAux=0, hDCDest; int y, x, offx, offy; long color; DWORD dwRop; HGDIOBJ oldBitmapAux=0; HBITMAP hBitmapAux=0; unsigned char *psrc; int lastIndex; COLORREF lastColor; switch ( op ) { case GrWRITE : case GrIMAGE : dwRop = SRCCOPY; break; case GrXOR : dwRop = SRCINVERT; break; case GrOR : dwRop = SRCPAINT; break; case GrAND : dwRop = SRCAND; //SRCERASE; break; default: dwRop = SRCCOPY; break; } hDC = GetDC ( hGRXWnd ); if(dwRop != SRCCOPY) { hDCAux = CreateCompatibleDC ( hDC ); hBitmapAux = CreateCompatibleBitmap ( hDC, w, h ); oldBitmapAux = SelectObject ( hDCAux, hBitmapAux ); offx = 0; offy = 0; hDCDest = hDCAux; } else { offx = dx; offy = dy; hDCDest = hDCMem; } psrc = (unsigned char *)src->gf_baseaddr[0]; psrc += sx + (sy * src->gf_lineoffset); lastIndex = 0; lastColor = _GetColor_palette(lastIndex); for ( y = 0; y < h; y++ ) { unsigned char *pbmpsrc = psrc; for ( x = 0; x < w; x++ ) { color = *pbmpsrc++; if(color != lastIndex) { lastIndex = color; lastColor = _GetColor_palette(color); } SetPixelV( hDCDest, offx+x, offy+y, lastColor); } psrc += src->gf_lineoffset; } BitBlt ( hDC, dx, dy, w, h, hDCDest, offx, offy, dwRop ); ReleaseDC ( hGRXWnd, hDC ); if(dwRop != SRCCOPY) { BitBlt ( hDCMem, dx, dy, w, h, hDCAux, 0, 0, dwRop ); SelectObject ( hDCAux, oldBitmapAux ); DeleteDC ( hDCAux ); DeleteObject ( hBitmapAux ); } } static void bltr2v_24(GrFrame *dst,int dx,int dy,GrFrame *src,int sx,int sy, int w,int h,GrColor op) { HDC hDC, hDCAux=0, hDCDest; int y, x, offx, offy; GrColor color; GrColor skipc; DWORD dwRop; HGDIOBJ oldBitmapAux=0; HBITMAP hBitmapAux=0; switch ( op ) { case GrWRITE : case GrIMAGE : dwRop = SRCCOPY; break; case GrXOR : dwRop = SRCINVERT; break; case GrOR : dwRop = SRCPAINT; break; case GrAND : dwRop = SRCAND; //SRCERASE; break; default: dwRop = SRCCOPY; break; } skipc = op ^ GrIMAGE; hDC = GetDC ( hGRXWnd ); if(dwRop != SRCCOPY) { hDCAux = CreateCompatibleDC ( hDC ); hBitmapAux = CreateCompatibleBitmap ( hDC, w, h ); oldBitmapAux = SelectObject ( hDCAux, hBitmapAux ); offx = 0; offy = 0; hDCDest = hDCAux; } else { offx = dx; offy = dy; hDCDest = hDCMem; } for ( y = 0; y < h; y++ ) { for ( x = 0; x < w; x++ ) { color = src->gf_driver->readpixel( src, x+sx, y+sy ); if( color != skipc ) SetPixelV( hDCDest, offx+x, offy+y, (COLORREF)color ); } } BitBlt ( hDC, dx, dy, w, h, hDCDest, offx, offy, dwRop ); ReleaseDC ( hGRXWnd, hDC ); if(dwRop != SRCCOPY) { BitBlt ( hDCMem, dx, dy, w, h, hDCAux, 0, 0, dwRop ); SelectObject ( hDCAux, oldBitmapAux ); DeleteDC ( hDCAux ); DeleteObject ( hBitmapAux ); } } static int init_frame(GrVideoMode *md) { if(md->bpp >= 24) { fGetColor = _GetColor_RGB; fGetColIndex = _GetColIndex_RGB; } else { fGetColor = _GetColor_palette; fGetColIndex = _GetColIndex_palette; } return 0; } GrFrameDriver _GrFrameDriverWIN32_4 = { GR_frameWIN32_4, /* frame mode */ GR_frameRAM8, /* compatible RAM frame mode */ TRUE, /* onscreen */ 4, /* line width alignment */ 1, /* number of planes */ 8, /* bits per pixel */ 8 * 16 * 1024L * 1024L, /* max plane size the code can handle */ init_frame, i_readpixel, i_drawpixel, i_drawline, i_drawhline, i_drawvline, i_drawblock, i_drawbitmap, drawpattern, bitblt, bltv2r_8, bltr2v_8, _GrFrDrvGenericGetIndexedScanline, i_putscanline }; GrFrameDriver _GrFrameDriverWIN32_8 = { GR_frameWIN32_8, /* frame mode */ GR_frameRAM8, /* compatible RAM frame mode */ TRUE, /* onscreen */ 4, /* line width alignment */ 1, /* number of planes */ 8, /* bits per pixel */ 8 * 16 * 1024L * 1024L, /* max plane size the code can handle */ init_frame, i_readpixel, i_drawpixel, i_drawline, i_drawhline, i_drawvline, i_drawblock, i_drawbitmap, drawpattern, bitblt, bltv2r_8, bltr2v_8, _GrFrDrvGenericGetIndexedScanline, i_putscanline }; GrFrameDriver _GrFrameDriverWIN32_24 = { GR_frameWIN32_24, /* frame mode */ #ifdef GRX_USE_RAM3x8 GR_frameRAM3x8, #else GR_frameRAM24, /* compatible RAM frame mode */ #endif TRUE, /* onscreen */ 4, /* line width alignment */ 1, /* number of planes */ 24, /* bits per pixel */ 8 * 16 * 1024L * 1024L, /* max plane size the code can handle */ init_frame, i_readpixel, i_drawpixel, i_drawline, i_drawhline, i_drawvline, i_drawblock, i_drawbitmap, drawpattern, bitblt, _GrFrDrvGenericBitBlt, bltr2v_24, _GrFrDrvGenericGetIndexedScanline, i_putscanline };