DIB engine

Ove Kaaven ovehk at ping.uio.no
Fri Sep 27 18:11:57 CDT 2002


Well, here is the DIB engine that a couple of people at TransGaming
(mostly David Hammerton, I think) did some work on a while ago, I finally
got around to review it and make sure it compiles against the current
ReWind (though perhaps it needs a few tweaks to compile against Wine).
It's not all that complete by any means, but we wanted to get it out
there, so feel free to comment on it (or even apply it to Wine if it's
good enough).
-------------- next part --------------
Index: configure.ac
===================================================================
RCS file: /cvsroot/rewind/rewind/configure.ac,v
retrieving revision 1.17
diff -u -r1.17 configure.ac
--- configure.ac	23 Aug 2002 23:23:36 -0000	1.17
+++ configure.ac	27 Sep 2002 17:42:04 -0000
@@ -1382,6 +1382,7 @@
 documentation/Makefile
 files/Makefile
 graphics/Makefile
+graphics/dibeng/Makefile
 graphics/enhmetafiledrv/Makefile
 graphics/metafiledrv/Makefile
 graphics/win16drv/Makefile
Index: dlls/gdi/Makefile.in
===================================================================
RCS file: /cvsroot/rewind/rewind/dlls/gdi/Makefile.in,v
retrieving revision 1.18
diff -u -r1.18 Makefile.in
--- dlls/gdi/Makefile.in	15 Feb 2002 19:12:36 -0000	1.18
+++ dlls/gdi/Makefile.in	27 Sep 2002 17:43:22 -0000
@@ -27,6 +27,7 @@
 GLUE = printdrv.c
 
 EXTRA_OBJS = \
+	$(TOPOBJDIR)/graphics/dibeng/dibeng.o \
 	$(TOPOBJDIR)/graphics/graphics.o \
 	$(TOPOBJDIR)/graphics/enhmetafiledrv/enhmetafiledrv.o \
 	$(TOPOBJDIR)/graphics/metafiledrv/metafiledrv.o \
@@ -35,6 +36,7 @@
 
 SUBDIRS = \
 	$(TOPOBJDIR)/graphics \
+	$(TOPOBJDIR)/graphics/dibeng \
 	$(TOPOBJDIR)/graphics/enhmetafiledrv \
 	$(TOPOBJDIR)/graphics/metafiledrv \
 	$(TOPOBJDIR)/graphics/win16drv \
Index: dlls/gdi/gdi32.spec
===================================================================
RCS file: /cvsroot/rewind/rewind/dlls/gdi/gdi32.spec,v
retrieving revision 1.12
diff -u -r1.12 gdi32.spec
--- dlls/gdi/gdi32.spec	17 Dec 2001 20:58:06 -0000	1.12
+++ dlls/gdi/gdi32.spec	27 Sep 2002 17:43:24 -0000
@@ -7,7 +7,7 @@
 import	kernel32.dll
 import	ntdll.dll
 
