changeset 1631:0e6c2aeed041

Got anti-aliased drawing working with GDI+ on Windows. Problem was I was specifying 0 in the alpha field making everything drawn invisible. dw_draw_arc() isn't working quite right but the rest appears to be working in anti-aliased mode.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Wed, 28 Mar 2012 18:33:54 +0000
parents 48fabb2f93c5
children fdf874f25076
files win/dw.c
diffstat 1 files changed, 252 insertions(+), 95 deletions(-) [+]
line wrap: on
line diff
--- a/win/dw.c	Wed Mar 28 16:29:35 2012 +0000
+++ b/win/dw.c	Wed Mar 28 18:33:54 2012 +0000
@@ -99,8 +99,25 @@
   FlushIntentionSync    = 1 
 } GpFlushIntention;
 
+typedef enum {
+  QualityModeInvalid  = -1,
+  QualityModeDefault  = 0,
+  QualityModeLow      = 1,
+  QualityModeHigh     = 2
+} QualityMode;
+
+typedef enum  {
+  SmoothingModeInvalid     = QualityModeInvalid,
+  SmoothingModeDefault     = QualityModeDefault,
+  SmoothingModeHighSpeed   = QualityModeLow,
+  SmoothingModeHighQuality = QualityModeHigh,
+  SmoothingModeNone,
+  SmoothingModeAntiAlias
+} SmoothingMode;
+
 typedef void GpGraphics;
 typedef void GpPen;
+typedef void GpBrush;
 typedef void GpBitmap;
 typedef void GpImage;
 typedef POINT GpPoint;
@@ -131,11 +148,22 @@
 /* Drawing functions */
 GpStatus WINAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics);
 GpStatus WINAPI GdipCreateFromHWND(HWND hwnd, GpGraphics **graphics);
+GpStatus WINAPI GdipDeleteGraphics(GpGraphics *graphics);
+GpStatus WINAPI GdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode);
+GpStatus WINAPI GdipCreatePen1(ARGB color, REAL width, GpUnit unit, GpPen **pen);
+GpStatus WINAPI GdipDeletePen(GpPen *pen);
+GpStatus WINAPI GdipCreateSolidFill(ARGB color, GpBrush **brush);
+GpStatus WINAPI GdipDeleteBrush(GpBrush *brush);
+GpStatus WINAPI GdipSetSolidFillColor(GpBrush *brush, ARGB color);
 GpStatus WINAPI GdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1, INT x2, INT y2);
 GpStatus WINAPI GdipDrawLinesI(GpGraphics *graphics, GpPen *pen, const GpPoint *points, INT count);
-GpStatus WINAPI GdipDeleteGraphics(GpGraphics *graphics);
-GpStatus WINAPI GdipCreatePen1(ARGB color, REAL width, GpUnit unit, GpPen **pen);
-GpStatus WINAPI GdipDeletePen(GpPen *pen);
+GpStatus WINAPI GdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height);
+GpStatus WINAPI GdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height);
+GpStatus WINAPI GdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);
+GpStatus WINAPI GdipDrawPolygonI(GpGraphics *graphics, GpPen *pen, const GpPoint *points, INT count);
+GpStatus WINAPI GdipFillPolygon2I(GpGraphics *graphics, GpBrush *brush, const GpPoint *points, INT count);
+GpStatus WINAPI GdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, INT y, INT width, INT height);
+GpStatus WINAPI GdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, INT y, INT width, INT height);
 GpStatus WINAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention);
 
 /* Pixel format information */
@@ -246,6 +274,7 @@
 DWORD _hBrush;
 #ifdef GDIPLUS
 DWORD _gpPen;
