Reimplement GdiGradientFill

arjen at nienhuisbeheer.nl arjen at nienhuisbeheer.nl
Thu Jun 5 17:22:37 CDT 2003


This new implementation:
- uses integer math only (great for embededWine TM)
- is pixel perfect (triangles now connect)
- allows any order for the coordinates
- maintains the order of the input array
- can Fill more than one Gradient in one call
- is shorter
- is more easy to read
- uses the wrong indentation style
- uses SetPixel extensively (great for bencmarks)
- plays your old CD's as well as your new DVD's and Super Audio CD's
- still doesn't check its input
- won't be used either

Arjen Nienhuis
-------------- next part --------------
Index: graphics/painting.c
===================================================================
RCS file: /home/wine/wine/graphics/painting.c,v
retrieving revision 1.57
diff -u -r1.57 painting.c
--- graphics/painting.c	13 May 2003 00:41:58 -0000	1.57
+++ graphics/painting.c	5 Jun 2003 21:51:17 -0000
@@ -1072,196 +1072,126 @@
 BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
                           void * grad_array, ULONG ngrad, ULONG mode )
 {
-  int i,j,y,x,t;
-  GRADIENT_RECT *rect;
-  GRADIENT_TRIANGLE *triangle;
-  double ired,igreen,iblue;
-  double red, green,blue;
-  double dx1,dx2,dx3;
-  double dr1,dr2,dr3;
-  double dg1,dg2,dg3;
-  double db1,db2,db3;
-  double sx,sy,sr,sg,sb;
-  double ex,ey,er,eb,eg;
-  double px,py,pr,pb,pg;
+  int i;
 
-  TRACE("vert_array:0x%08lx nvert:%ld grad_array:0x%08lx ngrad:%ld\n",(long)vert_array,nvert,(long)grad_array,ngrad);
+  TRACE("vert_array:0x%08lx nvert:%ld grad_array:0x%08lx ngrad:%ld\n",
+        (long)vert_array, nvert, (long)grad_array, ngrad);
 
-  switch(mode) {
-  case GRADIENT_FILL_RECT_H:
-    for(i=0;i<ngrad;i++) {
-      rect = (GRADIENT_RECT*)((long)grad_array+i*sizeof(GRADIENT_RECT));
-      y = vert_array[rect->UpperLeft].y;
-      /* Precompute some stuffs to speed up a little bit */
-      ired   = (double)(vert_array[rect->LowerRight].Red - vert_array[rect->UpperLeft].Red) / (double)(vert_array[rect->LowerRight].x - vert_array[rect->UpperLeft].x);
-      igreen = (double)(vert_array[rect->LowerRight].Green - vert_array[rect->UpperLeft].Green) / (double)(vert_array[rect->LowerRight].x - vert_array[rect->UpperLeft].x);
-      iblue  = (double)(vert_array[rect->LowerRight].Blue - vert_array[rect->UpperLeft].Blue) / (double)(vert_array[rect->LowerRight].x - vert_array[rect->UpperLeft].x);
-      red = vert_array[rect->UpperLeft].Red;
-      green = vert_array[rect->UpperLeft].Green;
-      blue = vert_array[rect->UpperLeft].Blue;
-      /* Draw the first line */
-      for (j=vert_array[rect->UpperLeft].x; j<=vert_array[rect->LowerRight].x; j++) {	
-	SetPixel(hdc,j,y,RGB(((int)red)>>8,((int)green)>>8,((int)blue)>>8));
-	red   += ired;
-	green += igreen;
-	blue  += iblue;
-      }
-      /* Extends to the correct size */
-      StretchBlt(hdc,vert_array[rect->UpperLeft].x, y+1,(vert_array[rect->LowerRight].x - vert_array[rect->UpperLeft].x), (vert_array[rect->LowerRight].y - y - 1),
-		 hdc,vert_array[rect->UpperLeft].x, y , (vert_array[rect->LowerRight].x - vert_array[rect->UpperLeft].x), 1, SRCCOPY);
-    }
-    break;
-  case GRADIENT_FILL_RECT_V:
-    for(i=0;i<ngrad;i++) {
-      rect = (GRADIENT_RECT*)((long)grad_array+i*sizeof(GRADIENT_RECT));
-      x = vert_array[rect->UpperLeft].x;
-      /* Precompute some stuffs to speed up a little bit */
-      ired   = (double)(vert_array[rect->LowerRight].Red - vert_array[rect->UpperLeft].Red) / (double)(vert_array[rect->LowerRight].y - vert_array[rect->UpperLeft].y);
-      igreen = (double)(vert_array[rect->LowerRight].Green - vert_array[rect->UpperLeft].Green) / (double)(vert_array[rect->LowerRight].y - vert_array[rect->UpperLeft].y);
-      iblue  = (double)(vert_array[rect->LowerRight].Blue - vert_array[rect->UpperLeft].Blue) / (double)(vert_array[rect->LowerRight].y - vert_array[rect->UpperLeft].y);
-      red = vert_array[rect->UpperLeft].Red;
-      green = vert_array[rect->UpperLeft].Green;
-      blue = vert_array[rect->UpperLeft].Blue;
-      /* Draw the first line */
-      for (j=vert_array[rect->UpperLeft].y; j<=vert_array[rect->LowerRight].y; j++) {	
-	SetPixel(hdc,x,j,RGB(((int)red)>>8,((int)green)>>8,((int)blue)>>8));
-	red   += ired;
-	green += igreen;
-	blue  += iblue;
-      }
-      /* Extends to the correct size */
-      StretchBlt(hdc,x+1,vert_array[rect->UpperLeft].y,
-		 (vert_array[rect->LowerRight].x - vert_array[rect->UpperLeft].x) - 1, (vert_array[rect->LowerRight].y - vert_array[rect->UpperLeft].y),
-		 hdc, x, vert_array[rect->UpperLeft].y, 1, (vert_array[rect->LowerRight].y - vert_array[rect->UpperLeft].y), SRCCOPY);
-    }
-    break;
-  case GRADIENT_FILL_TRIANGLE:
-    /*
-     * Based on gouraud shading
-     * Do it for each triangle
-     */
-    for(i=0;i<ngrad;i++) {
-      triangle = (GRADIENT_TRIANGLE*)((long)grad_array+i*sizeof(GRADIENT_TRIANGLE));      
-      /* Sort the points */
-      if (vert_array[triangle->Vertex1].y>vert_array[triangle->Vertex2].y) {
-	/* swap 1 and 2 */
-	t = triangle->Vertex2;
-	triangle->Vertex2 = triangle->Vertex1;
-	triangle->Vertex1 = t;
-      }
-      if (vert_array[triangle->Vertex2].y>vert_array[triangle->Vertex3].y) {
-	/* swap 2 and 3 */
-	t = triangle->Vertex3;
-	triangle->Vertex3 = triangle->Vertex2;
-	triangle->Vertex2 = t;
-      }
-      if (vert_array[triangle->Vertex1].y>vert_array[triangle->Vertex2].y) {
-	/* swap 1 and 2 */
-	t = triangle->Vertex2;
-	triangle->Vertex2 = triangle->Vertex1;
-	triangle->Vertex1 = t;
-      }
-      /* precompute some interpolation stuffs */
-      if (vert_array[triangle->Vertex2].y>vert_array[triangle->Vertex1].y) {
-	dx1 = (double)(vert_array[triangle->Vertex2].x - vert_array[triangle->Vertex1].x) / (double)(vert_array[triangle->Vertex2].y - vert_array[triangle->Vertex1].y );
-	dr1 = (double)(vert_array[triangle->Vertex2].Red - vert_array[triangle->Vertex1].Red) / (double)(vert_array[triangle->Vertex2].y - vert_array[triangle->Vertex1].y );
-	dg1 = (double)(vert_array[triangle->Vertex2].Green - vert_array[triangle->Vertex1].Green) / (double)(vert_array[triangle->Vertex2].y - vert_array[triangle->Vertex1].y );
-	db1 = (double)(vert_array[triangle->Vertex2].Blue - vert_array[triangle->Vertex1].Blue) / (double)(vert_array[triangle->Vertex2].y - vert_array[triangle->Vertex1].y );
-      } else
-	dx1=dr1=dg1=db1=0;
-      
-      if (vert_array[triangle->Vertex3].y>vert_array[triangle->Vertex1].y) {
-	dx2 = (double)(vert_array[triangle->Vertex3].x - vert_array[triangle->Vertex1].x) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex1].y );
-	dr2 = (double)(vert_array[triangle->Vertex3].Red - vert_array[triangle->Vertex1].Red) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex1].y );
-	dg2 = (double)(vert_array[triangle->Vertex3].Green - vert_array[triangle->Vertex1].Green) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex1].y );
-	db2 = (double)(vert_array[triangle->Vertex3].Blue - vert_array[triangle->Vertex1].Blue) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex1].y );
-      } else
-	dx2=dr2=dg2=db2=0;
+  switch(mode) 
+    {
+    case GRADIENT_FILL_RECT_H:
+      for(i = 0; i < ngrad; i++) 
+        {
+          GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
+          TRIVERTEX *v1 = vert_array + rect->UpperLeft;
+          TRIVERTEX *v2 = vert_array + rect->LowerRight;
+          int y1 = v1->y < v2->y ? v1->y : v2->y;
+          int y2 = v2->y > v1->y ? v2->y : v1->y;
+          int x, y, dx;
+          if (v1->x > v2->x)
+            {
+              TRIVERTEX *t = v2;
+              v2 = v1;
+              v1 = t;
+            }
+          dx = v2->x - v1->x;
+          for (x = 0; x < dx; x++)
+            {
+              for (y = y1; y < y2; y++)
+                SetPixel (hdc, x + v1->x, y, RGB(
+                  (v1->Red   * (dx - x) + v2->Red   * x) / dx >> 8,
+                  (v1->Green * (dx - x) + v2->Green * x) / dx >> 8,
+                  (v1->Blue  * (dx - x) + v2->Blue  * x) / dx >> 8));
+            }
+        }
+      break;
+    case GRADIENT_FILL_RECT_V:
+      for(i = 0; i < ngrad; i++) 
+        {
+          GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
+          TRIVERTEX *v1 = vert_array + rect->UpperLeft;
+          TRIVERTEX *v2 = vert_array + rect->LowerRight;
+          int x1 = v1->x < v2->x ? v1->x : v2->x;
+          int x2 = v2->x > v1->x ? v2->x : v1->x;
+          int x, y, dy;
+          if (v1->y > v2->y)
+            {
+              TRIVERTEX *t = v2;
+              v2 = v1;
+              v1 = t;
+            }
+          dy = v2->y - v1->y;
+          for (y = 0; y < dy; y++)
+            {
+              for (x = x1; x < x2; x++)
+                SetPixel (hdc, x, y + v1->y, RGB(
+                  (v1->Red   * (dy - y) + v2->Red   * y) / dy >> 8,
+                  (v1->Green * (dy - y) + v2->Green * y) / dy >> 8,
+                  (v1->Blue  * (dy - y) + v2->Blue  * y) / dy >> 8));
+            }
+        }
+      break;
+    case GRADIENT_FILL_TRIANGLE:
+      for (i = 0; i < ngrad; i++)  
+        {
+          GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
+          TRIVERTEX *v1 = vert_array + tri->Vertex1;
+          TRIVERTEX *v2 = vert_array + tri->Vertex2;
+          TRIVERTEX *v3 = vert_array + tri->Vertex3;
+          int y, dy;
+          
+          if (v1->y > v2->y)
+            { TRIVERTEX *t = v1; v1 = v2; v2 = t; }
+          if (v2->y > v3->y)
+            {
+              TRIVERTEX *t = v2; v2 = v3; v3 = t;
+              if (v1->y > v2->y)
+                { t = v1; v1 = v2; v2 = t; }
+            }
+          /* v1->y <= v2->y <= v3->y */
 
-      if (vert_array[triangle->Vertex3].y>vert_array[triangle->Vertex2].y) {
-	dx3 = (double)(vert_array[triangle->Vertex3].x - vert_array[triangle->Vertex2].x) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex2].y );
-	dr3 = (double)(vert_array[triangle->Vertex3].Red - vert_array[triangle->Vertex2].Red) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex2].y );
-	dg3 = (double)(vert_array[triangle->Vertex3].Green - vert_array[triangle->Vertex2].Green) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex2].y );
-	db3 = (double)(vert_array[triangle->Vertex3].Blue - vert_array[triangle->Vertex2].Blue) / (double)(vert_array[triangle->Vertex3].y - vert_array[triangle->Vertex2].y );
-      } else
-	dx3=dr3=dg3=db3=0;
+          dy = v3->y - v1->y;
+          for (y = 0; y < dy; y++)
+            {
+              /* v1->y <= y < v3->y */
+              TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
+              /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
+              int dy2 = v2->y - v->y;
+              int y2 = y + v1->y - v->y;
 
-      /* backup the topmost point */
-      sx=vert_array[triangle->Vertex1].x;sy=vert_array[triangle->Vertex1].y;
-      sr=vert_array[triangle->Vertex1].Red;sg=vert_array[triangle->Vertex1].Green;sb=vert_array[triangle->Vertex1].Blue;
-      ex=sx;ey=sy;er=sr;eg=sg;eb=sb;
-
-      if (dx1 > dx2) {
-	for (;sy<vert_array[triangle->Vertex2].y;sy++,ey++) {
-	  if ((ex-sx)>0) {
-	    ired = (double)(er - sr) / (double)(ex - sx);
-	    igreen = (double)(eg - sg) / (double)(ex - sx);
-	    iblue = (double)(eb - sb) / (double)(ex - sx);
-	  } else
-	    ired=igreen=iblue=0;
-	  px=sx;py=sy;pr=sr;pg=sg;pb=sb;
-	  for(;px<ex;px++) {
-	    SetPixel(hdc,px,py,RGB((int)pr>>8,(int)pg>>8,(int)pb>>8));
-	    pr += ired; pg += igreen; pb += iblue;
-	  }
-	  sx+=dx2;sr+=dr2;sg+=dg2;sb+=db2;
-	  ex+=dx1;er+=dr1;eg+=dg1;eb+=db1;
-	}
-	ex=vert_array[triangle->Vertex2].x;ey=vert_array[triangle->Vertex2].y;
-	er=vert_array[triangle->Vertex2].Red;eg=vert_array[triangle->Vertex2].Green;eb=vert_array[triangle->Vertex2].Blue;
-	for (;sy<=vert_array[triangle->Vertex3].y;sy++,ey++) {
-	  if ((ex-sx)>0) {
-	    ired = (double)(er - sr) / (double)(ex - sx);
-	    igreen = (double)(eg - sg) / (double)(ex - sx);
-	    iblue = (double)(eb - sb) / (double)(ex - sx);
-	  } else
-	    ired=igreen=iblue=0;
-	  px=sx;py=sy;pr=sr;pg=sg;pb=sb;
-	  for(;px<ex;px++) {
-	    SetPixel(hdc,px,py,RGB((int)pr>>8,(int)pg>>8,(int)pb>>8));
-	    pr += ired; pg += igreen; pb += iblue;
-	  }
-	  sx+=dx2;sr+=dr2;sg+=dg2;sb+=db2;
-	  ex+=dx3;er+=dr3;eg+=dg3;eb+=db3;
-	}      
-      } else {
-	for (;sy<vert_array[triangle->Vertex2].y;sy++,ey++) {
-	  if ((ex-sx)>0) {
-	    ired = (double)(er - sr) / (double)(ex - sx);
-	    igreen = (double)(eg - sg) / (double)(ex - sx);
-	    iblue = (double)(eb - sb) / (double)(ex - sx);
-	  } else
-	    ired=igreen=iblue=0;
-	  px=ex;py=ey;pr=er;pg=eg;pb=eb;
-	  for(;px<ex;px++) {
-	    SetPixel(hdc,px,py,RGB((int)pr>>8,(int)pg>>8,(int)pb>>8));
-	    pr += ired; pg += igreen; pb += iblue;
-	  }
-	  sx+=dx1;sr+=dr1;sg+=dg1;sb+=db1;
-	  ex+=dx2;er+=dr2;eg+=dg2;eb+=db2;
-	}
-	sx=vert_array[triangle->Vertex2].x;sy=vert_array[triangle->Vertex2].y;
-	sr=vert_array[triangle->Vertex2].Red;sg=vert_array[triangle->Vertex2].Green;sb=vert_array[triangle->Vertex2].Blue;
-	for (;sy<=vert_array[triangle->Vertex3].y;sy++,ey++) {
-	  if ((ex-sx)<0) {
-	    ired = (double)(er - sr) / (double)(ex - sx);
-	    igreen = (double)(eg - sg) / (double)(ex - sx);
-	    iblue = (double)(eb - sb) / (double)(ex - sx);
-	  } else
-	    ired=igreen=iblue=0;
-	  px=ex;py=ey;pr=er;pg=eg;pb=eb;
-	  for(;px<sx;px++) {
-	    SetPixel(hdc,px,py,RGB((int)pr>>8,(int)pg>>8,(int)pb>>8));
-	    pr += ired; pg += igreen; pb += iblue;
-	  }
-	  sx+=dx3;sr+=dr3;sg+=dg3;sb+=db3;
-	  ex+=dx2;er+=dr2;eg+=dg2;eb+=db2;
-	}
-      }
-    }
-    break;
-  default:
-    return FALSE;
+              int x1 = (v3->x     * y  + v1->x     * (dy  - y )) / dy;
+              int x2 = (v2->x     * y2 + v-> x     * (dy2 - y2)) / dy2;
+              int r1 = (v3->Red   * y  + v1->Red   * (dy  - y )) / dy;
+              int r2 = (v2->Red   * y2 + v-> Red   * (dy2 - y2)) / dy2;
+              int g1 = (v3->Green * y  + v1->Green * (dy  - y )) / dy;
+              int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
+              int b1 = (v3->Blue  * y  + v1->Blue  * (dy  - y )) / dy;
+              int b2 = (v2->Blue  * y2 + v-> Blue  * (dy2 - y2)) / dy2;
+               
+              int x;
+	      if (x1 < x2)
+                {
+                  int dx = x2 - x1;
+                  for (x = 0; x < dx; x++)
+                    SetPixel (hdc, x + x1, y + v1->y, RGB(
+                      (r1 * (dx - x) + r2 * x) / dx >> 8,
+                      (g1 * (dx - x) + g2 * x) / dx >> 8,
+                      (b1 * (dx - x) + b2 * x) / dx >> 8));
+                }
+              else
+                {
+                  int dx = x1 - x2;
+                  for (x = 0; x < dx; x++)
+                    SetPixel (hdc, x + x2, y + v1->y, RGB(
+                      (r2 * (dx - x) + r1 * x) / dx >> 8,
+                      (g2 * (dx - x) + g1 * x) / dx >> 8,
+                      (b2 * (dx - x) + b1 * x) / dx >> 8));
+                }
+            }
+        }
+      break;
+    default:
+      return FALSE;
   }
 
   return TRUE;


More information about the wine-patches mailing list