-debug_channels (bitblt bitmap clipping dc ddraw driver enhmetafile font gdi
+debug_channels (bitblt bitmap clipping dc dibeng ddraw driver enhmetafile font gdi
                 metafile palette print region text win16drv wing)
 
 # ordinal exports
Index: dlls/x11drv/x11drv_main.c
===================================================================
RCS file: /cvsroot/rewind/rewind/dlls/x11drv/x11drv_main.c,v
retrieving revision 1.48
diff -u -r1.48 x11drv_main.c
--- dlls/x11drv/x11drv_main.c	23 Aug 2002 22:47:28 -0000	1.48
+++ dlls/x11drv/x11drv_main.c	27 Sep 2002 17:45:41 -0000
@@ -55,7 +55,7 @@
 unsigned int screen_height;
 unsigned int screen_depth;
 Window root_window;
-int dxgrab, usedga, usexvidmode;
+int dxgrab, usedga, usexvidmode, usedibeng;
 
 unsigned int X11DRV_server_startticks;
 
@@ -221,6 +221,9 @@
 
     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
         usexvidmode = IS_OPTION_TRUE( buffer[0] );
+
+    if (!get_config_key( hkey, appkey, "UseDIBENG", buffer, sizeof(buffer) ))
+        usedibeng = IS_OPTION_TRUE( buffer[0] );
 
     screen_depth = 0;
     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
Index: graphics/dibeng/.cvsignore
===================================================================
RCS file: graphics/dibeng/.cvsignore
diff -N graphics/dibeng/.cvsignore
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/.cvsignore	27 Sep 2002 17:45:49 -0000
@@ -0,0 +1 @@
+Makefile
Index: graphics/dibeng/Makefile.in
===================================================================
RCS file: graphics/dibeng/Makefile.in
diff -N graphics/dibeng/Makefile.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/Makefile.in	27 Sep 2002 17:45:49 -0000
@@ -0,0 +1,23 @@
+DEFS      = @DLLFLAGS@ -D__WINE__
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = dibeng
+
+C_SRCS = \
+	dibeng_main.c \
+	dibeng_bitmap.c \
+	dibeng_brushes.c \
+	dibeng_pixel.c \
+	dibeng_primitives.c
+
+
+all: $(MODULE).o
+
+ at MAKE_RULES@
+
+$(MODULE).o: $(OBJS) Makefile.in $(TOPSRCDIR)/Make.rules.in
+	$(LDCOMBINE) $(OBJS) -o $@
+
+### Dependencies:
Index: graphics/dibeng/dibeng_bitmap.c
===================================================================
RCS file: graphics/dibeng/dibeng_bitmap.c
diff -N graphics/dibeng/dibeng_bitmap.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/dibeng_bitmap.c	27 Sep 2002 17:45:50 -0000
@@ -0,0 +1,444 @@
+/*
+  Copyright (c) 2002, TransGaming Technologies Inc.
+
+  Bitmap drawing and blitting.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "minmax.h"
+#include "bitmap.h"
+#include "brush.h"
+#include "pen.h"
+#include "gdi.h"
+#include "heap.h"
+#include "debugtools.h"
+
+#include "dibeng_private.h"
+
+
+DEFAULT_DEBUG_CHANNEL( dibeng );
+
+
+/***********************************************************************
+ * Creates a DIBENG DIB from a DC.
+ */
+void DIBENG_GetDIBFromDC( DC *dc, dibeng_t *dibeng )
+{
+  BITMAPOBJ *bmp = GDI_GetObjPtr( dc->hBitmap, BITMAP_MAGIC );
+  DIBSECTION *dib;
+
+  TRACE( "(%p, %p)\n", dc, dibeng );
+
+  if( !bmp )
+  {
+    ERR( "Bad bitmap handle %08x\n", dc->hBitmap );
+    return;
+  }
+
+  dib = bmp->dib;
+  if( !dib )
+  {
+    ERR( "Bitmap handle not a DIB: %08x.\n", dc->hBitmap );
+    return;
+  }
+
+  dibeng->width   = dib->dsBm.bmWidth;
+  dibeng->height  = dib->dsBm.bmHeight;
+  dibeng->bpp     = dib->dsBm.bmBitsPixel;
+  dibeng->linelen = dib->dsBm.bmWidthBytes;
+  dibeng->size    = dibeng->height * dibeng->linelen;
+
+  TRACE( "DIBENG: %dx%dx%d\n", dibeng->width, dibeng->height, dibeng->bpp );
+
+  dibeng->rmask = dib->dsBitfields[0];
+  dibeng->gmask = dib->dsBitfields[1];
+  dibeng->bmask = dib->dsBitfields[2];
+
+  /* Calculate mask shifts. */
+  if(( dibeng->bpp == 15 ) || ( dibeng->bpp == 16 ) || ( dibeng->bpp == 24 ) ||
+    ( dibeng->bpp == 32 ))
+  {
+    DWORD rmask = dibeng->rmask;
+    DWORD gmask = dibeng->gmask;
+    DWORD bmask = dibeng->bmask;
+
+    /* Calculate shifts. */
+    dibeng->rshift = 0;
+    dibeng->gshift = 0;
+    dibeng->bshift = 0;
+
+    while((( rmask >> dibeng->rshift ) & 1 ) == 0 )
+      dibeng->rshift++;
+    while((( gmask >> dibeng->gshift ) & 1 ) == 0 )
+      dibeng->gshift++;
+    while((( bmask >> dibeng->bshift ) & 1 ) == 0 )
+      dibeng->bshift++;
+
+    /* Calculate bits loss. */
+    dibeng->rloss = 8;
+    dibeng->gloss = 8;
+    dibeng->bloss = 8;
+
+    while((( rmask >> ( dibeng->rshift + 8 - dibeng->rloss )) & 1 ) == 1 )
+      dibeng->rloss--;
+    while((( gmask >> ( dibeng->gshift + 8 - dibeng->gloss )) & 1 ) == 1 )
+      dibeng->gloss--;
+    while((( bmask >> ( dibeng->bshift + 8 - dibeng->bloss )) & 1 ) == 1 )
+      dibeng->bloss--;
+  }
+
+
+  dibeng->buffer  = (LPVOID)dib->dsBm.bmBits;
+  dibeng->ROPmode = dc->ROPmode;
+  dibeng->dc      = dc;
+
+  dibeng->dib_pattern = NULL;
+
+  dibeng->text_color = dc->textColor;
+  dibeng->bg_color   = dc->backgroundColor;
+  dibeng->pen_color  = 0;
+  dibeng->use_bg     = ( dc->backgroundMode == OPAQUE );
+
+  GDI_ReleaseObj( dc->hBitmap );
+}
+
+/***********************************************************************
+ * Destroys a DIBENG DIB that was created with DIBENG_GetDIBFromDC.
+ * Does not touch dibeng->buffer.
+ */
+void DIBENG_ReleaseDIBFromDC( dibeng_t *dibeng )
+{
+  TRACE( "(%p)\n", dibeng );
+}
+
+
+/***********************************************************************
+ * Creates a DIBENG DIB from a Windows HBITMAP.
+ */
+void DIBENG_GetDIBFromHBITMAP( DC *dc, HBITMAP hbitmap, dibeng_t *dibeng )
+{
+  BITMAPOBJ *bmp = GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
+  struct {
+    BITMAPINFOHEADER bmih;
+    DWORD mask[3];
+  } info;
+
+  TRACE( "(%08x, %p)\n", hbitmap, dibeng );
+
+  if( !bmp )
+  {
+    ERR( "Bad bitmap handle %08x\n", hbitmap );
+    return;
+  }
+
+  dibeng->width   = bmp->bitmap.bmWidth;
+  dibeng->height  = bmp->bitmap.bmHeight;
+  dibeng->bpp     = bmp->bitmap.bmBitsPixel;
+  dibeng->linelen = bmp->bitmap.bmWidthBytes;
+  dibeng->size    = dibeng->height * dibeng->linelen;
+
+  TRACE( "DIBENG: %dx%dx%d\n", dibeng->width, dibeng->height, dibeng->bpp );
+
+  /* FIXME: One way to find the masks is to pass in a compatible DC, but it's
+   * not a nice way to do it. The best way would be to make x11drv save the
+   * masks for bitmaps (or if it does already, where are they stored?). */
+  FIXME( "Find masks for this bitmap.\n" );
+/*
+  dibeng->rmask = ;
+  dibeng->gmask = ;
+  dibeng->bmask = ;
+*/
+
+  /* Calculate mask shifts. */
+  if(( dibeng->bpp == 15 ) || ( dibeng->bpp == 16 ) || ( dibeng->bpp == 24 ) ||
+    ( dibeng->bpp == 32 ))
+  {
+    DWORD rmask = dibeng->rmask;
+    DWORD gmask = dibeng->gmask;
+    DWORD bmask = dibeng->bmask;
+
+    /* Calculate shifts. */
+    dibeng->rshift = 0;
+    dibeng->gshift = 0;
+    dibeng->bshift = 0;
+
+    while((( rmask >> dibeng->rshift ) & 1 ) == 0 )
+      dibeng->rshift++;
+    while((( gmask >> dibeng->gshift ) & 1 ) == 0 )
+      dibeng->gshift++;
+    while((( bmask >> dibeng->bshift ) & 1 ) == 0 )
+      dibeng->bshift++;
+
+    /* Calculate bits loss. */
+    dibeng->rloss = 8;
+    dibeng->gloss = 8;
+    dibeng->bloss = 8;
+
+    while((( rmask >> ( dibeng->rshift + 8 - dibeng->rloss )) & 1 ) == 1 )
+      dibeng->rloss--;
+    while((( gmask >> ( dibeng->gshift + 8 - dibeng->gloss )) & 1 ) == 1 )
+      dibeng->gloss--;
+    while((( bmask >> ( dibeng->bshift + 8 - dibeng->bloss )) & 1 ) == 1 )
+      dibeng->bloss--;
+  }
+
+  memset(&info, 0, sizeof(info));
+  info.bmih.biSize = sizeof(info.bmih);
+  info.bmih.biWidth = dibeng->width;
+  info.bmih.biHeight = -dibeng->height;
+  info.bmih.biPlanes = 1;
+  info.bmih.biBitCount = dibeng->bpp;
+  info.bmih.biSizeImage = dibeng->size;
+  if ( dibeng->bpp > 8 )
+  {
+    info.bmih.biCompression = BI_BITFIELDS;
+    info.mask[0] = dibeng->rmask;
+    info.mask[1] = dibeng->gmask;
+    info.mask[2] = dibeng->bmask;
+  }
+
+  /* Note: This assumes read-only. If we need to write, do something like
+   * calling SetBitmapBits in DIBENG_ReleaseDIBFromHBITMAP. */
+  dibeng->buffer  = (LPVOID)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dibeng->size );
+  GetDIBits( dc ? dc->hSelf : 0, hbitmap, 0, dibeng->height, dibeng->buffer, (LPVOID)&info, DIB_RGB_COLORS);
+
+  /* Doesn't matter, since a bitmap won't ever use those variables. */
+  dibeng->ROPmode = 0;
+  dibeng->dc      = NULL;
+
+  dibeng->dib_pattern = NULL;
+
+  dibeng->text_color = 0;
+  dibeng->bg_color   = 0;
+  dibeng->pen_color  = 0;
+  dibeng->use_bg     = 1;
+
+  GDI_ReleaseObj( hbitmap );
+}
+
+/***********************************************************************
+ * Destroys a DIBENG DIB that was created with DIBENG_GetDIBFromHBITMAP.
+ */
+void DIBENG_ReleaseDIBFromHBITMAP( dibeng_t *dibeng )
+{
+  TRACE( "(%p)\n", dibeng );
+
+  HeapFree( GetProcessHeap(), 0, dibeng->buffer );
+}
+
+
+/***********************************************************************
+ * Creates a DIBENG DIB and an associated chunk of memory of width w
+ * and height h, using the properties from dibeng_in.
+ */
+void DIBENG_CreateDIB( dibeng_t *dibeng_in, INT w, INT h, dibeng_t *dibeng_out )
+{
+  TRACE( "(%p, %d, %d, %p)\n", dibeng_in, w, h, dibeng_out );
+
+  dibeng_out->width   = w;
+  dibeng_out->height  = h;
+  dibeng_out->bpp     = dibeng_in->bpp;
+  dibeng_out->linelen = DIB_GetDIBWidthBytes( dibeng_out->width, dibeng_out->bpp );
+  dibeng_out->size    = dibeng_out->height * dibeng_out->linelen;
+
+  dibeng_out->rmask = dibeng_in->rmask;
+  dibeng_out->gmask = dibeng_in->gmask;
+  dibeng_out->bmask = dibeng_in->bmask;
+
+  dibeng_out->rshift = dibeng_in->rshift;
+  dibeng_out->gshift = dibeng_in->gshift;
+  dibeng_out->bshift = dibeng_in->bshift;
+
+  dibeng_out->rloss = dibeng_in->rloss;
+  dibeng_out->gloss = dibeng_in->gloss;
+  dibeng_out->bloss = dibeng_in->bloss;
+
+  dibeng_out->buffer  = (LPVOID)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dibeng_out->size );
+  dibeng_out->ROPmode = dibeng_in->ROPmode;
+  dibeng_out->dc      = dibeng_in->dc;
+
+  dibeng_out->dib_pattern = NULL;
+
+  dibeng_out->text_color = dibeng_in->text_color;
+  dibeng_out->bg_color   = dibeng_in->bg_color;
+  dibeng_out->pen_color  = 0;
+  dibeng_out->use_bg     = dibeng_in->use_bg;
+}
+
+/***********************************************************************
+ * Destroys a DIBENG DIB that was created with DIBENG_CreateDIB.
+ */
+void DIBENG_DestroyDIB( dibeng_t *dibeng )
+{
+  TRACE( "(%p)", dibeng );
+
+  HeapFree( GetProcessHeap(), 0, dibeng->buffer );
+}
+
+
+/***********************************************************************
+ * Draws a 1-bit bitmap into a (1-bit) DIB.
+ */
+void DIBENG_DrawBitmap1( dibeng_t *dib, INT x, INT y, dibeng_t *bm )
+{
+  FIXME( "(%p, %d, %d, %p): stub\n", dib, x, y, bm );
+}
+
+/***********************************************************************
+ * Draws a 4-bit bitmap into a (4-bit) DIB.
+ */
+void DIBENG_DrawBitmap4( dibeng_t *dib, INT x, INT y, dibeng_t *bm )
+{
+  FIXME( "(%p, %d, %d, %p): stub\n", dib, x, y, bm );
+}
+
+/***********************************************************************
+ * Draws a 8-bit bitmap into a (8-bit) DIB.
+ */
+void DIBENG_DrawBitmap8( dibeng_t *dib, INT x, INT y, dibeng_t *bm )
+{
+  FIXME( "(%p, %d, %d, %p): stub\n", dib, x, y, bm );
+}
+
+/***********************************************************************
+ * Draws a 16-bit bitmap into a (16-bit) DIB.
+ */
+void DIBENG_DrawBitmap16( dibeng_t *dib, INT x, INT y, dibeng_t *bm )
+{
+  INT x_start = max( x, 0 );
+  INT y_start = max( y, 0 );
+  INT x_end   = min( x + bm->width, dib->width );
+  INT y_end   = min( y + bm->height, dib->height );
+  USHORT *bits = bm->buffer;
+  INT i, j;
+
+  FIXME( "(%p, %d, %d, %p): partial stub\n", dib, x, y, bm );
+
+  /* FIXME: There should be a way to know what the color depth of the DIB
+   * was before the driver overwrote it (when calling GetDeviceCaps in
+   * CreateDIBitmap). We need this if we want Windows consistency.
+   */
+  /* Manually Convert from whatever the color depth of the pattern is to
+   * the DIB's depth. */
+  if( bm->bpp == 16 )
+  {
+    for( j = y_start; j < y_end; j++ )
+    {
+      for( i = x_start; i < x_end; i++ )
+      {
+        USHORT pixel;
+        COLORREF color;
+        pixel = bits[( i % bm->width ) + ( j % bm->height ) * bm->width];
+        color = DIBENG_Pixel2RGB( dib, pixel );
+
+        DIBENG_DrawRGB( dib, i, j, color );
+      }
+    }
+  }
+  else
+  {
+    FIXME( "This hack doesn't support %d bpp bitmap.\n", bm->bpp );
+    return;
+  }
+}
+
+/***********************************************************************
+ * Draws a 24-bit bitmap into a (24-bit) DIB.
+ */
+void DIBENG_DrawBitmap24( dibeng_t *dib, INT x, INT y, dibeng_t *bm )
+{
+  FIXME( "(%p, %d, %d, %p): stub\n", dib, x, y, bm );
+}
+
+/***********************************************************************
+ * Draws a 32-bit bitmap into a (32-bit) DIB.
+ */
+void DIBENG_DrawBitmap32( dibeng_t *dib, INT x, INT y, dibeng_t *bm )
+{
+  FIXME( "(%p, %d, %d, %p): stub\n", dib, x, y, bm );
+}
+
+
+/***********************************************************************
+ * Draws a bitmap into a DIB, handling bpp-checking (and possibly conversion).
+ */
+void DIBENG_DrawBitmap( dibeng_t *dib, INT x, INT y, dibeng_t *bm )
+{
+  switch( dib->bpp )
+  {
+    case 32:
+      DIBENG_DrawBitmap32( dib, x, y, bm );
+      break;
+    case 24:
+      DIBENG_DrawBitmap24( dib, x, y, bm );
+      break;
+    case 16:
+      DIBENG_DrawBitmap16( dib, x, y, bm );
+      break;
+    case 8:
+      DIBENG_DrawBitmap8( dib, x, y, bm );
+      break;
+    case 4:
+      DIBENG_DrawBitmap4( dib, x, y, bm );
+      break;
+    case 1:
+      DIBENG_DrawBitmap1( dib, x, y, bm );
+      break;
+  }
+}
+
+/***********************************************************************
+ * Draws a 1-bit bitmap into a DIB, 1 being the pen color, and 0 being
+ * the background color (or transparent).
+ */
+void DIBENG_Draw1BitBitmap( dibeng_t *dib, INT x, INT y, INT width, INT height, const USHORT *bm )
+{
+  INT x_start = max( x, 0 );
+  INT y_start = max( y, 0 );
+  INT x_end   = min( x + width, dib->width );
+  INT y_end   = min( y + height, dib->height );
+  USHORT bits = 0;
+  USHORT draw_pixel;
+  USHORT num_bits;
+  INT i, j;
+  DWORD old_ROPmode = dib->ROPmode;
+
+  dib->ROPmode = SRCAND;
+
+  TRACE( "(%p, %d, %d, %d, %d, %p)\n", dib, x, y, width, height, bm );
+
+  for( j = y_start; j < y_end; j++ )
+  {
+    num_bits = 0;
+
+    for( i = x_start; i < x_end; i++ )
+    {
+      if(( num_bits ) == 0 || ( i - x_start == width ))
+      {
+        bits = *bm;
+        bm++;
+        num_bits = width;
+      }
+
+      /* Get the left-most bit. */
+      draw_pixel = ( bits >> ( 8 * sizeof( USHORT ) - num_bits )) & 1;
+      num_bits--;
+
+      if( draw_pixel )
+      {
+        DIBENG_DrawRGB( dib, i, j, dib->pen_color );
+      }
+      else if( dib->use_bg )
+      {
+        DIBENG_DrawRGB( dib, i, j, dib->bg_color );
+      }
+    }
+  }
+
+  dib->ROPmode = old_ROPmode;
+}
+
Index: graphics/dibeng/dibeng_brushes.c
===================================================================
RCS file: graphics/dibeng/dibeng_brushes.c
diff -N graphics/dibeng/dibeng_brushes.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/dibeng_brushes.c	27 Sep 2002 17:45:50 -0000
@@ -0,0 +1,37 @@
+/*
+  Copyright (c) 2002, TransGaming Technologies Inc.
+
+  Brushes.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "minmax.h"
+#include "bitmap.h"
+#include "brush.h"
+#include "pen.h"
+#include "gdi.h"
+#include "heap.h"
+#include "debugtools.h"
+
+#include "dibeng_private.h"
+
+
+DEFAULT_DEBUG_CHANNEL( dibeng );
+
+
+
+/* Used to create pre-defined brush hatches. Must be word aligned. */
+const USHORT ptrn_bdiagonal[]  = { 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 };
+const USHORT ptrn_cross[]      = { 0x0800, 0x0800, 0x0800, 0xff00, 0x0800, 0x0800, 0x0800, 0x0800 };
+const USHORT ptrn_fdiagonal[]  = { 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100 };
+const USHORT ptrn_diagcross[]  = { 0x8100, 0x4200, 0x2400, 0x1800, 0x1800, 0x2400, 0x4200, 0x8100 };
+const USHORT ptrn_horizontal[] = { 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0x0000, 0x0000, 0x0000 };
+const USHORT ptrn_vertical[]   = { 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800 };
+
+
+
+
Index: graphics/dibeng/dibeng_main.c
===================================================================
RCS file: graphics/dibeng/dibeng_main.c
diff -N graphics/dibeng/dibeng_main.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/dibeng_main.c	27 Sep 2002 17:45:50 -0000
@@ -0,0 +1,653 @@
+/*
+  Copyright (c) 2002, TransGaming Technologies Inc.
+
+  DIB Initialization stuff, and GDI wrappers.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "minmax.h"
+#include "bitmap.h"
+#include "brush.h"
+#include "pen.h"
+#include "gdi.h"
+#include "heap.h"
+#include "debugtools.h"
+
+#include "dibeng_private.h"
+
+
+DEFAULT_DEBUG_CHANNEL( dibeng );
+
+
+
+/* Declared in dibeng_brushes.c */
+extern const USHORT ptrn_bdiagonal[];
+extern const USHORT ptrn_cross[];
+extern const USHORT ptrn_fdiagonal[];
+extern const USHORT ptrn_diagcross[];
+extern const USHORT ptrn_horizontal[];
+extern const USHORT ptrn_vertical[];
+
+
+
+
+/* FIXME: Create real GDI wrappers, that create a DIB and call a DIB function
+ * of the same name, so that we don't create multiple copies of the same DIB
+ * (ie. DIBENG_PolyPolygon calling DIBENG_Polygon multiple times).
+ */
+
+
+
+/***********************************************************************
+ * DIBENG_LineTo
+ *
+ */
+BOOL DIBENG_LineTo( DC *dc, INT x, INT y )
+{
+  dibeng_t dib;
+  PENOBJ *pen_ptr;
+  TRACE( "(%p, %d, %d)\n", dc, x, y );
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dc, &dib );
+
+  /* Get pen. */
+  pen_ptr = (PENOBJ *)GDI_GetObjPtr( dc->hPen, PEN_MAGIC );
+  dib.pen_color = pen_ptr->logpen.lopnColor;
+
+  DIBENG_Line( &dib, dc->CursPosX, dc->CursPosY, x, y, FALSE );
+
+  /* Release pen. */
+  GDI_ReleaseObj( dc->hPen );
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib );
+
+  /* Update current position. */
+  dc->CursPosX = x;
+  dc->CursPosY = y;
+
+  return TRUE;
+}
+
+/***********************************************************************
+ * DIBENG_Ellipse
+ *
+ */
+BOOL DIBENG_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
+{
+  FIXME( "(%p, %d, %d, %d, %d): semi-working\n",
+    dc, left, top, right, bottom );
+
+#if 0
+  dibeng_t dib;
+  INT temp;
+  INT x, y;	/* Position of ellipse. */
+  INT rx, ry;	/* Radius of ellipse. */
+  PENOBJ *pen_ptr;
+  BRUSHOBJ *brush_ptr;
+
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dc, &dib );
+
+  /* Get pen and brush. */
+  /* FIXME: Doesn't handle pen and brush modes.. it assumes it's a solid pen. */
+  pen_ptr = (PENOBJ *)GDI_GetObjPtr( dc->hPen, PEN_MAGIC );
+  /* FIXME: Doesn't handle brush modes... */
+  brush_ptr = (BRUSHOBJ *)GDI_GetObjPtr( dc->hBrush, BRUSH_MAGIC );
+
+
+  /* Swap left and right if needed. */
+  if( left > right )
+  {
+    temp = left;
+    left = right;
+    right = temp;
+  }
+  /* Swap top and bottom if needed. */
+  if( top > bottom )
+  {
+    temp = top;
+    top = bottom;
+    bottom = temp;
+  }
+
+  x = ( right + left ) / 2;
+  y = ( bottom + top ) / 2;
+  rx = x - left;
+  ry = y - top;
+
+  /* Set fill color. */
+  dib.pen_color = brush_ptr->logbrush.lbColor;
+
+  /* Draw filled ellipse. */
+  DIBENG_Ellipse( dib, x, y, rx, ry, TRUE );
+
+  /* FIXME: Need optimization so that it doesn't overlap the filled ellipse. */
+
+  /* Set outline color. */
+  dib.pen_color = pen_ptr->logpen.lopnColor;
+
+  /* Draw outline ellipse. */
+  DIBENG_Ellipse( dib, x, y, rx, ry, FALSE );
+
+  /* Release pen and brush. */
+  GDI_ReleaseObj( dc->hPen );
+  GDI_ReleaseObj( dc->hBrush );
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib );
+
+#endif
+  return TRUE;
+}
+
+/***********************************************************************
+ * DIBENG_GetPixel
+ *
+ */
+COLORREF DIBENG_GetPixel( DC *dc, INT x, INT y )
+{
+  dibeng_t dib;
+  COLORREF read_color;
+
+  TRACE( "(%p, %d, %d): stub\n", dc, x, y );
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dc, &dib );
+
+  /* Read RGB color value. */
+  read_color = DIBENG_ReadRGB( &dib, x, y );
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib );
+
+  return read_color;
+}
+
+/***********************************************************************
+ * DIBENG_Polygon
+ *
+ */
+BOOL DIBENG_Polygon( DC *dc, const POINT *pt, INT count )
+{
+  INT i;
+  dibeng_t dib;
+  PENOBJ *pen_ptr;
+  BRUSHOBJ *brush_ptr;
+  LOGBRUSH brush;
+  LOGPEN pen;
+
+  TRACE( "(%p, %p, %d)\n", dc, pt, count );
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dc, &dib );
+
+  /* Get pen and brush. */
+  pen_ptr = (PENOBJ *)GDI_GetObjPtr( dc->hPen, PEN_MAGIC );
+  pen = pen_ptr->logpen;
+  brush_ptr = (BRUSHOBJ *)GDI_GetObjPtr( dc->hBrush, BRUSH_MAGIC );
+  brush = brush_ptr->logbrush;
+
+  /* Draw polygon according to brush style. */
+  if( brush.lbStyle == BS_HOLLOW || brush.lbStyle == BS_NULL )
+  {
+    /* Nothing to do. */
+  }
+  else if( brush.lbStyle == BS_SOLID )
+  {
+    /* Fill polygon. */
+    dib.pen_color = brush.lbColor;
+    DIBENG_FillPolygon( &dib, pt, count );
+  }
+  else if( brush.lbStyle == BS_PATTERN || brush.lbStyle == BS_PATTERN8X8 )
+  {
+    INT i;
+    INT width, height;   /* w,h of polygon. */
+    INT bmx, bmy;        /* Bitmap x,y delta (eg. width + bmx == factor of 8). */
+    dibeng_t dib_temp;  /* Temp bitmap. */
+    dibeng_t dib_pat;   /* Pattern bitmap. */
+    POINT *temp_points = NULL;
+    HBITMAP hbm = (HBITMAP)brush.lbHatch;
+    INT minx, maxx;
+    INT miny, maxy;
+    WORD old_bg_use;
+
+    /* Hack. Must find a way to get the proper masks and shifts. */
+    FIXME( "Find masks for this bitmap (hack for now).\n" );
+    dib_pat.rmask = dib.rmask;
+    dib_pat.gmask = dib.gmask;
+    dib_pat.bmask = dib.bmask;
+    dib_pat.rshift = dib.rshift;
+    dib_pat.gshift = dib.gshift;
+    dib_pat.bshift = dib.bshift;
+    /* Get the brush's pattern. */
+    DIBENG_GetDIBFromHBITMAP( dc, hbm, &dib_pat );
+
+    temp_points = (POINT *)HeapAlloc( GetProcessHeap(), 0, count * sizeof( POINT ));
+    if( !temp_points )
+    {
+      ERR( "Not enough memory to create points.\n" );
+    }
+
+    minx = miny = MAXLONG;
+    maxx = maxy = -1;
+
+    for( i = 0; i < count; i++ )
+    {
+      /* Copy points. */
+      temp_points[i].x = pt[i].x;
+      temp_points[i].y = pt[i].y;
+
+      /* Get min/max values. */
+      minx = min( minx, temp_points[i].x );
+      maxx = max( maxx, temp_points[i].x );
+      miny = min( miny, temp_points[i].y );
+      maxy = max( maxy, temp_points[i].y );
+    }
+
+    /* Calculate bitmap x,y delta to align with pattern. */
+    bmx = ( minx % dib_pat.width );
+    bmy = ( miny % dib_pat.height );
+
+    /* Align min/max to pattern. */
+    minx = minx - bmx;
+    miny = miny - bmy;
+
+    /* Calculate polygon w,h taking the pattern delta into account. */
+    width  = maxx - minx + 1;
+    height = maxy - miny + 1;
+
+    for( i = 0; i < count; i++ )
+    {
+      /* Re-set polygon origin. */
+      temp_points[i].x -= minx;
+      temp_points[i].y -= miny;
+    }
+
+    /* Create temp bitmap. */
+    DIBENG_CreateDIB( &dib, width, height, &dib_temp );
+
+    /* Render polygon into temp bitmap in black and white. */
+    dib_temp.ROPmode = R2_COPYPEN;
+    dib_temp.pen_color = RGB( 255, 255, 255 );
+    dib_temp.bg_color = RGB( 0, 0, 0 );
+    dib_temp.use_bg = TRUE;
+    DIBENG_FillPolygon( &dib_temp, temp_points, count );
+
+    /* Render pattern in temp bitmap using AND mode. */
+    dib_temp.ROPmode = 0x00A000C9;
+    dib_temp.dib_pattern = &dib_pat;
+    DIBENG_FillRect( &dib_temp, 0, 0, dib_temp.width, dib_temp.height );
+    dib_temp.dib_pattern = NULL;
+
+    /* Render polygon transparently into screen device in background color. */
+    old_bg_use = dib.use_bg;
+
+    dib.use_bg = FALSE;
+    dib.pen_color = dc->backgroundColor;
+    dib.ROPmode = R2_COPYPEN;
+
+    DIBENG_FillPolygon( &dib, pt, count );
+
+    /* Render bitmap transparently into screen device. */
+    DIBENG_Blit( &dib, minx, miny, width, height, &dib_temp, 0, 0, SRCCOPY );
+
+    dib.use_bg = old_bg_use;
+
+
+    /* Delete temp bitmap and pattern bitmap. */
+    DIBENG_DestroyDIB( &dib_temp );
+    DIBENG_ReleaseDIBFromHBITMAP( &dib_pat );
+    /* Free points. */
+    HeapFree( GetProcessHeap(), 0, temp_points );
+  }
+  else if( brush.lbStyle == BS_DIBPATTERN || brush.lbStyle == BS_DIBPATTERN8X8 )
+  {
+    FIXME( "BS_DIBPATTERN and BS_DIBPATTERN8X8 brush styles not implemented.\n" );
+  }
+  else if( brush.lbStyle == BS_HATCHED )
+  {
+    INT i, x, y;
+    INT width, height;   /* w,h of polygon. */
+    INT bmx, bmy;        /* Bitmap x,y delta (eg. width + bmx == factor of 8). */
+    dibeng_t dib_temp;  /* Temp bitmap. */
+    POINT *temp_points = NULL;
+    const USHORT *pattern = NULL;   /* Pre-defined pattern to use. */
+    INT minx, maxx;
+    INT miny, maxy;
+    COLORREF old_color;
+    WORD old_bg_use;
+
+
+    /* Set pattern according to hatch style. */
+    if( brush.lbHatch == HS_BDIAGONAL )
+    {
+      pattern = ptrn_bdiagonal;
+    }
+    else if( brush.lbHatch == HS_CROSS )
+    {
+      pattern = ptrn_cross;
+    }
+    else if( brush.lbHatch == HS_DIAGCROSS )
+    {
+      pattern = ptrn_diagcross;
+    }
+    else if( brush.lbHatch == HS_FDIAGONAL )
+    {
+      pattern = ptrn_fdiagonal;
+    }
+    else if( brush.lbHatch == HS_HORIZONTAL )
+    {
+      pattern = ptrn_horizontal;
+    }
+    else if( brush.lbHatch == HS_VERTICAL )
+    {
+      pattern = ptrn_vertical;
+    }
+    else
+    {
+      ERR( "Unknown hatch style (%d).\n", brush.lbHatch );
+    }
+
+
+    /* If pattern is not NULL, then we draw the hatched pattern. */
+    if( pattern )
+    {
+      temp_points = (POINT *)HeapAlloc( GetProcessHeap(), 0, count * sizeof( POINT ));
+      if( !temp_points )
+      {
+        ERR( "Not enough memory to create points.\n" );
+      }
+
+      minx = miny = MAXLONG;
+      maxx = maxy = -1;
+
+      for( i = 0; i < count; i++ )
+      {
+        /* Copy points. */
+        temp_points[i].x = pt[i].x;
+        temp_points[i].y = pt[i].y;
+
+        /* Get min/max values. */
+        minx = min( minx, temp_points[i].x );
+        maxx = max( maxx, temp_points[i].x );
+        miny = min( miny, temp_points[i].y );
+        maxy = max( maxy, temp_points[i].y );
+      }
+
+      /* Calculate bitmap x,y delta to align with pattern (pre-defined pattern is 8x8). */
+      bmx = ( minx & 7 );
+      bmy = ( miny & 7 );
+
+      /* Align min/max to pattern. */
+      minx = minx - bmx;
+      miny = miny - bmy;
+
+      /* Calculate polygon w,h taking the pattern delta into account. */
+      width = maxx - minx + 1;
+      height = maxy - miny + 1;
+
+      /* Re-set polygon origin. */
+      for( i = 0; i < count; i++ )
+      {
+        temp_points[i].x -= minx;
+        temp_points[i].y -= miny;
+      }
+
+      /* Create temp bitmap. */
+      DIBENG_CreateDIB( &dib, width, height, &dib_temp );
+
+      /* Render polygon into bitmap using black and white. */
+      dib_temp.ROPmode   = R2_COPYPEN;
+      dib_temp.pen_color = RGB( 255, 255, 255 );
+      dib_temp.bg_color  = RGB( 0, 0, 0 );
+      dib_temp.use_bg    = TRUE;
+      DIBENG_FillPolygon( &dib_temp, temp_points, count );
+
+      /* Render pattern in temp bitmap using AND mode. */
+      dib_temp.pen_color = brush.lbColor;
+
+/* FIXME: Use a special PatBlt() to draw 1-bit bitmaps, or make
+ * DIBENG_Draw1BitBitmap more generic.
+ */
+      for( y = 0; y < height; y += 8 )
+      {
+        for( x = 0; x < width; x += 8 )
+        {
+          DIBENG_Draw1BitBitmap( &dib_temp, x, y, 8, 8, pattern );
+        }
+      }
+
+      /* Render polygon transparently into screen device in background color. */
+      old_bg_use = dib.use_bg;
+      old_color = brush.lbColor;
+
+      dib.use_bg = FALSE;
+      dib.pen_color = dc->backgroundColor;
+      dib.ROPmode = R2_COPYPEN;
+
+      DIBENG_FillPolygon( &dib, pt, count );
+
+      brush.lbColor = old_color;
+
+      /* Render bitmap transparently into screen device. */
+      DIBENG_Blit( &dib, minx, miny, width, height, &dib_temp, 0, 0, SRCCOPY );
+
+      dib.use_bg = old_bg_use;
+
+
+      /* Delete temp bitmap. */
+      DIBENG_DestroyDIB( &dib_temp );
+      /* Free points. */
+      HeapFree( GetProcessHeap(), 0, temp_points );
+    }
+  }
+  else
+  {
+    ERR( "Unknown brush style.\n" );
+  }
+
+  /* Draw outline. */
+  dib.pen_color = pen.lopnColor;
+  for( i = 0; i < ( count - 1 ); i++ )
+    DIBENG_Line( &dib, pt[i].x, pt[i].y, pt[i + 1].x, pt[i + 1].y, FALSE );
+  DIBENG_Line( &dib, pt[i].x, pt[i].y, pt[0].x, pt[0].y, FALSE );
+
+  /* Release pen and brush. */
+  GDI_ReleaseObj( dc->hPen );
+  GDI_ReleaseObj( dc->hBrush );
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib );
+
+  return TRUE;
+}
+
+/***********************************************************************
+ * DIBENG_Polyline
+ *
+ */
+BOOL DIBENG_Polyline( DC *dc, const POINT *pt, INT count )
+{
+  dibeng_t dib;
+  INT i;
+  PENOBJ *pen_ptr;
+
+  FIXME( "(%p, %p, %d): semi-working\n", dc, pt, count );
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dc, &dib );
+
+  /* Get pen color. */
+  /* FIXME: Use brush if If pen is a geometric pen, like in LineTo? */
+  /* FIXME: Doesn't handle pen modes.. it assumes a solid pen of width 1. */
+  pen_ptr = (PENOBJ *)GDI_GetObjPtr( dc->hPen, PEN_MAGIC );
+
+  /* Set foreground color. */
+  dib.pen_color = pen_ptr->logpen.lopnColor;
+
+  for( i = 0; i < ( count - 1 ); i++ )
+    DIBENG_Line( &dib, pt[i].x, pt[i].y, pt[i + 1].x, pt[i + 1].y, FALSE );
+
+  /* Release pen. */
+  GDI_ReleaseObj( dc->hPen );
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib );
+
+  return TRUE;
+}
+
+/***********************************************************************
+ * DIBENG_PolyPolygon
+ *
+ */
+BOOL DIBENG_PolyPolygon( DC *dc, const POINT *pt, const INT *counts, UINT polygons )
+{
+  FIXME( "(%p, %p, %p, %u): semi-working (stubbed out)\n", dc, pt, counts, polygons );
+
+#if 0
+  INT i;
+  INT pts_count = 0;
+
+  for( i = 0; i < polygons; i++ )
+  {
+    DIBENG_Polygon( dc, &pt[pts_count], counts[i] );
+    pts_count += counts[i];
+  }
+#endif
+
+  return TRUE;
+}
+
+/***********************************************************************
+ * DIBENG_PolyPolyline
+ *
+ */
+BOOL DIBENG_PolyPolyline( DC *dc, const POINT *pt, const DWORD *counts, DWORD polylines )
+{
+  INT i;
+  INT pts_count = 0;
+
+  TRACE( "(%p, %p, %p, %lu)\n", dc, pt, counts, polylines );
+
+  for( i = 0; i < polylines; i++ )
+  {
+    DIBENG_Polyline( dc, &pt[pts_count], counts[i] );
+    pts_count += counts[i];
+  }
+
+  return TRUE;
+}
+
+/***********************************************************************
+ * DIBENG_SetPixel
+ *
+ */
+COLORREF DIBENG_SetPixel( DC *dc, INT x, INT y, COLORREF color )
+{
+  dibeng_t dib;
+  COLORREF old_color;
+
+  FIXME("(%p, %d, %d, 0x%08lx): not tested\n", dc, x, y, color);
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dc, &dib );
+
+  /* Read and convert pixel from buffer. */
+  old_color = DIBENG_ReadRGB( &dib, x, y );
+
+  /* Set new color in buffer. */
+  DIBENG_DrawRGB( &dib, x, y, color );
+
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib );
+
+  return old_color;
+}
+
+/***********************************************************************
+ * DIBENG_BitBlt
+ *
+ */
+BOOL DIBENG_BitBlt( DC *dcDst, INT xDst, INT yDst, INT width, INT height,
+  DC *dcSrc, INT xSrc, INT ySrc, DWORD rop )
+{
+  FIXME( "(0x%p, %d, %d, %d, %d, 0x%p, %d, %d, %ld) stub\n", dcDst, xDst, yDst,
+    width, height, dcSrc, xSrc, ySrc, rop );
+
+/* This doesnt work properly yet, hence lets not use it.
+ */
+#if 0
+  dibeng_t dib_dst, dib_src;
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dcDst, &dib_dst );
+  DIBENG_GetDIBFromDC( dcSrc, &dib_src );
+
+  if( rop == SRCCOPY
+    || rop == SRCPAINT /* hack */ )
+  {
+    FIXME( "(%p, %d, %d, %d, %d, %p, %d, %d, %06ux): incomplete\n",
+      dcDst, xDst, yDst, width, height,
+      dcSrc, xSrc, ySrc, rop
+      );
+
+    DIBENG_BitBlit( dib_dst, xDst, yDst, width, height, dib_src, xSrc, ySrc, rop );
+
+    return TRUE;
+  }
+  else
+  {
+    FIXME("(%p, %d, %d, %d, %d, %p, %d, %d, %06ux): stub (!SRCCOPY && !SRCPAINT)\n",
+      dcDst, xDst, yDst, width, height,
+      dcSrc, xSrc, ySrc, rop
+    );
+  }
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib_src );
+  DIBENG_ReleaseDIBFromDC( &dib_dst );
+#endif
+  return TRUE;
+}
+
+/***********************************************************************
+ * DIBENG_PatBlt
+ *
+*/
+BOOL DIBENG_PatBlt( DC *dc, INT left, INT top, INT width, INT height, DWORD rop )
+{
+  dibeng_t dib;
+  BRUSHOBJ *brush_ptr;
+
+  TRACE( "(%p, %d, %d, %d, %d, %06lx)\n",
+    dc, left, top, width, height, rop );
+
+  /* Set up DIB engine. */
+  DIBENG_GetDIBFromDC( dc, &dib );
+
+  /* Get pen. */
+  brush_ptr = (BRUSHOBJ *)GDI_GetObjPtr( dc->hBrush, BRUSH_MAGIC );
+
+  dib.pen_color = brush_ptr->logbrush.lbColor;
+  dib.ROPmode = rop;
+
+  DIBENG_FillRect( &dib, left, top, width, height );
+
+  /* Release brush. */
+  GDI_ReleaseObj( dc->hBrush );
+
+  /* Shut down DIB engine. */
+  DIBENG_ReleaseDIBFromDC( &dib );
+
+  return TRUE;
+}
+
Index: graphics/dibeng/dibeng_pixel.c
===================================================================
RCS file: graphics/dibeng/dibeng_pixel.c
diff -N graphics/dibeng/dibeng_pixel.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/dibeng_pixel.c	27 Sep 2002 17:45:50 -0000
@@ -0,0 +1,677 @@
+/*
+  Copyright (c) 2002, TransGaming Technologies Inc.
+
+  Specialized RGB pixel drawing functions for the different Raster OPeration
+  (ROP) modes.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "gdi.h"
+#include "debugtools.h"
+
+#include "dibeng_private.h"
+
+/* Maximum ROP length for Reverse Polish strings. */
+#define MAX_ROP_LEN    12
+
+/* Define if you want extra info when calling DIBENG_DrawRGB_ROP3(). */
+/*#define ROP3_DEBUG     1*/
+
+
+DEFAULT_DEBUG_CHANNEL( dibeng );
+
+
+/* Look in MSDN:
+ * /Platform SDK/Graphics and Multimedia Services/GDI/Raster Operation Codes/Ternary Raster Operations/
+ * or online: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_6n77.asp
+ * for the full list of ROP2 and ROP3 modes.
+ */
+
+
+/* ROP2 modes are implemented as function pointers, as there are only 16 of them.
+ * ROP3 modes are implemented as a parser (256 functions is too much, IMHO).
+ */
+
+
+
+/* ROP2 functions. */
+COLORREF DIBENG_DrawRGB_ROP2_BLACK( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_NOTMERGEPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_MASKNOTPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_NOTCOPYPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_MASKPENNOT( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_NOT( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_XORPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_NOTMASKPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_MASKPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_NOTXORPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_NOP( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_MERGENOTPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_COPYPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_MERGEPENNOT( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_MERGEPEN( COLORREF dst, COLORREF pen );
+COLORREF DIBENG_DrawRGB_ROP2_WHITE( COLORREF dst, COLORREF pen );
+
+
+/*************************************************************************
+ * ROP2 Table of function pointers.
+ ************************************************************************/
+const DrawRGB_ROP_FUNC draw_rgb_ROP2_table[16] =
+{
+  DIBENG_DrawRGB_ROP2_BLACK,
+  DIBENG_DrawRGB_ROP2_NOTMERGEPEN,
+  DIBENG_DrawRGB_ROP2_MASKNOTPEN,
+  DIBENG_DrawRGB_ROP2_NOTCOPYPEN,
+  DIBENG_DrawRGB_ROP2_MASKPENNOT,
+  DIBENG_DrawRGB_ROP2_NOT,
+  DIBENG_DrawRGB_ROP2_XORPEN,
+  DIBENG_DrawRGB_ROP2_NOTMASKPEN,
+  DIBENG_DrawRGB_ROP2_MASKPEN,
+  DIBENG_DrawRGB_ROP2_NOTXORPEN,
+  DIBENG_DrawRGB_ROP2_NOP,
+  DIBENG_DrawRGB_ROP2_MERGENOTPEN,
+  DIBENG_DrawRGB_ROP2_COPYPEN,
+  DIBENG_DrawRGB_ROP2_MERGEPENNOT,
+  DIBENG_DrawRGB_ROP2_MERGEPEN,
+  DIBENG_DrawRGB_ROP2_WHITE
+};
+
+
+/*************************************************************************
+ * ROP3 Table of ROP strings.
+ ************************************************************************/
+
+/* Maybe there is a better way to do this? If someone wants to take
+ * the time to work out how exactly MS decodes their ROP3 stuff,
+ * feel free.
+ * Information can be found at the URL above.
+ */
+static const char draw_rgb_ROP3_table_str[256][MAX_ROP_LEN] =
+{
+  "0",        /* BLACKNESS */
+  "DPSoon",
+  "DPSona",
+  "PSon",
+  "SDPona",
+  "DPon",
+  "PDSxnon",
+  "PDSaon",
+  "SDPnaa",
+  "PDSxon",
+  "DPna",
+  "PSDnaon",
+  "SPna",
+  "PDSnaon",
+  "PDSonon",
+  "Pn",
+  "PDSona",
+  "DSon",     /* NOTSRCERASE */
+  "SDPxnon",
+  "SDPaon",
+  "DPSxnon",
+  "DPSaon",
+  "PSDPSanaxx",
+  "SSPxDSxaxn",
+  "SPxPDxa",
+  "SDPSanaxn",
+  "PDSPaox",
+  "SDPSxaxn",
+  "PSDPaox",
+  "DSPDxaxn",
+  "PDSox",
+  "PDSoan",
+  "DPSnaa",
+  "SDPxon",
+  "DSna",
+  "SPDnaon",
+  "SPxDSxa",
+  "PDSPanaxn",
+  "SDPSaox",
+  "SDPSxnox",
+  "DPSxa",
+  "PSDPSaoxxn",
+  "DPSana",
+  "SSPxPDxaxn",
+  "SPDSoax",
+  "PSDnox",
+  "PSDPxox",
+  "PSDnoan",
+  "PSna",
+  "SDPnaon",
+  "SDPSoox",
+  "Sn",       /* NOTSRCCOPY */
+  "SPDSaox",
+  "SPDSxnox",
+  "SDPox",
+  "SDPoan",
+  "PSDPoax",
+  "SPDnox",
+  "SPDSxox",
+  "SPDnoan",
+  "PSx",
+  "SPDSonox",
+  "SPDSnaox",
+  "PSan",
+  "PSDnaa",
+  "DPSxon",
+  "SDxPDxa",
+  "SPDSanaxn",
+  "SDna",     /* SRCERASE */
+  "DPSnaon",
+  "DSPDaox",
+  "PSDPxaxn",
+  "SDPxa",
+  "PDSPDaoxxn",
+  "DPSDoax",
+  "PDSnox",
+  "SDPana",
+  "SSPxDSxoxn",
+  "PDSPxox",
+  "PDSnoan",
+  "PDna",
+  "DSPnaon",
+  "DPSDaox",
+  "SPDSxaxn",
+  "DPSonon",
+  "Dn",       /* DSTINVERT */
+  "DPSox",
+  "DPSoan",
+  "PDSPoax",
+  "DPSnox",
+  "DPx",     /* PATINVERT */
+  "DPSDonox",
+  "DPSDxox",
+  "DPSnoan",
+  "DPSDnaox",
+  "DPan",
+  "PDSxa",
+  "DSPDSaoxxn",
+  "DSPDoax",
+  "SDPnox",
+  "SDPSoax",
+  "DSPnox",
+  "DSx",      /* SRCINVERT */
+  "SDPSonox",
+  "DSPDSonoxxn",
+  "PDSxxn",
+  "DPSax",
+  "PSDPSoaxxn",
+  "SDPax",
+  "PDSPDoaxxn",
+  "SDPSnoax",
+  "PDSxnan",
+  "PDSana",
+  "SSDxPDxaxn",
+  "SDPSxox",
+  "SDPnoan",
+  "DSPDxox",
+  "DSPnoan",
+  "SDPSnaox",
+  "DSan",
+  "PDSax",
+  "DSPDSoaxxn",
+  "DPSDnoax",
+  "SDPxnan",
+  "SPDSnoax",
+  "DPSxnan",
+  "SPxDSxo",
+  "DPSaan",
+  "DPSaa",
+  "SPxDSxon",
+  "DPSxna",
+  "SPDSnoaxn",
+  "SDPxna",
+  "PDSPnoaxn",
+  "DSPDSoaxx",
+  "PDSaxn",
+  "DSa",      /* SRCAND */
+  "SDPSnaoxn",
+  "DSPnoa",
+  "DSPDxoxn",
+  "SDPnoa",
+  "SDPSxoxn",
+  "SSDxPDxax",
+  "PDSanan",
+  "PDSxna",
+  "SDPSnoaxn",
+  "DPSDPoaxx",
+  "SPDaxn",
+  "PSDPSoaxx",
+  "DPSaxn",
+  "DPSxx",
+  "PSDPSonoxx",
+  "SDPSonoxn",
+  "DSxn",
+  "DPSnax",
+  "SDPSoaxn",
+  "SPDnax",
+  "DSPDoaxn",
+  "DSPDSaoxx",
+  "PDSxan",
+  "DPa",
+  "PDSPnaoxn",
+  "DPSnoa",
+  "DPSDxoxn",
+  "PDSPonoxn",
+  "PDxn",
+  "DSPnax",
+  "PDSPoaxn",
+  "DPSoa",
+  "DPSoxn",
+  "D",
+  "DPSono",
+  "SPDSxax",
+  "DPSDaoxn",
+  "DSPnao",
+  "DPno",
+  "PDSnoa",
+  "PDSPxoxn",
+  "SSPxDSxox",
+  "SDPanan",
+  "PSDnax",
+  "DPSDoaxn",
+  "DPSDPaoxx",
+  "SDPxan",
+  "PSDPxax",
+  "DSPDaoxn",
+  "DPSnao",
+  "DSno",     /* MERGEPAINT */
+  "SPDSanax",
+  "SDxPDxan",
+  "DPSxo",
+  "DPSano",
+  "PSa",      /* MERGECOPY */
+  "SPDSnaoxn",
+  "SPDSonoxn",
+  "PSxn",
+  "SPDnoa",
+  "SPDSxoxn",
+  "SDPnax",
+  "PSDPoaxn",
+  "SDPoa",
+  "SPDoxn",
+  "DPSDxax",
+  "SPDSaoxn",
+  "S",        /* SRCCOPY */
+  "SDPono",
+  "SDPnao",
+  "SPno",
+  "PSDnoa",
+  "PSDPxoxn",
+  "PDSnax",
+  "SPDSoaxn",
+  "SSPxPDxax",
+  "DPSanan",
+  "PSDPSaoxx",
+  "DPSxan",
+  "PDSPxax",
+  "SDPSaoxn",
+  "DPSDanax",
+  "SPxDSxan",
+  "SPDnao",
+  "SDno",
+  "SDPxo",
+  "SDPano",
+  "PDSoa",
+  "PDSoxn",
+  "DSPDxax",
+  "PSDPaoxn",
+  "SDPSxax",
+  "PDSPaoxn",
+  "SDPSanax",
+  "SPxPDxan",
+  "SSPxDSxax",
+  "DSPDSanaxxn",
+  "DPSao",
+  "DPSxno",
+  "SDPao",
+  "SDPxno",
+  "DSo",      /* SRCPAINT */
+  "SDPnoo",
+  "P",        /* PATCOPY */
+  "PDSono",
+  "PDSnao",
+  "PSno",
+  "PSDnao",
+  "PDno",
+  "PDSxo",
+  "PDSano",
+  "PDSao",
+  "PDSxno",
+  "DPo",
+  "DPSnoo",   /* PATPAINT */
+  "PSo",
+  "PSDnoo",
+  "DPSoo",
+  "1"         /* WHITENESS */
+};
+
+
+
+
+/*************************************************************************
+ * ROP2 (binary raster operations).
+ ************************************************************************/
+
+/* optimized for all cases */
+inline COLORREF DIBENG_DrawRGB_ROP2_ALL( DWORD ropmode, COLORREF dst, COLORREF pen)
+{
+  switch (ropmode)
+  {
+      case R2_BLACK:
+        return 0;
+      case R2_NOTMERGEPEN:
+        return ( ~( pen | dst ));
+      case R2_MASKNOTPEN:
+        return ( ~pen & dst );
+      case R2_NOTCOPYPEN:
+        return ~pen;
+      case R2_MASKPENNOT:
+        return ( ~dst & pen );
+      case R2_NOT:
+        return ~dst;
+      case R2_XORPEN:
+        return ( pen ^ dst );
+      case R2_NOTMASKPEN:
+        return ( ~( pen & dst ));
+      case R2_MASKPEN:
+        return ( pen & dst );
+      case R2_NOTXORPEN:
+        return ( ~( pen ^ dst ));
+      case R2_NOP:
+        return dst;
+      case R2_MERGENOTPEN:
+        return ( ~pen | dst );
+      case R2_COPYPEN:
+        return pen;
+      case R2_MERGEPENNOT:
+        return ( ~dst | pen );
+      case R2_MERGEPEN:
+        return ( pen | dst );
+      case R2_WHITE:
+        return RGB( 255, 255, 255 );
+      default:
+        FIXME("invalid ROP2 mode\n");
+        return 0;
+  }
+}
+
+/* 00 R2_BLACK  0  */
+COLORREF DIBENG_DrawRGB_ROP2_BLACK( COLORREF dst, COLORREF pen )
+{
+  return 0;
+}
+
+/* 01 R2_NOTMERGEPEN  DPon  ( ~( P | D ))  */
+COLORREF DIBENG_DrawRGB_ROP2_NOTMERGEPEN( COLORREF dst, COLORREF pen )
+{
+  return ( ~( pen | dst ));
+}
+
+/* 02 R2_MASKNOTPEN  DPna  ( ~P & D )  */
+COLORREF DIBENG_DrawRGB_ROP2_MASKNOTPEN( COLORREF dst, COLORREF pen )
+{
+  return ( ~pen & dst );
+}
+
+/* 03 R2_NOTCOPYPEN  Pn  ( ~P )  */
+COLORREF DIBENG_DrawRGB_ROP2_NOTCOPYPEN( COLORREF dst, COLORREF pen )
+{
+  return ~pen;
+}
+
+/* 04 R2_MASKPENNOT  PDna  ( ~D & P )  */
+COLORREF DIBENG_DrawRGB_ROP2_MASKPENNOT( COLORREF dst, COLORREF pen )
+{
+  return ( ~dst & pen );
+}
+
+/* 05 R2_NOT  Dn  ( ~D )  */
+COLORREF DIBENG_DrawRGB_ROP2_NOT( COLORREF dst, COLORREF pen )
+{
+  return ~dst;
+}
+
+/* 06 R2_XORPEN  DPx  ( P ^ D )  */
+COLORREF DIBENG_DrawRGB_ROP2_XORPEN( COLORREF dst, COLORREF pen )
+{
+  return ( pen ^ dst );
+}
+
+/* 07 R2_NOTMASKPEN DPan  ( ~( P & D ))  */
+COLORREF DIBENG_DrawRGB_ROP2_NOTMASKPEN( COLORREF dst, COLORREF pen )
+{
+  return ( ~( pen & dst ));
+}
+
+/* 08 R2_MASKPEN  DPa  ( P & D )  */
+COLORREF DIBENG_DrawRGB_ROP2_MASKPEN( COLORREF dst, COLORREF pen )
+{
+  return ( pen & dst );
+}
+
+/* 09 R2_NOTXORPEN  DPxn  ( ~( P ^ D ))  */
+COLORREF DIBENG_DrawRGB_ROP2_NOTXORPEN( COLORREF dst, COLORREF pen )
+{
+  return ( ~( pen ^ dst ));
+}
+
+/* 0A R2_NOP  D  */
+COLORREF DIBENG_DrawRGB_ROP2_NOP( COLORREF dst, COLORREF pen )
+{
+  return dst;
+}
+
+/* 0B R2_MERGENOTPEN  DPno  ( ~P | D )  */
+COLORREF DIBENG_DrawRGB_ROP2_MERGENOTPEN( COLORREF dst, COLORREF pen )
+{
+  return ( ~pen | dst );
+}
+
+/* 0C R2_COPYPEN  P  */
+COLORREF DIBENG_DrawRGB_ROP2_COPYPEN( COLORREF dst, COLORREF pen )
+{
+  return pen;
+}
+
+/* 0D R2_MERGEPENNOT  PDno  ( ~D | P )  */
+COLORREF DIBENG_DrawRGB_ROP2_MERGEPENNOT( COLORREF dst, COLORREF pen )
+{
+  return ( ~dst | pen );
+}
+
+/* 0E R2_MERGEPEN  DPo  ( P | D )  */
+COLORREF DIBENG_DrawRGB_ROP2_MERGEPEN( COLORREF dst, COLORREF pen )
+{
+  return ( pen | dst );
+}
+
+/* 0F R2_WHITE  1  */
+COLORREF DIBENG_DrawRGB_ROP2_WHITE( COLORREF dst, COLORREF pen )
+{
+  return RGB( 255, 255, 255 );
+}
+
+
+
+/*************************************************************************
+ * ROP3 (ternary raster operations).
+ ************************************************************************/
+
+COLORREF DIBENG_DrawRGB_ROP3( COLORREF src, COLORREF dst, COLORREF pat, DWORD ROPmode )
+{
+  /* Pointer to appropriate ROP string. */
+  const char *rop_str = NULL;
+  COLORREF stack[MAX_ROP_LEN];
+  COLORREF temp;
+  short cur_stack = 0;
+
+  TRACE( "(%ld, %ld, %ld, %ld)\n", src, dst, pat, ROPmode );
+#if 1
+  /* optimizations for common/easy ROP's, add any more here? */
+  switch (ROPmode)
+  {
+      case BLACKNESS: /* 0x00 */
+        return 0;
+	  case SRCINVERT:
+	    return ~src;
+	  case DSTINVERT: /* 0x55 */
+	    return ~dst;
+	  case PATINVERT: /* 0x5a */
+	    return ~pat;
+	  case SRCCOPY:
+	    return src;
+	  case PATCOPY:
+	    return pat;
+	  case WHITENESS:
+	    return RGB( 255, 255, 255 );
+  }
+  /* end optimizations, use parser */
+#endif
+
+  /* this parser could do with a fair bit of optimizations..
+   * but this will do for now. */
+
+  rop_str = draw_rgb_ROP3_table_str[( ROPmode >> 0x10 ) & 0xff ];
+
+#if ROP3_DEBUG
+  ERR( "ROP: 0x%lx   ROP string: %s\n", ROPmode, rop_str );
+#endif
+
+
+  if( rop_str[0] == '1' )
+    return RGB( 255, 255, 255 );
+
+  if( rop_str[0] == '0' )
+    return 0;
+
+  if( rop_str[1] == 0 )
+  {
+    switch( rop_str[0] )
+    {
+      case 'P':
+        return pat;
+      case 'S':
+        return src;
+      case 'D':
+        return dst;
+      default:
+        ERR( "(a) Error at ROP 0x%lx with character %c.\n", ROPmode, rop_str[0] );
+        return 0;
+    }
+  }
+
+  /* Parse string until we have no more operators. */
+  while( rop_str[0] )
+  {
+    switch( rop_str[0] )
+    {
+      case 'P':
+        stack[cur_stack] = pat;
+#if ROP3_DEBUG
+        ERR( "P (0x%lx\n", stack[cur_stack] );
+#endif
+        cur_stack++;
+        break;
+      case 'S':
+        stack[cur_stack] = src;
+#if ROP3_DEBUG
+        ERR( "S (0x%lx\n", stack[cur_stack] );
+#endif
+        cur_stack++;
+        break;
+      case 'D':
+        stack[cur_stack] = dst;
+#if ROP3_DEBUG
+        ERR( "S (0x%lx\n", stack[cur_stack] );
+#endif
+        cur_stack++;
+        break;
+      case 'a':
+#if ROP3_DEBUG
+        if( cur_stack < 2 )
+        {
+          ERR( "(b) Error at ROP 0x%lx.\n", ROPmode );
+          break;
+        }
+#endif
+
+        /* Pop 2, push 1. */
+        temp = stack[cur_stack - 1] & stack[cur_stack - 2];
+#if ROP3_DEBUG
+        ERR( "0x%lx & 0x%lx == 0x%lx\n", stack[cur_stack - 1], stack[cur_stack - 2], stack[cur_stack - 1] & stack[cur_stack - 2] );
+#endif
+        stack[cur_stack - 2] = temp;
+        cur_stack--;
+        break;
+      case 'n':
+#if ROP3_DEBUG
+        if( cur_stack < 1 )
+        {
+          ERR( "(c) Error at ROP 0x%lx.\n", ROPmode );
+          break;
+        }
+#endif
+
+        /* Pop 1, push 1. */
+        temp = ~stack[cur_stack - 1];
+#if ROP3_DEBUG
+        ERR( "~ 0x%lx == 0x%lx\n", stack[cur_stack - 1], ~stack[cur_stack - 1] );
+#endif
+        stack[cur_stack - 1] = temp;
+        break;
+      case 'o':
+#if ROP3_DEBUG
+        if( cur_stack < 1 )
+        {
+          ERR( "(d) Error at ROP 0x%lx.\n", ROPmode );
+          break;
+        }
+#endif
+        /* Pop 2, push 1. */
+        temp = stack[cur_stack - 1] | stack[cur_stack - 2];
+#if ROP3_DEBUG
+        ERR( "0x%lx | 0x%lx == 0x%lx\n", stack[cur_stack - 1], stack[cur_stack - 2], stack[cur_stack - 1] | stack[cur_stack - 2] );
+#endif
+        stack[cur_stack - 2] = temp;
+        cur_stack--;
+        break;
+      case 'x':
+#if ROP3_DEBUG
+        if( cur_stack < 2 )
+        {
+          ERR( "(e) Error at ROP 0x%lx.\n", ROPmode );
+          break;
+        }
+#endif
+
+        /* Pop 2, push 1. */
+        temp = stack[cur_stack - 1] ^ stack[cur_stack - 2];
+#if ROP3_DEBUG
+        ERR( "0x%lx ^ 0x%lx == 0x%lx\n", stack[cur_stack - 1], stack[cur_stack - 2], stack[cur_stack - 1] ^ stack[cur_stack - 2] );
+#endif
+        stack[cur_stack - 2] = temp;
+        cur_stack--;
+        break;
+      default:
+        ERR( "(f) Error at ROP 0x%lx with character %c.\n", ROPmode, rop_str[0] );
+        return 0;
+    }
+
+    rop_str++;
+  }
+
+#if ROP3_DEBUG
+  if( cur_stack != 1 )
+    ERR( "(g) Error at ROP 0x%lx, cur_stack == %d.\n", ROPmode, cur_stack );
+
+  ERR( "Final color: %lx\n", stack[0] );
+#endif
+
+  /* The string left in the stack is our final ROP. */
+  return stack[0];
+}
Index: graphics/dibeng/dibeng_primitives.c
===================================================================
RCS file: graphics/dibeng/dibeng_primitives.c
diff -N graphics/dibeng/dibeng_primitives.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/dibeng_primitives.c	27 Sep 2002 17:45:50 -0000
@@ -0,0 +1,867 @@
+/*
+  Copyright (c) 2002, TransGaming Technologies Inc.
+
+  Primitives drawing, eg. pixels, lines, rectangles, ellipses, etc.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "minmax.h"
+#include "bitmap.h"
+#include "brush.h"
+#include "pen.h"
+#include "gdi.h"
+#include "heap.h"
+#include "debugtools.h"
+
+#include "dibeng_private.h"
+
+DEFAULT_DEBUG_CHANNEL( dibeng );
+
+/* FIXME: The polygon ET stuff should be static, and its prototypes put
+ * here. Maybe swap the tabs for space at the same time... */
+
+
+/***********************************************************************
+ * Converts a Windows RGB value to a pixel value, taking into account
+ * the color depth of the DIB.
+ */
+inline UINT DIBENG_RGB2Pixel( dibeng_t *dib, COLORREF rgb )
+{
+  UINT pixel = 0;
+
+  TRACE( "(%p, 0x%lx)\n", dib, rgb );
+
+  switch( dib->bpp )
+  {
+    case 15:
+    case 16:
+    case 24:
+    case 32:
+      pixel = (((( GetRValue( rgb ) >> dib->rloss ) << dib->rshift ) & dib->rmask ) |
+        ((( GetGValue( rgb ) >> dib->gloss ) << dib->gshift ) & dib->gmask ) |
+        ((( GetBValue( rgb ) >> dib->bloss ) << dib->bshift ) & dib->bmask ));
+      break;
+    case 1:
+    case 4:
+    case 8:
+    default:
+      FIXME("depth not supported: %i\n", dib->bpp);
+      break;
+  }
+
+  TRACE( "Returning pixel color: 0x%x\n", pixel );
+  return pixel;
+}
+
+/***********************************************************************
+ * Converts a pixel value to a Windows RGB value, taking into account
+ * the color depth of the DIB.
+ */
+inline COLORREF DIBENG_Pixel2RGB( dibeng_t *dib, UINT pixel )
+{
+  COLORREF rgb = 0;
+
+  TRACE( "(%p, 0x%x)\n", dib, pixel );
+
+  switch( dib->bpp )
+  {
+    case 15:
+    case 16:
+    case 24:
+    case 32:
+      /* Account for the bits lost when converting.
+       * e.g. in RGB->16bit->RGB == 255->31->248.
+       * Make it map back to 255. */
+      /* FIXME: Is this consistent with how Windows does it? */
+      rgb = RGB((( pixel & dib->rmask ) >> dib->rshift ) << dib->rloss,
+                (( pixel & dib->gmask ) >> dib->gshift ) << dib->gloss,
+                (( pixel & dib->bmask ) >> dib->bshift ) << dib->bloss );
+      break;
+    case 1:
+    case 4:
+    case 8:
+    default:
+      FIXME("depth not supported: %i\n", dib->bpp);
+      break;
+  }
+
+
+  TRACE( "Returning COLORREF: 0x%lx\n", rgb );
+  return rgb;
+}
+
+/***********************************************************************
+ * Draws a RGB color in the destination DIB, using a mix of the destination
+ * pixel, the destination DIB's pen color or brush pattern, and the source
+ * pixel, depending on the ROP mode.
+ */
+void DIBENG_DrawRGB( dibeng_t *dib, INT x, INT y, COLORREF c )
+{
+/* FIXME: optimizations required here.. Here are some ideas:
+ *  - write an optimized function to draw lines (horizontal easiest)
+ *    which would basically grab the background of the line all at
+ *    once, do any necessary calculations depending on the ROP mode
+ *    and then all at once blot on the new line.
+ *  - Use the above idea for optimizing fills aswell, a fill can
+ *    be made out of lots of lines joined together.
+ */
+  TRACE( "(%p, %d, %d, 0x%lx)\n", dib, x, y, c );
+
+  /* Implemented ROP2 modes. */
+  if( dib->ROPmode < 0x10 )
+  {
+    UINT final_pixel;
+    COLORREF temp;
+    COLORREF dst, pen;
+
+    dst = DIBENG_ReadRGB( dib, x, y );
+    pen = dib->pen_color;
+
+    /* FIXME: Where does the "use_bg" test go? Test with source color alone,
+     * or final color?
+     */
+
+    final_pixel = DIBENG_RGB2Pixel( dib,
+        DIBENG_DrawRGB_ROP2_ALL( dib->ROPmode, dst, pen) );
+    DIBENG_DrawPixel( dib, x, y, final_pixel );
+  }
+  /* Not implemented, undocumented, or new ROP2 modes. */
+  else if( dib->ROPmode < 0x42 )
+  {
+    FIXME( "ROP2 not implemented: 0x%lx\n", dib->ROPmode );
+  }
+  /* ROP3 modes. */
+  else if( dib->ROPmode < 0xffffff )
+  {
+    UINT final_pixel;
+    COLORREF temp;
+    COLORREF src, dst, pat;
+
+    dst = DIBENG_ReadRGB( dib, x, y );
+    src = c;
+    pat = 0;
+    /* Get pattern color only if the brush is set up. */
+    if( dib->dib_pattern )
+    {
+      pat = DIBENG_ReadRGB( dib->dib_pattern, x % dib->dib_pattern->width,
+        y % dib->dib_pattern->height );
+    }
+    /* Otherwise, get brush color from dib->pen_color. */
+    else
+    {
+      pat = dib->pen_color;
+    }
+
+    /* FIXME: Is this really how to do it? Needs more testing. */
+    /* If the source pixel is black and the background is in transparent mode, don't draw anything. */
+    if(( src == 0 ) && ( !dib->use_bg ))
+      return;
+
+    temp = DIBENG_DrawRGB_ROP3( src, dst, pat, dib->ROPmode );
+    final_pixel = DIBENG_RGB2Pixel( dib, temp );
+    DIBENG_DrawPixel( dib, x, y, final_pixel );
+  }
+  else if( dib->ROPmode == 0x80000000 )
+  {
+    /* NOMIRRORBITMAP. Only on Windows 98/Me, Windows 2000/XP. */
+    FIXME( "stub\n" );
+  }
+  else
+  {
+    ERR( "Unknown ROP mode: 0x%lx.\n", dib->ROPmode );
+  }
+}
+
+COLORREF DIBENG_ReadRGB( dibeng_t *dib, INT x, INT y )
+{
+  UINT pixel;
+  COLORREF color;
+
+  TRACE( "(%p, %d, %d)\n", dib, x, y );
+
+  pixel = DIBENG_ReadPixel( dib, x, y );
+  color = DIBENG_Pixel2RGB( dib, pixel );
+  return color;
+}
+
+/***********************************************************************
+ * Draws a pixel in the destination DIB, exactly as it is given.
+ */
+inline void DIBENG_DrawPixel( dibeng_t *dib, INT x, INT y, UINT c )
+{
+  LPBYTE buffer = (LPBYTE)dib->buffer;
+  buffer += y * dib->linelen;
+
+  TRACE( "(%p, %d, %d, %u) bpp: %i.\n", dib, x, y, c, dib->bpp );
+
+  switch (dib->bpp)
+  {
+    case 32:
+      {
+        unsigned int *addr = (unsigned int *)buffer + (x*4);
+        *addr = c;
+      }
+      break;
+    case 24:
+      {
+        unsigned char *addr = buffer + (x*3);
+        addr[3] = c >> 8;
+        addr[2] = c >> 16;
+        addr[1] = c >> 24;
+        break;
+      }
+    case 16:
+    case 15:
+      {
+        unsigned char *addr = buffer + (x*2);
+        addr[1] = c >> 8;
+	    addr[0] = c;
+      }
+      break;
+    case 8:
+      {
+        unsigned char *addr = buffer + x;
+        *addr = c; /* palette index */
+	  }
+      break;
+    case 4:
+    case 1:
+    default:
+      FIXME("unsupported depth: %i\n", dib->bpp);
+      break;
+  }
+}
+
+inline UINT DIBENG_ReadPixel( dibeng_t *dib, INT x, INT y )
+{
+  UINT pixel = 0;  /* Color read from buffer. */
+  LPBYTE buffer = (LPBYTE)dib->buffer;
+  buffer += y * dib->linelen;
+
+  TRACE( "(%p, %d, %d)\n", dib, x, y );
+
+  switch (dib->bpp)
+  {
+    case 32:
+      {
+        unsigned int *addr = (unsigned int *)buffer + (x*4);
+        pixel = *addr;
+      }
+      break;
+    case 24:
+      {
+        unsigned char *addr = buffer + (x*3);
+	    pixel = addr[3] << 24 |
+	            addr[2] << 16 |
+		        addr[1] << 8;
+        break;
+      }
+    case 16:
+    case 15:
+      {
+        unsigned char *addr = buffer + (x*2);
+	    pixel = addr[1] << 8 |
+	            addr[0];
+      }
+      break;
+    case 8:
+      {
+        unsigned char *addr = buffer + x;
+        pixel = *addr; /* palette index */
+	  }
+      break;
+    case 4:
+    case 1:
+    default:
+      FIXME("unsupported depth: %i\n", dib->bpp);
+      break;
+  }
+
+  return pixel;
+}
+
+void DIBENG_DrawHorzLine( dibeng_t *dib, INT x1, INT x2, INT y )
+{
+  INT i;
+
+  TRACE( "(%p, %d, %d, %d)\n", dib, x1, x2, y );
+
+  for( i = x1; i < x2; i++ )
+  {
+    DIBENG_DrawRGB( dib, i, y, 0 );
+  }
+}
+
+void DIBENG_DrawVertLine( dibeng_t *dib, INT x, INT y1, INT y2 )
+{
+  INT i;
+
+  TRACE( "(%p, %d, %d, %d)\n", dib, x, y1, y2 );
+
+  for( i = y1; i < y2; i++ )
+  {
+    DIBENG_DrawRGB( dib, x, i, 0 );
+  }
+}
+
+void DIBENG_FillRect( dibeng_t *dib, INT x1, INT y1, INT x2, INT y2 )
+{
+  INT i;
+  INT minx, maxx;
+  INT miny, maxy;
+
+  TRACE( "(%p, %d, %d, %d, %d)\n", dib, x1, y1, x2, y2 );
+
+  /* Clip to buffer size. */
+  minx = max( x1, 0 );
+  maxx = min( x2, dib->width - 1 );
+  miny = max( y1, 0 );
+  maxy = min( y2, dib->height - 1 );
+
+  for( i = miny; i <= maxy; i++ )
+  {
+    DIBENG_DrawHorzLine( dib, minx, maxx, i );
+  }
+}
+
+/* FIXME: Optimize, and complete function (eg. other ROP modes)... */
+void DIBENG_Blit( dibeng_t *dibeng_dst, INT dstx, INT dsty, INT w, INT h,
+  dibeng_t *dibeng_src, INT srcx, INT srcy, DWORD rop )
+{
+  INT x, y;
+  DWORD old_ROPmode = dibeng_dst->ROPmode;
+
+  TRACE( "(%p, %d, %d, %d, %d, %p, %d, %d, 0x%lx)\n", dibeng_dst, dstx, dsty,
+    w, h, dibeng_src, srcx, srcy, rop );
+
+  dibeng_dst->ROPmode = rop;
+
+  for( y = 0; y < h; y++ )
+  {
+    for( x = 0; x < w; x++ )
+    {
+      DIBENG_DrawRGB( dibeng_dst, dstx + x, dsty + y, DIBENG_ReadRGB( dibeng_src, srcx + x, srcy + y ));
+    }
+  }
+
+  dibeng_dst->ROPmode = old_ROPmode;
+}
+
+/***********************************************************************
+ * DIBENG_Line
+ * Draws a line, excluding the last point if draw_last_point is FALSE.
+ */
+void DIBENG_Line( dibeng_t *dib, INT x1, INT y1, INT x2, INT y2, BOOL draw_last_point )
+{
+  /* FIXME: Do not draw last point (x2,y2); be careful of the point swap. */
+
+  INT deltax, deltay;
+  INT xinc;
+  INT temp;
+  INT d;
+
+  TRACE( "(%p, %d, %d, %d, %d, %d)\n", dib, x1, y1, x2, y2, draw_last_point );
+
+  if( y1 > y2 )
+  {
+    temp = x1;
+    x1 = x2;
+    x2 = temp;
+
+    temp = y1;
+    y1 = y2;
+    y2 = temp;
+  }
+
+  deltax = x2 - x1;
+  deltay = y2 - y1;
+  xinc = 1;
+
+  if( deltax < 0 )
+  {
+    deltax = -deltax;
+    xinc = -1;
+  }
+
+  /* Vertical line. */
+  if( !deltax )
+  {
+    DIBENG_DrawVertLine( dib, x1, y1, y2 );
+    return;
+  }
+
+  /* Horizontal line. */
+  if( !deltay )
+  {
+    if( xinc < 0 )
+    {
+      DIBENG_DrawHorzLine( dib, x2, x1, y1 );
+    }
+    else
+    {
+      DIBENG_DrawHorzLine( dib, x1, x2, y1 );
+    }
+    return;
+  }
+
+  /* Diagonal line. */
+  if( deltax == deltay )
+  {
+    while( x1 != x2 )
+    {
+      DIBENG_DrawRGB( dib, x1, y1, 0 );
+      x1 += xinc;
+      y1++;
+    }
+    DIBENG_DrawRGB( dib, x1, y1, 0 );
+    return;
+  }
+
+  DIBENG_DrawRGB( dib, x1, y1, 0 );
+
+  if( deltax > deltay )
+  {
+    d = ( deltay << 1 ) - deltax;
+    while( x1 != x2 )
+    {
+      if( d > 0 )
+      {
+        y1++;
+        d += ( deltay - deltax ) << 1;
+      }
+      else
+      {
+        d += ( deltay << 1 );
+      }
+      x1 += xinc;
+      DIBENG_DrawRGB( dib, x1, y1, 0 );
+    }
+  }
+  else
+  {
+    d = ( deltax << 1 ) - deltay;
+    while( y1 < y2 )
+    {
+      if( d > 0 )
+      {
+        x1 += xinc;
+        d += ( deltax << 1 ) - ( deltay << 1 );
+      }
+      else
+      {
+        d += ( deltax << 1 );
+      }
+      y1++;
+      DIBENG_DrawRGB( dib, x1, y1, 0 );
+    }
+  }
+}
+
+
+
+
+/****************************************************************************
+ * Insert an edge in the ET, sorted in (increasing) min x order.
+ */
+void DIBENG_InsertEdge( ET_node_t **head, ET_node_t *new_node )
+{
+	ET_node_t *cur_node;
+	ET_node_t *prev_node;
+
+	/* If the list is empty, simply add it. */
+	if( *head == NULL )
+	{
+		*head = new_node;
+		new_node->next = NULL;
+		return;
+	}
+
+	/* Find proper place in scan line list to insert node in. */
+	prev_node = NULL;
+	cur_node = *head;
+	while( cur_node && ( new_node->minx > cur_node->minx ))
+	{
+		prev_node = cur_node;
+		cur_node = cur_node->next;
+	}
+
+	/* The edge's min x is smaller than the current edge with the smallest min x. */
+	if( !prev_node )
+	{
+		new_node->next = *head;
+		*head = new_node;
+		return;
+	}
+
+	/* The edge's min x is bigger than the current edge with the biggest min x. */
+	if( !cur_node )
+	{
+		prev_node->next = new_node;
+		return;
+	}
+
+	/* The only option left; the min x's are equal or the edge's min x is smaller. */
+	new_node->next = cur_node;
+	prev_node->next = new_node;
+}
+
+/****************************************************************************
+ * Initializes the Global Edge Table (GET).
+ */
+ET_list_t *DIBENG_InitGET( const POINT *points, INT count )
+{
+	ET_list_t *et_head = NULL;
+	ET_node_t *new_node;
+	const POINT *p1;
+	const POINT *p2;
+	INT i;
+
+	/* Insert the edge from last point to first. */
+	p1 = &points[count - 1];
+	p2 = &points[0];
+
+	new_node = (ET_node_t *)HeapAlloc( GetProcessHeap(), 0, sizeof( ET_node_t ));
+	new_node->minx = ( p1->y < p2->y ) ? p1->x : p2->x;
+	new_node->maxy = max( p1->y, p2->y );
+	new_node->dx   = ( p2->x - p1->x );
+	new_node->dy   = ( p2->y - p1->y );
+	/* Find the x inc direction. Positive only if the two deltas are the same
+	 * sign. */
+	if((( new_node->dx > 0 ) && ( new_node->dy > 0 )) ||
+		(( new_node->dx < 0 ) && ( new_node->dy < 0 )))
+	{
+		new_node->xinc = 1;
+	}
+	else
+	{
+		new_node->xinc = -1;
+	}
+	/* Make the deltas absolute. */
+	new_node->dx   = ( new_node->dx > 0 ) ? new_node->dx : -new_node->dx;
+	new_node->dy   = ( new_node->dy > 0 ) ? new_node->dy : -new_node->dy;
+	new_node->d    = ( new_node->dx > new_node->dy ) ?
+		(( new_node->dy << 1 ) - new_node->dx ) :
+		(( new_node->dx << 1 ) - new_node->dy );
+	new_node->next = NULL;
+
+	et_head = (ET_list_t *)HeapAlloc( GetProcessHeap(), 0, sizeof( ET_list_t ));
+	et_head->y = min( p1->y, p2->y );
+	et_head->next = NULL;
+	et_head->edges = new_node;
+
+
+	for( i = 0; i < ( count - 1 ); i++ )
+	{
+		ET_list_t *cur_list;
+		ET_list_t *prev_list;
+		INT miny;
+
+		p1 = &points[i];
+		p2 = &points[i + 1];
+
+		/* Create ET node. */
+		new_node = (ET_node_t *)HeapAlloc( GetProcessHeap(), 0, sizeof( ET_node_t ));
+		new_node->minx = ( p1->y < p2->y ) ? p1->x : p2->x;
+		new_node->maxy = max( p1->y, p2->y );
+		new_node->dx   = p2->x - p1->x;
+		new_node->dy   = p2->y - p1->y;
+		/* Find the x inc direction. Positive only if the two deltas are the same
+		 * sign. */
+		if((( new_node->dx > 0 ) && ( new_node->dy > 0 )) ||
+			(( new_node->dx < 0 ) && ( new_node->dy < 0 )))
+		{
+			new_node->xinc = 1;
+		}
+		else
+		{
+			new_node->xinc = -1;
+		}
+		/* Make the deltas absolute. */
+		new_node->dx   = ( new_node->dx > 0 ) ? new_node->dx : -new_node->dx;
+		new_node->dy   = ( new_node->dy > 0 ) ? new_node->dy : -new_node->dy;
+		new_node->d    = ( new_node->dx > new_node->dy ) ?
+			(( new_node->dy << 1 ) - new_node->dx ) :
+			(( new_node->dx << 1 ) - new_node->dy );
+		new_node->next = NULL;
+
+
+		miny = min( p1->y, p2->y );
+
+		/* Scan line is lower than the current lowest one. */
+		if( miny < et_head->y )
+		{
+			ET_list_t *temp_list = (ET_list_t *)HeapAlloc( GetProcessHeap(), 0, sizeof( ET_list_t ));
+			temp_list->y = miny;
+			temp_list->next = et_head;
+			temp_list->edges = new_node;
+			et_head = temp_list;
+			continue;
+		}
+
+		/* Find proper list in ET to insert node in. */
+		prev_list = NULL;
+		cur_list = et_head;
+		while( cur_list && ( miny > cur_list->y ))
+		{
+			prev_list = cur_list;
+			cur_list = cur_list->next;
+		}
+
+		/* Scan line is higher than the current highest one. */
+		if( !cur_list )
+		{
+			ET_list_t *temp_list = (ET_list_t *)HeapAlloc( GetProcessHeap(), 0, sizeof( ET_list_t ));
+			temp_list->y = miny;
+			temp_list->next = NULL;
+			temp_list->edges = new_node;
+			prev_list->next = temp_list;
+			continue;
+		}
+
+		/* Scan line is not in ET. */
+		if( miny < cur_list->y )
+		{
+			ET_list_t *temp_list = (ET_list_t *)HeapAlloc( GetProcessHeap(), 0, sizeof( ET_list_t ));
+			temp_list->y = miny;
+			temp_list->next = cur_list;
+			temp_list->edges = new_node;
+			prev_list->next = temp_list;
+			continue;
+		}
+
+		/* Insert edge at the right location. */
+		DIBENG_InsertEdge( &cur_list->edges, new_node );
+	}
+
+	return et_head;
+}
+
+/****************************************************************************
+ * Destroys an Edge Table (ET).
+ */
+void DIBENG_DestroyET( ET_node_t *et_head )
+{
+	while( et_head )
+	{
+		ET_node_t *temp_node = et_head;
+		et_head = temp_node->next;
+		HeapFree( GetProcessHeap(), 0, temp_node );
+	}
+}
+
+
+/****************************************************************************
+ * Destroys the Global Edge Table (GET).
+ */
+void DIBENG_DestroyGET( ET_list_t *et_head )
+{
+	while( et_head )
+	{
+		ET_list_t *temp_list;
+
+		DIBENG_DestroyET( et_head->edges );
+
+		temp_list = et_head;
+		et_head = temp_list->next;
+		HeapFree( GetProcessHeap(), 0, temp_list );
+	}
+}
+
+/****************************************************************************
+ * Updates edges in Active Edge Table (AET).
+ */
+void DIBENG_UpdateAET( ET_node_t **aet, ET_list_t *et, INT y )
+{
+	ET_node_t *cur_node;
+	ET_node_t *prev_node;
+
+
+	/* Add edges in AET that are on the current scan line. */
+	if( et->y == y )
+	{
+		while( et->edges )
+		{
+			/* Remove it from ET. */
+			ET_node_t *temp_node = et->edges;
+			et->edges = et->edges->next;
+			temp_node->next = NULL;
+
+			/* Insert it in AET. */
+			DIBENG_InsertEdge( aet, temp_node );
+		}
+	}
+
+
+	/* Remove edges from AET that have max y = y. */
+	while( *aet && (( *aet )->maxy == y ))
+	{
+		ET_node_t *temp_node = *aet;
+		*aet = ( *aet )->next;
+		HeapFree( GetProcessHeap(), 0, temp_node );
+	}
+
+	/* If after updating, the list is empty, we're done. */
+	if( *aet == NULL )
+		return;
+
+	prev_node = *aet;
+	cur_node = ( *aet )->next;
+	while( cur_node )
+	{
+		if( cur_node->maxy == y )
+		{
+			prev_node->next = cur_node->next;
+			HeapFree( GetProcessHeap(), 0, cur_node );
+			cur_node = prev_node;
+		}
+
+		prev_node = cur_node;
+		cur_node = cur_node->next;
+	}
+}
+
+/****************************************************************************
+ * Sort edges in Active Edge Table (AET) by min x. Uses Insertion Sort.
+ * Assumes AET is non-empty.
+ */
+void DIBENG_SortAET( ET_node_t **aet )
+{
+	ET_node_t *sorted_node;
+	ET_node_t *unsorted_node;
+
+
+	sorted_node = *aet;
+	unsorted_node = ( *aet )->next;
+	while( unsorted_node )
+	{
+		if( unsorted_node->minx < sorted_node->minx )
+		{
+			ET_node_t *prev_node = NULL;
+			ET_node_t *cur_node = *aet;
+
+			while( cur_node->minx < unsorted_node->minx )
+			{
+				prev_node = cur_node;
+				cur_node = cur_node->next;
+			}
+
+			if( !prev_node )
+			{
+				sorted_node->next = unsorted_node->next;
+				*aet = unsorted_node;
+				unsorted_node->next = cur_node;
+			}
+			else if( !cur_node )
+			{
+			    ERR("no prev_node or cur_node?\n");
+				assert( 0 );
+			}
+			else
+			{
+				sorted_node->next = unsorted_node->next;
+				prev_node->next = unsorted_node;
+				unsorted_node->next = cur_node;
+			}
+		}
+		else
+		{
+			sorted_node = sorted_node->next;
+		}
+
+		unsorted_node = sorted_node->next;
+	}
+}
+
+
+/* FIXME: The pixels don't map 100% to MS Windows' Polygon function. */
+void DIBENG_FillPolygon( dibeng_t *dib, const POINT *points, INT count )
+{
+	ET_list_t *et_head = DIBENG_InitGET( points, count );
+	ET_list_t *cur_list = et_head;
+	ET_node_t *aet = NULL;
+	INT y = cur_list->y;
+
+    TRACE( "(%p, %p, %d)\n", dib, points, count );
+
+	do
+	{
+		INT even;
+		ET_node_t *p1;
+		ET_node_t *p2;
+		ET_node_t *p;
+
+		/* Insert/delete edges in Active Edge Table (AET). */
+		DIBENG_UpdateAET( &aet, cur_list, y );
+
+		/* If after updating, the list is empty, we're done. */
+		if( aet == NULL )
+			break;
+
+		/* Sorts edges in AET by min x order. */
+		DIBENG_SortAET( &aet );
+
+		/* Draw spans in pairs of x coordinates. */
+		p1 = aet;
+		p2 = aet->next;
+		even = 1;
+
+		while( p2 )
+		{
+			if( even )
+				DIBENG_DrawHorzLine( dib, p1->minx + 1, p2->minx, y );
+			even ^= 1;
+			p1 = p2;
+			p2 = p2->next;
+		}
+
+		/* Compute x coordinates for next scan line. */
+		y++;
+		if( cur_list->next && ( cur_list->next->y == y ))
+			cur_list = cur_list->next;
+
+		p = aet;
+		while( p )
+		{
+			if( p->dx > p->dy )
+			{
+				while( 1 )
+				{
+					if( p->d > 0 )
+					{
+						p->d += ( p->dy - p->dx ) << 1;
+						p->minx += p->xinc;
+						break;
+					}
+					else
+					{
+						p->d += ( p->dy << 1 );
+						p->minx += p->xinc;
+					}
+				}
+			}
+			else
+			{
+				if( p->d > 0 )
+				{
+					p->minx += p->xinc;
+					p->d += ( p->dx << 1 ) - ( p->dy << 1 );
+				}
+				else
+				{
+					p->d += ( p->dx << 1 );
+				}
+			}
+
+			p = p->next;
+		}
+	} while( aet && et_head );
+
+
+	DIBENG_DestroyET( aet );
+	DIBENG_DestroyGET( et_head );
+}
+
Index: graphics/dibeng/dibeng_private.h
===================================================================
RCS file: graphics/dibeng/dibeng_private.h
diff -N graphics/dibeng/dibeng_private.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ graphics/dibeng/dibeng_private.h	27 Sep 2002 17:45:50 -0000
@@ -0,0 +1,53 @@
+#ifndef __DIBENG_PRIVATE_H__
+#define __DIBENG_PRIVATE_H__
+
+
+#include "wine/dibeng_main.h"
+
+/* dibeng_pixel.c */
+typedef COLORREF (*DrawRGB_ROP_FUNC)( COLORREF dst, COLORREF pat );
+const DrawRGB_ROP_FUNC draw_rgb_ROP2_table[16];
+inline COLORREF DIBENG_DrawRGB_ROP2_ALL( DWORD ropmode, COLORREF dst, COLORREF pen);
+COLORREF DIBENG_DrawRGB_ROP3( COLORREF src, COLORREF dst, COLORREF pat, DWORD ROPmode );
+
+/* dibeng_primitives.c */
+
+/* Edge Table (ET) node. */
+typedef struct ET_node_s
+{
+  INT maxy;         /* Maximum y for this edge. */
+  INT minx;         /* x coordinate of the lower endpoint (point with the minimum y). */
+  INT dx, dy;        /* Deltas (dy/dx = slope). */
+  INT d;            /* Delta accumulator. */
+  INT xinc;         /* Increment used for updating x coordinates. */
+  struct ET_node_s *next;
+} ET_node_t;
+
+/* Global Edge Table (ET) linked-list of linked-lists (the latter contains edge nodes). */
+typedef struct ET_list_s
+{
+  INT y;           /* Minimum y for the scanline containing an edge. */
+  ET_node_t *edges;
+  struct ET_list_s *next;
+} ET_list_t;
+
+void DIBENG_DrawRGB( dibeng_t *dib, INT x, INT y, COLORREF c );
+COLORREF DIBENG_ReadRGB( dibeng_t *dib, INT x, INT y );
+inline void DIBENG_DrawPixel( dibeng_t *dib, INT x, INT y, UINT c );
+inline UINT DIBENG_ReadPixel( dibeng_t *dib, INT x, INT y );
+void DIBENG_DrawHorzLine( dibeng_t *dib, INT x1, INT x2, INT y );
+void DIBENG_DrawVertLine( dibeng_t *dib, INT x, INT y1, INT y2 );
+void DIBENG_FillRect( dibeng_t *dib, INT x1, INT y1, INT x2, INT y2 );
+void DIBENG_Blit( dibeng_t *dibeng_dst, INT dstx, INT dsty, INT w, INT h, dibeng_t *dibeng_src, INT srcx, INT srcy, DWORD rop );
+/*BOOL DIBENG_PatBlt( DC *dc, INT left, INT top, INT width, INT height, DWORD rop );*/
+
+void DIBENG_Line( dibeng_t *dib, INT x1, INT y1, INT x2, INT y2, BOOL draw_last_point );
+void DIBENG_FillPolygon( dibeng_t *dib, const POINT *points, INT count );
+
+
+/* dibeng_bitmap.c */
+void DIBENG_Draw1BitBitmap( dibeng_t *dib, INT x, INT y, INT width, INT height, const USHORT *bm );
+void DIBENG_DrawBitmap( dibeng_t *dib, INT x, INT y, dibeng_t *bm );
+
+
+#endif    /* __DIBENG_PRIVATE_H__ */
Index: graphics/x11drv/bitblt.c
===================================================================
RCS file: /cvsroot/rewind/rewind/graphics/x11drv/bitblt.c,v
retrieving revision 1.38
diff -u -r1.38 bitblt.c
--- graphics/x11drv/bitblt.c	23 Aug 2002 22:47:29 -0000	1.38
+++ graphics/x11drv/bitblt.c	27 Sep 2002 17:45:54 -0000
@@ -22,6 +22,9 @@
 #include "x11drv.h"
 #include "debugtools.h"
 
+#include "wine/dibeng_main.h"
+extern int usedibeng;
+
 DEFAULT_DEBUG_CHANNEL(bitblt);
 
 
@@ -1477,7 +1480,16 @@
 {
     BOOL result;
 
-    X11DRV_LockDIBSection( dc, DIB_Status_GdiMod, FALSE );
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    BOOL ret;
+	    ret = DIBENG_PatBlt(dc, left, top, width, height, rop);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
+
+    X11DRV_CoerceDIBSection( dc, DIB_Status_GdiMod, FALSE );
     result = BITBLT_InternalStretchBlt( dc, left, top, width, height, NULL, 0, 0, 0, 0, rop );
     X11DRV_UnlockDIBSection( dc, TRUE );
     return result;
Index: graphics/x11drv/bitmap.c
===================================================================
RCS file: /cvsroot/rewind/rewind/graphics/x11drv/bitmap.c,v
retrieving revision 1.35
diff -u -r1.35 bitmap.c
--- graphics/x11drv/bitmap.c	23 Aug 2002 22:47:29 -0000	1.35
+++ graphics/x11drv/bitmap.c	27 Sep 2002 17:45:54 -0000
@@ -20,13 +20,16 @@
 #include "windef.h"
 #include "wine/winuser16.h"
 
+
 DEFAULT_DEBUG_CHANNEL(x11drv);
 
   /* GCs used for B&W and color bitmap operations */
 GC BITMAP_monoGC = 0, BITMAP_colorGC = 0;
 
+
 extern const DC_FUNCTIONS *X11DRV_DC_Funcs;  /* hack */
 
+
 /***********************************************************************
  *           X11DRV_BITMAP_Init
  */
@@ -92,7 +95,7 @@
     if(bmp->funcs != dc->funcs) {
         WARN("Trying to select non-X11 DDB into an X11 dc\n");
         GDI_ReleaseObj( hbitmap );
-	return 0;
+        return 0;
     }
 
     if (!(hrgn = CreateRectRgn(0, 0, bmp->bitmap.bmWidth, bmp->bitmap.bmHeight)))
@@ -100,7 +103,6 @@
         GDI_ReleaseObj( hbitmap );
         return 0;
     }
-
     dc->totalExtent.left   = 0;
     dc->totalExtent.top    = 0;
     dc->totalExtent.right  = bmp->bitmap.bmWidth;
@@ -123,9 +125,10 @@
         XSetSubwindowMode( gdi_display, physDev->gc, IncludeInferiors );
         XFlush( gdi_display );
         wine_tsx11_unlock();
-	dc->bitsPerPixel = bmp->bitmap.bmBitsPixel;
+        dc->bitsPerPixel = bmp->bitmap.bmBitsPixel;
         DC_InitDC( dc );
     }
+
     GDI_ReleaseObj( hbitmap );
     return prevHandle;
 }
@@ -144,11 +147,13 @@
 BOOL X11DRV_CreateBitmap( HBITMAP hbitmap )
 {
     BITMAPOBJ *bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
+    X11DRV_DIBSECTION *dib;
 
     if(!bmp) {
         WARN("Bad bitmap handle %08x\n", hbitmap);
 	return FALSE;
     }
+    dib = (X11DRV_DIBSECTION *) bmp->dib;
 
       /* Check parameters */
     if (bmp->bitmap.bmPlanes != 1)
@@ -167,16 +172,21 @@
     TRACE("(%08x) %dx%d %d bpp\n", hbitmap, bmp->bitmap.bmWidth,
 	  bmp->bitmap.bmHeight, bmp->bitmap.bmBitsPixel);
 
-      /* Create the pixmap */
-    if (!(bmp->physBitmap = (void *)TSXCreatePixmap(gdi_display, root_window,
-                                                    bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
-                                                    bmp->bitmap.bmBitsPixel)))
-    {
-        WARN("Can't create Pixmap\n");
-	GDI_ReleaseObj( hbitmap );
-	return FALSE;
+      /* Create the pixmap if none already created
+       * (could have been creating with create dib section) */
+    if (!bmp->physBitmap)
+    {
+	if (!(bmp->physBitmap = (void *)TSXCreatePixmap(gdi_display, root_window,
+							bmp->bitmap.bmWidth, bmp->bitmap.bmHeight,
+							bmp->bitmap.bmBitsPixel)))
+	{
+		WARN("Can't create Pixmap\n");
+		GDI_ReleaseObj( hbitmap );
+		return FALSE;
+	}
     }
-    bmp->funcs = X11DRV_DC_Funcs;
+    if (!bmp->funcs)
+        bmp->funcs = X11DRV_DC_Funcs;
 
     if (bmp->bitmap.bmBits) /* Set bitmap bits */
 	X11DRV_BitmapBits( hbitmap, bmp->bitmap.bmBits,
@@ -605,4 +615,3 @@
     }
     return pixmap;
 }
-
Index: graphics/x11drv/graphics.c
===================================================================
RCS file: /cvsroot/rewind/rewind/graphics/x11drv/graphics.c,v
retrieving revision 1.42
diff -u -r1.42 graphics.c
--- graphics/x11drv/graphics.c	23 Aug 2002 22:47:29 -0000	1.42
+++ graphics/x11drv/graphics.c	27 Sep 2002 17:45:58 -0000
@@ -34,6 +34,9 @@
 #include "region.h"
 #include "debugtools.h"
 
+#include "wine/dibeng_main.h"
+extern int usedibeng;
+
 DEFAULT_DEBUG_CHANNEL(graphics);
 
 #define ABS(x)    ((x)<0?(-(x)):(x))
@@ -291,9 +294,17 @@
     POINT start;
     POINT end;
 
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+    {
+        BOOL ret;
+        ret = DIBENG_LineTo(dc, x, y);
+        X11DRV_UnlockDIBSection(dc, TRUE);
+        return ret;
+    }
     if (X11DRV_SetupGCForPen( dc )) {
 	/* Update the pixmap from the DIB section */
-	X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+	X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
 	start.x = dc->CursPosX;
 	start.y = dc->CursPosY;
@@ -309,8 +320,8 @@
 		  dc->DCOrgY + end.y);
 
 	/* Update the DIBSection from the pixmap */
-	X11DRV_UnlockDIBSection(dc, TRUE);
     }
+    X11DRV_UnlockDIBSection(dc, TRUE);
     return TRUE;
 }
 
@@ -524,11 +535,24 @@
     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
     BOOL update = FALSE;
 
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    BOOL ret;
+	    ret = DIBENG_Ellipse(dc, left, top, right, bottom);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
+
     left   = XLPTODP( dc, left );
     top    = YLPTODP( dc, top );
     right  = XLPTODP( dc, right );
     bottom = YLPTODP( dc, bottom );
-    if ((left == right) || (top == bottom)) return TRUE;
+    if ((left == right) || (top == bottom))
+    {
+        X11DRV_UnlockDIBSection(dc, FALSE);
+        return TRUE;
+	}
 
     if (right < left) { INT tmp = right; right = left; left = tmp; }
     if (bottom < top) { INT tmp = bottom; bottom = top; top = tmp; }
@@ -550,7 +574,7 @@
     physDev->pen.width = width;
 
     /* Update the pixmap from the DIB section */
-    X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+    X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
     if (X11DRV_SetupGCForBrush( dc ))
     {
@@ -858,12 +882,21 @@
     Pixel pixel;
     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
 
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    COLORREF ret;
+	    ret = DIBENG_SetPixel(dc, x, y, color);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
+
     x = dc->DCOrgX + INTERNAL_XWPTODP( dc, x, y );
     y = dc->DCOrgY + INTERNAL_YWPTODP( dc, x, y );
     pixel = X11DRV_PALETTE_ToPhysical( dc, color );
 
     /* Update the pixmap from the DIB section */
-    X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+    X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
     /* inefficient but simple... */
     wine_tsx11_lock();
@@ -890,8 +923,17 @@
     int pixel;
     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
 
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    COLORREF ret;
+	    ret = DIBENG_GetPixel(dc, x, y);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
+
     /* Update the pixmap from the DIB section */
-    X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+    X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
     x = dc->DCOrgX + INTERNAL_XWPTODP( dc, x, y );
     y = dc->DCOrgY + INTERNAL_YWPTODP( dc, x, y );
@@ -983,12 +1025,23 @@
     register int i;
     XPoint *points;
     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
+    BOOL update = FALSE;
+
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    BOOL ret;
+	    ret = DIBENG_Polyline(dc, pt, count);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
 
     if((oldwidth = physDev->pen.width) == 0) physDev->pen.width = 1;
 
     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * count )))
     {
         WARN("No memory to convert POINTs to XPoints!\n");
+        X11DRV_UnlockDIBSection(dc, FALSE);
         return FALSE;
     }
     for (i = 0; i < count; i++)