+DWORD _gpBrush;
 #endif
 
 BYTE _red[] = {   0x00, 0xbb, 0x00, 0xaa, 0x00, 0xbb, 0x00, 0xaa, 0x77,
@@ -3778,11 +3807,14 @@
     COLORREF foreground = RGB(128,128,128);
     COLORREF background = DW_RGB_TRANSPARENT;
 #ifdef GDIPLUS
-    ARGB gpfore = MAKEARGB(0, 128, 128, 128);
+    ARGB gpfore = MAKEARGB(255, 128, 128, 128);
+    GpBrush *brush;
     GpPen *pen;
     
     GdipCreatePen1(gpfore, 1.0, UnitPixel, &pen);
     TlsSetValue(_gpPen, (LPVOID)pen);
+    GdipCreateSolidFill(gpfore, &brush);
+    TlsSetValue(_gpBrush, (LPVOID)brush);
 #endif    
     TlsSetValue(_foreground, (LPVOID)foreground);
     TlsSetValue(_background, (LPVOID)background);
@@ -3829,6 +3861,7 @@
    _hBrush = TlsAlloc();
 #ifdef GDIPLUS
    _gpPen = TlsAlloc();
+   _gpBrush = TlsAlloc();
 #endif   
 
    icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
@@ -9564,6 +9597,7 @@
    HBRUSH hBrush = TlsGetValue(_hBrush);
    COLORREF foreground;
 #ifdef GDIPLUS
+   GpBrush *brush = TlsGetValue(_gpBrush);
    GpPen *pen = TlsGetValue(_gpPen);
    ARGB gpfore;
 #endif
@@ -9571,11 +9605,12 @@
    value = _internal_color(value);
    foreground = RGB(DW_RED_VALUE(value), DW_GREEN_VALUE(value), DW_BLUE_VALUE(value));
 #ifdef GDIPLUS
-   gpfore = MAKEARGB(0, DW_RED_VALUE(value), DW_GREEN_VALUE(value), DW_BLUE_VALUE(value));
+   gpfore = MAKEARGB(255, DW_RED_VALUE(value), DW_GREEN_VALUE(value), DW_BLUE_VALUE(value));
    
    GdipDeletePen(pen);
    GdipCreatePen1(gpfore, 1.0, UnitPixel, &pen);
    TlsSetValue(_gpPen, (LPVOID)pen);
+   GdipSetSolidFillColor(brush, gpfore);
 #endif    
 
    DeleteObject(hPen);
@@ -9666,7 +9701,7 @@
  */
 void API dw_draw_line(HWND handle, HPIXMAP pixmap, int x1, int y1, int x2, int y2)
 {
-#ifdef GDIPLUS1
+#ifdef GDIPLUS
    GpGraphics *graphics = NULL;
    GpPen *pen = TlsGetValue(_gpPen);
    
@@ -9677,8 +9712,8 @@
    else
       return;
    
+   GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias);
    GdipDrawLineI(graphics, pen, x1, y1, x2, y2);
-   GdipFlush(graphics, FlushIntentionSync);
    GdipDeleteGraphics(graphics);
 #else
    HDC hdcPaint;
@@ -9704,6 +9739,39 @@
 #endif
 }
 