@@ -1000,15 +1053,15 @@
     if (X11DRV_SetupGCForPen ( dc ))
     {
 	/* Update the pixmap from the DIB section */
-	X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+	X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
         TSXDrawLines( gdi_display, physDev->drawable, physDev->gc,
                       points, count, CoordModeOrigin );
-
-	/* Update the DIBSection from the pixmap */
-    	X11DRV_UnlockDIBSection(dc, TRUE);
+		update = TRUE;
     }
 
+	/* Update the DIBSection from the pixmap */
+    X11DRV_UnlockDIBSection(dc, update);
     HeapFree( GetProcessHeap(), 0, points );
     physDev->pen.width = oldwidth;
     return TRUE;
@@ -1026,9 +1079,19 @@
     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
     BOOL update = FALSE;
 
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    BOOL ret;
+	    ret = DIBENG_Polygon(dc, pt, count);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
+
     if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (count+1) )))
     {
         WARN("No memory to convert POINTs to XPoints!\n");
+	    X11DRV_UnlockDIBSection(dc, FALSE);
         return FALSE;
     }
     for (i = 0; i < count; i++)
@@ -1039,7 +1102,7 @@
     points[count] = points[0];
 
     /* Update the pixmap from the DIB section */
-    X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+    X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
     if (X11DRV_SetupGCForBrush( dc ))
     {
@@ -1074,6 +1137,15 @@
     /* FIXME: The points should be converted to device coords before */
     /* creating the region. */
 
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    BOOL ret;
+	    ret = DIBENG_PolyPolygon(dc, pt, counts, polygons);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
+
     hrgn = CreatePolyPolygonRgn( pt, counts, polygons, dc->polyFillMode );
     X11DRV_PaintRgn( dc, hrgn );
     DeleteObject( hrgn );
@@ -1086,12 +1158,13 @@
 	XPoint *points;
 
 	/* Update the pixmap from the DIB section */
-	X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+	X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
 	for (i = 0; i < polygons; i++) if (counts[i] > max) max = counts[i];
         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * (max+1) )))
         {
             WARN("No memory to convert POINTs to XPoints!\n");
+	        X11DRV_UnlockDIBSection(dc, FALSE);
             return FALSE;
         }
 	for (i = 0; i < polygons; i++)
@@ -1107,11 +1180,11 @@
                           points, j + 1, CoordModeOrigin );
 	}
 
+	HeapFree( GetProcessHeap(), 0, points );
+    }
 	/* Update the DIBSection of the dc's bitmap */
 	X11DRV_UnlockDIBSection(dc, TRUE);
 
-	HeapFree( GetProcessHeap(), 0, points );
-    }
     return TRUE;
 }
 
@@ -1124,18 +1197,28 @@
 {
     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
 
+    if (X11DRV_LockDIBSection(dc, DIB_Status_None, FALSE)
+        == DIB_Status_AppMod && usedibeng)
+	{
+	    BOOL ret;
+	    ret = DIBENG_PolyPolyline(dc, pt, counts, polylines);
+	    X11DRV_UnlockDIBSection(dc, TRUE);
+	    return ret;
+	}
+
     if (X11DRV_SetupGCForPen ( dc ))
     {
         int i, j, max = 0;
         XPoint *points;
 
 	/* Update the pixmap from the DIB section */
-    	X11DRV_LockDIBSection(dc, DIB_Status_GdiMod, FALSE);
+    	X11DRV_CoerceDIBSection(dc, DIB_Status_GdiMod, FALSE);
 
         for (i = 0; i < polylines; i++) if (counts[i] > max) max = counts[i];
         if (!(points = HeapAlloc( GetProcessHeap(), 0, sizeof(XPoint) * max )))
         {
             WARN("No memory to convert POINTs to XPoints!\n");
+	        X11DRV_UnlockDIBSection(dc, FALSE);
             return FALSE;
         }
         for (i = 0; i < polylines; i++)
@@ -1150,11 +1233,11 @@
 			  points, j, CoordModeOrigin );
         }
 