+/* Internal function to generate POINT arrays used by Windows APIs */
+POINT *_makePoints(int *npoints, int *x, int *y)
+{
+   POINT *points;
+   int i;
+   
+   /*
+    * Allocate enough space for the number of points supplied plus 1.
+    * Under windows, unless the first and last points are the same
+    * the polygon won't be closed
+    */
+   points = (POINT *)malloc( ((*npoints)+1) * sizeof(POINT) );
+   
+   if(points)
+   {
+      for ( i = 0 ; i < *npoints ; i++ )
+      {
+         points[i].x = x[i];
+         points[i].y = y[i];
+      }
+      if ( !( points[0].x == points[(*npoints)-1].x
+      &&   points[0].y == points[(*npoints)-1].y ) )
+      {
+         /* set the last point to be the same as the first point... */
+         points[*npoints].x = points[0].x;
+         points[*npoints].y = points[0].y;
+         /* ... and increment the number of points */
+         (*npoints)++;
+      }
+   }
+   return points;
+}
+
 /* Draw a closed polygon on a window (preferably a render window).
  * Parameters:
  *       handle: Handle to the window.
@@ -9715,58 +9783,73 @@
  */
 void API dw_draw_polygon(HWND handle, HPIXMAP pixmap, int flags, int npoints, int *x, int *y)
 {
-   HDC hdcPaint;
-   HBRUSH oldBrush;
-   HPEN oldPen;
    POINT *points = NULL;
-   int i;
-
-   if ( handle )
-      hdcPaint = GetDC( handle );
-   else if ( pixmap )
-      hdcPaint = pixmap->hdc;
-   else
+   
+   /* Sanity check */
+   if(npoints < 1)
       return;
-   if ( npoints )
-   {
-      /*
-       * Allocate enough space for the number of points supplied plus 1.
-       * Under windows, unless the first and last points are the same
-       * the polygon won't be closed
-       */
-      points = (POINT *)malloc( (npoints+1) * sizeof(POINT) );
-      /*
-       * should check for NULL pointer return!
-       */
-      for ( i = 0 ; i < npoints ; i++ )
-      {
-         points[i].x = x[i];
-         points[i].y = y[i];
-      }
-      if ( !( points[0].x == points[npoints-1].x
-      &&   points[0].y == points[npoints-1].y ) )
-      {
-         /* set the last point to be the same as the first point... */
-         points[npoints].x = points[0].x;
-         points[npoints].y = points[0].y;
-         /* ... and increment the number of points */
-         npoints++;
-      }
+
+#ifdef GDIPLUS
+   if(!(flags & DW_DRAW_NOAA))
+   {
+      GpGraphics *graphics = NULL;
+      
+      if(handle)
+         GdipCreateFromHWND(handle, &graphics);
+      else if(pixmap)
+         GdipCreateFromHDC(pixmap->hdc, &graphics);
+      else
+         return;
+      
+      GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias);
+      if((points = _makePoints(&npoints, x, y)))
+      {
+         if(flags & DW_DRAW_FILL)
+         {
+            GpBrush *brush = TlsGetValue(_gpBrush);
+            
+            GdipFillPolygon2I(graphics, brush, points, npoints);
+         }
+         else
+         {
+            GpPen *pen = TlsGetValue(_gpPen);
+            
+            GdipDrawPolygonI(graphics, pen, points, npoints);
+         }
+      }
+      GdipDeleteGraphics(graphics);
    }
    else
-      return;
-
-   oldBrush = SelectObject( hdcPaint, TlsGetValue(_hBrush) );
-   oldPen = SelectObject( hdcPaint, TlsGetValue(_hPen) );
-   if ( flags & DW_DRAW_FILL )
-      Polygon( hdcPaint, points, npoints );
-   else
-      Polyline( hdcPaint, points, npoints );
-   SelectObject( hdcPaint, oldBrush );
-   SelectObject( hdcPaint, oldPen );
-   if ( !pixmap )
-      ReleaseDC( handle, hdcPaint );
-   free(points);
+#endif   
+   {
+      HDC hdcPaint;
+      
+      if ( handle )
+         hdcPaint = GetDC( handle );
+      else if ( pixmap )
+         hdcPaint = pixmap->hdc;
+      else 
+         return;
+
+      if((points = _makePoints(&npoints, x, y)))
+      {
+         HBRUSH oldBrush = SelectObject( hdcPaint, TlsGetValue(_hBrush) );
+         HPEN oldPen = SelectObject( hdcPaint, TlsGetValue(_hPen) );
+      
+         if ( flags & DW_DRAW_FILL )
+            Polygon( hdcPaint, points, npoints );
+         else
+            Polyline( hdcPaint, points, npoints );
+            
+         SelectObject( hdcPaint, oldBrush );
+         SelectObject( hdcPaint, oldPen );
+      }
+      
+      if ( !pixmap )
+         ReleaseDC( handle, hdcPaint );
+   }
+   if(points)
+      free(points);
 }
 
 /* Draw a rectangle on a window (preferably a render window).
@@ -9781,23 +9864,54 @@
  */
 void API dw_draw_rect(HWND handle, HPIXMAP pixmap, int flags, int x, int y, int width, int height)
 {
-   HDC hdcPaint;
-   RECT Rect;
-
-   if(handle)
-      hdcPaint = GetDC(handle);
-   else if(pixmap)
-      hdcPaint = pixmap->hdc;
+ #ifdef GDIPLUS
+   if(!(flags & DW_DRAW_NOAA))
+   {
+      GpGraphics *graphics = NULL;
+      
+      if(handle)
+         GdipCreateFromHWND(handle, &graphics);
+      else if(pixmap)
+         GdipCreateFromHDC(pixmap->hdc, &graphics);
+      else
+         return;
+      
+      GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias);
+      if(flags & DW_DRAW_FILL)
+      {
+         GpBrush *brush = TlsGetValue(_gpBrush);
+      
+         GdipFillRectangleI(graphics, brush, x, y, width, height);
+      }
+      else
+      {
+         GpPen *pen = TlsGetValue(_gpPen);
+         
+         GdipDrawRectangleI(graphics, pen, x, y, width, height);
+      }
+      GdipDeleteGraphics(graphics);
+   }
    else