-	/* Update the DIBSection of the dc's bitmap */
-    	X11DRV_UnlockDIBSection(dc, TRUE);
-
 	HeapFree( GetProcessHeap(), 0, points );
     }
+	/* Update the DIBSection of the dc's bitmap */
+    X11DRV_UnlockDIBSection(dc, TRUE);
+
     return TRUE;
 }
 
Index: include/gdi.h
===================================================================
RCS file: /cvsroot/rewind/rewind/include/gdi.h,v
retrieving revision 1.57
diff -u -r1.57 gdi.h
--- include/gdi.h	23 Aug 2002 22:47:30 -0000	1.57
+++ include/gdi.h	27 Sep 2002 17:46:14 -0000
@@ -117,6 +117,49 @@
     BOOL          vport2WorldValid;  /* Is xformVport2World valid? */
 } DC;
 
+
+
+/* DIBENG engine structure and defines. */
+
+
+/* Device-independent bitmap structure. */
+typedef struct dibeng_s
+{
+  INT width, height;   /* Dimensions of the Memory DC. */
+  INT bpp;             /* Bits per pixel. */
+  INT linelen;         /* Row length. */
+  INT size;            /* Total size (height * linelen). */
+
+  DWORD rmask;         /* RGB masks. */
+  DWORD gmask;
+  DWORD bmask;
+  DWORD rshift;        /* RGB mask shifts. */
+  DWORD gshift;
+  DWORD bshift;
+  DWORD rloss;        /* RGB bits loss. */
+  DWORD gloss;
+  DWORD bloss;
+
+  LPVOID buffer;       /* Address of buffer. */
+
+  DC *dc;              /* Pointer to associated Memory DC. */
+
+  struct dibeng_s *dib_pattern;  /* DIBENG brush pattern; used if brush
+                                 * style is BS_PATTERN or BS_DIBPATTERN. */
+
+  DWORD    ROPmode;     /* DC ROP mode. */
+  COLORREF text_color;  /* Text color. */
+  COLORREF bg_color;    /* Background color. */
+  COLORREF pen_color;   /* Pen (for ROP2 modes) or brush color (for ROP3 modes). */
+  BOOL     use_bg;      /* "Use background color?" flag (transparent otherwise). */
+
+
+  /* Clipping info goes here... */
+
+} dibeng_t;
+
+
+
 /* Device functions for the Wine driver interface */
 
 typedef INT (*DEVICEFONTENUMPROC)(LPENUMLOGFONTEXW,LPNEWTEXTMETRICEXW,DWORD,
Index: include/wine/dibeng_main.h
===================================================================
RCS file: include/wine/dibeng_main.h
diff -N include/wine/dibeng_main.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ include/wine/dibeng_main.h	27 Sep 2002 17:46:46 -0000
@@ -0,0 +1,33 @@
+#ifndef __DIBENG_MAIN_H__
+#define __DIBENG_MAIN_H__
+
+
+#include "gdi.h"
+
+
+/* dibeng_bitmap.c */
+void DIBENG_GetDIBFromDC( DC *dc, dibeng_t *dibeng );
+void DIBENG_ReleaseDIBFromDC( dibeng_t *dibeng );
+void DIBENG_GetDIBFromHBITMAP( DC *dc, HBITMAP hbitmap, dibeng_t *dibeng );
+void DIBENG_ReleaseDIBFromHBITMAP( dibeng_t *dibeng );
+void DIBENG_CreateDIB( dibeng_t *dibeng_in, INT w, INT h, dibeng_t *dibeng_out );
+void DIBENG_DestroyDIB( dibeng_t *dibeng );
+
+/* dibeng_primitives.c */
+UINT DIBENG_RGB2Pixel( dibeng_t *dib, COLORREF rgb );
+COLORREF DIBENG_Pixel2RGB( dibeng_t *dib, UINT pixel );
+
+/* dibeng_main.c */
+BOOL DIBENG_LineTo( DC *dc, INT x, INT y );
+BOOL DIBENG_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom );
+COLORREF DIBENG_GetPixel( DC *dc, INT x, INT y );
+BOOL DIBENG_Polygon( DC *dc, const POINT *pt, INT count );
+BOOL DIBENG_Polyline( DC *dc, const POINT *pt, INT count );
+BOOL DIBENG_PolyPolygon( DC *dc, const POINT *pt, const INT *counts, UINT polygons );
+BOOL DIBENG_PolyPolyline( DC *dc, const POINT *pt, const DWORD *counts, DWORD polylines );
+COLORREF DIBENG_SetPixel( DC *dc, INT x, INT y, COLORREF color );
+BOOL DIBENG_BitBlt( DC *dcDst, INT xDst, INT yDst, INT width, INT height, DC *dcSrc, INT xSrc, INT ySrc, DWORD rop );
+BOOL DIBENG_PatBlt( DC *dc, INT left, INT top, INT width, INT height, DWORD rop );
+
+
+#endif    /* __DIBENG_MAIN_H__ */


More information about the wine-patches mailing list