-      return;
-
-   SetRect(&Rect, x, y, x + width , y + height );
-   if(flags & DW_DRAW_FILL)
-      FillRect(hdcPaint, &Rect, TlsGetValue(_hBrush));
-   else
-      FrameRect(hdcPaint, &Rect, TlsGetValue(_hBrush));
-   if(!pixmap)
-      ReleaseDC(handle, hdcPaint);
+#endif   
+   {
+      HDC hdcPaint;
+      RECT Rect;
+
+      if(handle)
+         hdcPaint = GetDC(handle);
+      else if(pixmap)
+         hdcPaint = pixmap->hdc;
+      else
+         return;
+
+      SetRect(&Rect, x, y, x + width , y + height );
+      if(flags & DW_DRAW_FILL)
+         FillRect(hdcPaint, &Rect, TlsGetValue(_hBrush));
+      else
+         FrameRect(hdcPaint, &Rect, TlsGetValue(_hBrush));
+      if(!pixmap)
+         ReleaseDC(handle, hdcPaint);
+   }
 }
 
 /* Draw an arc on a window (preferably a render window).
@@ -9815,34 +9929,74 @@
  */
 void API dw_draw_arc(HWND handle, HPIXMAP pixmap, int flags, int xorigin, int yorigin, int x1, int y1, int x2, int y2)
 {
-   HDC hdcPaint;
-   HBRUSH oldBrush;
-   HPEN oldPen;
    double dx = xorigin - x1;
    double dy = yorigin - y1;
    double r = sqrt(dx*dx + dy*dy);
-
-   if(handle)
-      hdcPaint = GetDC(handle);
-   else if(pixmap)
-      hdcPaint = pixmap->hdc;
-   else
-      return;
-     
-   if(flags & DW_DRAW_FILL)     
-      oldBrush = SelectObject( hdcPaint, TlsGetValue(_hBrush) );
+   int ri = (int)r;
+
+#ifdef GDIPLUS
+   if(!(flags & DW_DRAW_NOAA))
+   {
+      GpGraphics *graphics = NULL;
+      GpPen *pen = TlsGetValue(_gpPen);
+      
+      if(handle)
+         GdipCreateFromHWND(handle, &graphics);
+      else if(pixmap)
+         GdipCreateFromHDC(pixmap->hdc, &graphics);
+      else
+         return;
+      
+      GdipSetSmoothingMode(graphics, SmoothingModeAntiAlias);
+      if(flags & DW_DRAW_FULL)
+      {
+         if(flags & DW_DRAW_FILL)
+         {
+            GpBrush *brush = TlsGetValue(_gpBrush);
+         
+            GdipFillEllipseI(graphics, brush, xorigin-ri, yorigin-ri, xorigin+ri, yorigin+ri);
+         }
+         else
+            GdipDrawEllipseI(graphics, pen, xorigin-ri, yorigin-ri, xorigin+ri, yorigin+ri);
+      }
+      else
+      {
+         double a1 = atan2((y1-yorigin), (x1-xorigin));
+         double a2 = atan2((y2-yorigin), (x2-xorigin));
+         
+         GdipDrawArcI(graphics, pen, xorigin-ri, yorigin-ri, xorigin+ri, yorigin+ri, (REAL)a1, (REAL)a2);
+      }
+      GdipDeleteGraphics(graphics);
+   }
    else
-      oldBrush = SelectObject( hdcPaint, GetStockObject(HOLLOW_BRUSH) );
-   oldPen = SelectObject( hdcPaint, TlsGetValue(_hPen) );
-   if(flags & DW_DRAW_FULL)
-      Ellipse(hdcPaint, x1, y1, x2, y2);
-   else
-      Arc(hdcPaint, xorigin-(int)r, yorigin-(int)r, xorigin+(int)r, yorigin+(int)r, x2, y2, x1, y1);
-   SelectObject( hdcPaint, oldBrush );
-   SelectObject( hdcPaint, oldPen );
-
-   if(!pixmap)
-      ReleaseDC(handle, hdcPaint);
+#endif   
+   {
+      HDC hdcPaint;
+      HBRUSH oldBrush;
+      HPEN oldPen;
+      
+      if(handle)
+         hdcPaint = GetDC(handle);
+      else if(pixmap)
+         hdcPaint = pixmap->hdc;
+      else
+         return;
+        
+      if(flags & DW_DRAW_FILL)     
+         oldBrush = SelectObject( hdcPaint, TlsGetValue(_hBrush) );
+      else
+         oldBrush = SelectObject( hdcPaint, GetStockObject(HOLLOW_BRUSH) );
+      oldPen = SelectObject( hdcPaint, TlsGetValue(_hPen) );
+      if(flags & DW_DRAW_FULL)
+         Ellipse(hdcPaint, x1, y1, x2, y2);
+      else
+         Arc(hdcPaint, xorigin-(int)r, yorigin-(int)r, xorigin+(int)r, yorigin+(int)r, x2, y2, x1, y1);
+      SelectObject( hdcPaint, oldBrush );
+      SelectObject( hdcPaint, oldPen );
+
+      if(!pixmap)
+         ReleaseDC(handle, hdcPaint);
+  }
 }
 
 /* Draw text on a window (preferably a render window).
@@ -10751,6 +10905,7 @@
    HPEN hPen;
    HBRUSH hBrush;
 #ifdef GDIPLUS
+   GpBrush *brush;
    GpPen *pen;
 #endif       
 
@@ -10765,6 +10920,8 @@
    if((hBrush = TlsGetValue(_hBrush)))
        DeleteObject(hBrush);
 #ifdef GDIPLUS
+   if((brush = TlsGetValue(_gpBrush)))
+      GdipDeleteBrush(brush);
    if((pen = TlsGetValue(_gpPen)))
       GdipDeletePen(pen);
 #endif