A Dimecres, 6 d'octubre de 2010, Christian Feuersaenger va escriure:
> Am 05.10.2010 22:59, schrieb Albert Astals Cid:
> > A Dijous, 30 de setembre de 2010, Christian Feuersaenger va escriure:
> >> Hello Albert,
> >> 
> >> Am 30.09.2010 00:00, schrieb Albert Astals Cid:
> >>> A Dijous, 19 d'agost de 2010, vàreu escriure:
> >>>> Dear Albert,
> >>>> 
> >>>> attached you find a test.pdf in which the improvements can be seen.
> >>>> 
> >>>> The rendering quality of my patch is much better; it eliminates the
> >>>> moire effects of the flat shading approximation (top left image).
> >>>> 
> >>>> Compare also the image with opacity on page 2 of test.pdf.
> >>>> 
> >>>> Besides the improved rendering quality, the most obvious change is the
> >>>> required runtime: on my system, the default xpdf requires 15 seconds
> >>>> until it stops rendering the first page whereas xpdf with poppler
> >>>> support and my new patch requires about one second. The pdftoppm
> >>>> utility is also considerably faster.
> >>>> 
> >>>> Let me stress that the patch is unrelated to my previous bugfixes, so
> >>>> rendering problems are only fixed together with the other bugfix.
> >>> 
> >>> I'm not sure i understand this last sentence, you say that the patches
> >>> are
> >>> unrelated but then you say the bugs are only fixed together with the
> >>> other
> >>> patch?
> >>> 
> >>> Should i run a regression test over this patch or does it need to be in
> >>> conjunction with the other patch?
> >> 
> >> The "Implementation for real gouraud shaded triangles" is more a new
> >> feature than simply a bugfix: it re-implements the shaders for the
> >> splash device. Its purpose is mainly a vastly improved rendering speed.
> >> I'd suggest to run regression tests on this implementation separately
> >> from my other patch proposals.
> >> 
> >> The other patch proposals (you have  processed them already; I still
> >> have to investigate your problem report) are bug fixes which should be
> >> tested separately.
> >> 
> >> My last remark is to be understood as follows:
> >> 1. if you view test.pdf with both patches, you have best quality and
> >> highest speed.
> >> 2. if you view test.pdf only with the given patch, you have high speed
> >> and good quality for the triangle patches, but the coons patch things
> >> will be buggy.
> >> 3. if you only process the other patch proposal (the bugfixes which are
> >> not part of mail), the coons patches are rendered correctly; but the
> >> triangle patches are slow and only approximately correct due to the
> >> piecewise flat triangle approximation as it is currently done in
> >> libpoppler.
> >> 
> >> I think the most reliable quality verification can be gained by testing
> >> both patches separately.
> > 
> > Ok, i've ran the test regression over this aptch and everything seems to
> > be ok, could you please fix the FIXME and TODO you have in the code?
> 
> Hello Albert,
> 
> I'm glad the regression tests passed. Concerning the FIXME and TODO
> list: They constitute (without exception) additional features which do
> not limit the application of the patch (falling back to the old
> implementations automatically). I am willing to work on the FIXMEs, but
> a realization might not be finished before the beginning of the new year
> due to my personal time schedule for the next months.
> 
> I suggest to incorporate the patch into libpoppler as-is, and I will
> work on the remaining feature requests eventually.

Not really, i want at least splashModeXBGR8 fixed (can can just try it with 
qt4/test/test-poppler-qt4) before commiting since is what the Qt frontend uses 
that is the major user of the Splash backend.

I attach the patch as i tried.

Albert

> 
> Best regards
> 
> Christian
> 
> > Thanks,
> > 
> >    Albert
> >> 
> >> Best regards
> >> 
> >> Christian
> >> 
> >> PS
> >> Sorry if you get notifications because of 'Post by non-member to a
> >> members-only list'... I keep clicking onto the wrong email address :(
> >> (have now registered both of them)
> >> 
> >>> Albert
> >>> 
> >>>> Best regards
> >>>> 
> >>>> Christian
> >>>> 
> >>>> Am 18.08.2010 23:15, schrieb Albert Astals Cid:
> >>>>> A Dijous, 15 de juliol de 2010, Christian Feuersaenger va escriure:
> >>>>>> Dear poppler developers,
> >>>>>> 
> >>>>>> hereby I propose a new patch for a high quality, fast gouraud
> >>>>>> shader for
> >>>>>> triangle shadings.
> >>>>>> 
> >>>>>> The patch provides
> >>>>>> - scalable triangle shadings (in contrast to the old approach),
> >>>>>> - correct shading, no approximation using flat triangles,
> >>>>>> - greatly (!) improved rendering speed,
> >>>>>> - support for opacity (in contrast to the previous approach).
> >>>>>> 
> >>>>>> This patch is relative to the master branch,
> >>>>>> git show poppler-0.14.0-91-g31ac578 .
> >>>>>> 
> >>>>>> It is unrelated to my previous patch proposals concerning shadings;
> >>>>>> the
> >>>>>> other patch proposal (my mail several weeks ago) is still important
> >>>>>> and
> >>>>>> relevant. The patch in this mail is independent and does not
> >>>>>> include my
> >>>>>> previous patch proposals.
> >>>>>> 
> >>>>>> I tested the new patch with pdftoppm and with the xpdf-poppler fork
> >>>>>> of Rogerio Brito; it appears to work reliable. I tested
> >>>>>> - matrix shadings and triangle patch shadings (Types 4 and 5),
> >>>>>> - degenerated triangles,
> >>>>>> - clipping,
> >>>>>> - opacity,
> >>>>>> - RGB color spaces.
> >>>>>> 
> >>>>>> The implementation now supports these shadings on a display driver
> >>>>>> level
> >>>>>> and is implemented directly in the splash device (using scanline
> >>>>>> sweeps).
> >>>>>> 
> >>>>>> I've been defensive: I have no test cases for other color spaces and
> >>>>>> I have no test data for non-parametric shadings. Consequently, I
> >>>>>> disabled
> >>>>>> the shader for these cases; it will fall back to the existing
> >>>>>> solutions
> >>>>>> (approximate shading by means of many flat triangles).
> >>>>>> 
> >>>>>> I hope you find my patch proposal useful. I believe it is worthy of
> >>>>>> being part of libpoppler.
> >>>>> 
> >>>>> Do you have a pdf where we can see the improvement this patch gives?
> >>>>> 
> >>>>> Albert
> >>>>> 
> >>>>>> Thanks,
> >>>>>> 
> >>>>>> Christian
> >>>>> 
> >>>>> _______________________________________________
> >>>>> poppler mailing list
> >>>>> [email protected]
> >>>>> http://lists.freedesktop.org/mailman/listinfo/poppler
> >>> 
> >>> _______________________________________________
> >>> poppler mailing list
> >>> [email protected]
> >>> http://lists.freedesktop.org/mailman/listinfo/poppler
> >> 
> >> _______________________________________________
> >> poppler mailing list
> >> [email protected]
> >> http://lists.freedesktop.org/mailman/listinfo/poppler
> > 
> > _______________________________________________
> > poppler mailing list
> > [email protected]
> > http://lists.freedesktop.org/mailman/listinfo/poppler
> 
> _______________________________________________
> poppler mailing list
> [email protected]
> http://lists.freedesktop.org/mailman/listinfo/poppler
diff --git a/poppler/Function.cc b/poppler/Function.cc
index e7383fd..d32948c 100644
--- a/poppler/Function.cc
+++ b/poppler/Function.cc
@@ -523,6 +523,7 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
   e = obj1.getNum();
   obj1.free();
 
+  isLinear = fabs(e-1.) < 1e-10;
   ok = gTrue;
   return;
 
@@ -553,7 +554,7 @@ void ExponentialFunction::transform(double *in, double *out) {
     x = in[0];
   }
   for (i = 0; i < n; ++i) {
-    out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
+    out[i] = c0[i] + ( isLinear ? x : pow(x, e) ) * (c1[i] - c0[i]);
     if (hasRange) {
       if (out[i] < range[i][0]) {
 	out[i] = range[i][0];
diff --git a/poppler/Function.h b/poppler/Function.h
index 2dcccb0..de9a88c 100644
--- a/poppler/Function.h
+++ b/poppler/Function.h
@@ -174,6 +174,7 @@ private:
   double c0[funcMaxOutputs];
   double c1[funcMaxOutputs];
   double e;
+  bool isLinear;
   GBool ok;
 };
 
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 7552fed..8edb0b6 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -3096,6 +3096,11 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
 }
 
 void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
+  if( out->useShadingType( shading->getType() ) ) {
+    if( out->gouraudTriangleShadedFill( state, shading ) )
+      return;
+  }
+
   double x0, y0, x1, y1, x2, y2;
   GfxColor color0, color1, color2;
   int i;
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index 59a8863..7a9e68e 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -3394,6 +3394,41 @@ void GfxGouraudTriangleShading::getTriangle(
   }
 }
 
+void GfxGouraudTriangleShading::getParameterizedColor(
+					double t, GfxColor* color ) {
+
+  double out[gfxColorMaxComps];
+  int j;
+
+  for (j = 0; j < nFuncs; ++j) {
+    funcs[j]->transform(&t, &out[j]);
+  }
+  for (j = 0; j < gfxColorMaxComps; ++j) {
+    color->c[j] = dblToCol(out[j]);
+  }
+}
+
+void GfxGouraudTriangleShading::getTriangle(
+				    int i,
+				    double *x0, double *y0, double *color0,
+				    double *x1, double *y1, double *color1,
+				    double *x2, double *y2, double *color2) {
+  int v;
+
+  v = triangles[i][0];
+  *x0 = vertices[v].x;
+  *y0 = vertices[v].y;
+  *color0 = colToDbl(vertices[v].color.c[0]);
+  v = triangles[i][1];
+  *x1 = vertices[v].x;
+  *y1 = vertices[v].y;
+  *color1 = colToDbl(vertices[v].color.c[0]);
+  v = triangles[i][2];
+  *x2 = vertices[v].x;
+  *y2 = vertices[v].y;
+  *color2 = colToDbl(vertices[v].color.c[0]);
+}
+
 //------------------------------------------------------------------------
 // GfxPatchMeshShading
 //------------------------------------------------------------------------
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 900214d..dbcbcee 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -876,10 +876,35 @@ public:
   virtual GfxShading *copy();
 
   int getNTriangles() { return nTriangles; }
+
+  bool isParameterized() const { return nFuncs > 0; }
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMin() const { return funcs[0]->getDomainMin(0); }
+  /**
+   * @precondition isParameterized() == true
+   */
+  double getParameterDomainMax() const { return funcs[0]->getDomainMax(0); }
+
+  /**
+   * @precondition isParameterized() == false
+   */
   void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
 		   double *x1, double *y1, GfxColor *color1,
 		   double *x2, double *y2, GfxColor *color2);
 
+  /**
+   * Variant for functions.
+   *
+   * @precondition isParameterized() == true
+   */
+  void getTriangle(int i, double *x0, double *y0, double *color0,
+		   double *x1, double *y1, double *color1,
+		   double *x2, double *y2, double *color2);
+
+  void getParameterizedColor( double t, GfxColor* color );
+
 private:
 
   GfxGouraudVertex *vertices;
diff --git a/poppler/OutputDev.h b/poppler/OutputDev.h
index cdc74cf..b6bc5ca 100644
--- a/poppler/OutputDev.h
+++ b/poppler/OutputDev.h
@@ -47,6 +47,8 @@ class GfxColorSpace;
 class GfxImageColorMap;
 class GfxFunctionShading;
 class GfxAxialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
 class GfxRadialShading;
 class Stream;
 class Links;
@@ -87,6 +89,9 @@ public:
   // will be reduced to a series of other drawing operations.
   virtual GBool useShadedFills() { return gFalse; }
 
+  // Does this device support specific shading types?
+  // see gouraudTriangleShadedFill() and patchMeshShadedFill()
+  virtual GBool useShadingType( int type ) { if( type < 4 ) return useShadedFills(); return gFalse; }
   // Does this device use FillColorStop()?
   virtual GBool useFillColorStop() { return gFalse; }
 
@@ -208,6 +213,10 @@ public:
     { return gFalse; }
   virtual GBool radialShadedSupportExtend(GfxState * /*state*/, GfxRadialShading * /*shading*/)
     { return gFalse; }
+  virtual GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+    { return gFalse; }
+  virtual GBool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
+    { return gFalse; }
 
   //----- path clipping
   virtual void clip(GfxState * /*state*/) {}
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 0ae5bc5..129f07a 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -963,6 +963,13 @@ void SplashOutputDev::startDoc(XRef *xrefA) {
   nT3Fonts = 0;
 }
 
+GBool SplashOutputDev::useShadingType( int type )
+{
+  if( type < 4 )
+    return useShadedFills();
+  return type == 4 || type == 5;
+}
+
 void SplashOutputDev::startPage(int pageNum, GfxState *state) {
   int w, h;
   double *ctm;
@@ -3186,3 +3193,8 @@ void SplashOutputDev::setFreeTypeHinting(GBool enable)
 {
   enableFreeTypeHinting = enable;
 }
+
+GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
+{
+	return splash->gouraudTriangleShadedFill(state,shading);
+}
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index adbd196..2b7a9e3 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -81,6 +81,8 @@ public:
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() { return gTrue; }
 
+  virtual GBool useShadingType( int type );
+
   // This device now supports text in pattern colorspace!
   virtual GBool supportTextCSPattern(GfxState *state)
   	{ return state->getFillColorSpace()->getMode() == csPattern; }
@@ -217,6 +219,8 @@ public:
 
   SplashFont *getCurrentFont() { return font; }
 
+  GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading);
+
 #if 1 //~tmp: turn off anti-aliasing temporarily
   virtual GBool getVectorAntialias();
   virtual void setVectorAntialias(GBool vaa);
diff --git a/splash/Splash.cc b/splash/Splash.cc
index 5e27d42..c0278bb 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -55,6 +55,10 @@ static inline Guchar div255(int x) {
   return (Guchar)((x + (x >> 8) + 0x80) >> 8);
 }
 
+template<typename T>
+inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
+
+
 //------------------------------------------------------------------------
 // SplashPipe
 //------------------------------------------------------------------------
@@ -3182,6 +3186,332 @@ void Splash::compositeBackground(SplashColorPtr color) {
   memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
 }
 
+//#include <iostream> // FIXME
+GBool Splash::gouraudTriangleShadedFill(GfxState *gfxState, GfxGouraudTriangleShading *shading)
+{
+	// TODO : 
+	// - sanity checking between Function and colorspace is not done
+	// - did not test anything but RGB colors
+  double xdbl[3] = {0., 0., 0.};
+  double ydbl[3] = {0., 0., 0.};
+  int    x[3] = {0, 0, 0};
+  int    y[3] = {0, 0, 0};
+  double xt=0.,xa=0.,yt=0.;
+  double ca=0.,ct=0.;
+
+  // triangle interpolation:
+  //
+  double scanLimitMapL[2] = {0., 0.};
+  double scanLimitMapR[2] = {0., 0.};
+  double scanColorMapL[2] = {0., 0.};
+  double scanColorMapR[2] = {0., 0.};
+  double scanColorMap[2] = {0., 0.};
+  int scanEdgeL[2] = { 0, 0 };
+  int scanEdgeR[2] = { 0, 0 };
+  bool hasFurtherSegment = false;
+
+  int X=0,Y=0;
+  int scanLineOff=0;
+  int bitmapOff=0;
+  int scanLimitR=0,scanLimitL=0,Yt=0;
+  int i=0,m=0;
+
+  int bitmapWidth = bitmap->getWidth();
+  SplashClip* clip = getClip();
+  SplashBitmap *blitTarget = bitmap;
+  SplashColorPtr bitmapData = bitmap->getDataPtr();
+  SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
+  SplashColorPtr cur=NULL;
+  SplashCoord* userToCanvasMatrix = getMatrix();
+  SplashColorMode bitmapMode = bitmap->getMode();
+  bool hasAlpha=(bitmapAlpha != NULL);
+  int rowSize = bitmap->getRowSize();
+  int colorComps=0;
+  switch (bitmapMode) {
+  case splashModeMono1:
+    return gFalse; // FIXME. This can't work yet.
+    break;
+  case splashModeMono8:
+    return gFalse; // FIXME I disable it just because it is not tested.
+    colorComps=1;
+    break;
+  case splashModeRGB8:
+  case splashModeBGR8:
+    colorComps=3;
+    break;
+  case splashModeXBGR8:
+    return gFalse; // FIXME I disable it just because it is not tested.
+    colorComps=3;
+	break;
+#if SPLASH_CMYK
+  case splashModeCMYK8:
+    return gFalse; // FIXME I disable it just because it is not tested.
+    colorComps=4;
+    break;
+#endif
+  }
+
+  SplashPipe pipe;
+  SplashColor cSrcVal;
+  pipeInit(&pipe, 0, 0, NULL, cSrcVal, state->strokeAlpha,
+	   gFalse, gFalse);
+
+  // idea:
+  // 1. If pipe->noTransparency && !state->blendFunc
+  //  -> blit directly into the drawing surface!
+  //  -> disable alpha manually.
+  // 2. Otherwise:
+  // - blit also directly, but into an intermediate surface.
+  // Afterwards, blit the intermediate surface using the drawing pipeline.
+  // This is necessary because triangle elements can be on top of each
+  // other, so the complete shading needs to be drawn before opacity is
+  // applied.
+  // - the final step, is performed using a SplashPipe:
+  // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
+  // - invoke drawPixel(&pipe,X,Y,bNoClip);
+  bool bDirectBlit = pipe.noTransparency && !state->blendFunc;
+  if( !bDirectBlit ) {
+	  blitTarget = new SplashBitmap( 
+			  bitmap->getWidth(),
+			  bitmap->getHeight(),
+			  bitmap->getRowPad(),
+			  bitmap->getMode(),
+			  true,
+			  bitmap->getRowSize() >= 0 );
+	  bitmapData = blitTarget->getDataPtr();
+	  bitmapAlpha = blitTarget->getAlphaPtr();
+
+	  // initialisation seems to be necessary:
+	  int S = bitmap->getWidth() * bitmap->getHeight();
+	  for( i = 0; i<S; ++i )
+		  bitmapAlpha[i] = 0;
+	  hasAlpha = true;
+  }
+
+  if( shading->isParameterized() ) {
+    double color[3];
+    double colorinterp;
+    GfxColor mappedColor;
+
+    for (i = 0; i < shading->getNTriangles(); ++i) {
+          shading->getTriangle(i, 
+                           xdbl+0, ydbl+0, color+0,
+                           xdbl+1, ydbl+1, color+1,
+                           xdbl+2, ydbl+2, color+2);
+          for( m =0; m<3; ++m ) {
+            xt= xdbl[m] * userToCanvasMatrix[0] + ydbl[m] * userToCanvasMatrix[2] + userToCanvasMatrix[4];
+            yt= xdbl[m] * userToCanvasMatrix[1] + ydbl[m] * userToCanvasMatrix[3] + userToCanvasMatrix[5];
+            xdbl[m] = xt;
+            ydbl[m] = yt;
+            // we operate on scanlines which are integer offsets into the
+            // raster image. The double offsets are of no use here.
+            x[m] = splashRound(xt);
+            y[m] = splashRound(yt);
+          }
+          // sort according to y coordinate to simplify sweep through scanlines:
+		  // INSERTION SORT.
+		  if( y[0] > y[1] ) {
+			  Guswap( x[0], x[1] );  Guswap( y[0], y[1] ); Guswap( color[0], color[1] );
+		  }
+		  // first two are sorted .
+		  assert( y[0] <= y[1] );
+		  if( y[1] > y[2] ) {
+			  int tmpX = x[2];
+			  int tmpY = y[2];
+			  double tmpC = color[2];
+			  x[2] = x[1]; y[2] = y[1]; color[2] = color[1];
+
+			  if( y[0] > tmpY ) {
+				  x[1] = x[0]; y[1] = y[0]; color[1] = color[0];
+				  x[0] = tmpX; y[0] = tmpY; color[0] = tmpC;
+			  } else {
+				  x[1] = tmpX; y[1] = tmpY; color[1] = tmpC;
+			  }
+		  }
+		  // first three are sorted
+		  assert( y[0] <= y[1] );
+		  assert( y[1] <= y[2] );
+		  /////
+
+		  // this here is det( T ) == 0
+		  // where T is the matrix to map to barycentric coordinates.
+		  if( (x[0]-x[2]) * (y[1]-y[2])
+			- (x[1]-x[2]) * (y[0]-y[2]) == 0 )
+            continue; // degenerate triangle.
+
+          // this here initialises the scanline generation.
+          // We start with low Y coordinates and sweep up to the large Y
+          // coordinates.
+          //
+          // scanEdgeL[m] in {0,1,2} m=0,1
+          // scanEdgeR[m] in {0,1,2} m=0,1
+          //
+          // are the two edges between which scanlines are (currently)
+          // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
+          // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
+          //
+          scanEdgeL[0] = 0;
+          scanEdgeR[0] = 0;
+          if( y[0] == y[1] ) {
+            scanEdgeL[0] = 1;
+            scanEdgeL[1] = scanEdgeR[1] =2;
+
+          } else {
+            scanEdgeL[1] = 1; scanEdgeR[1] = 2;
+          }
+          assert( y[scanEdgeL[0]] < y[scanEdgeL[1]] );
+          assert( y[scanEdgeR[0]] < y[scanEdgeR[1]] );
+
+		  // Ok. Now prepare the linear maps which map the y coordinate of
+		  // the current scanline to the corresponding LEFT and RIGHT x
+		  // coordinate (which define the scanline).
+          scanLimitMapL[0] = double(x[scanEdgeL[1]]  - x[scanEdgeL[0]]) / (y[scanEdgeL[1]]  - y[scanEdgeL[0]] );
+          scanLimitMapL[1] = x[scanEdgeL[0]]  - y[scanEdgeL[0]]  * scanLimitMapL[0];
+          scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+          scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+          xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1];
+          xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1];
+          if( xa > xt ) {
+            // I have "left" is to the right of "right".
+            // Exchange sides!
+            Guswap(scanEdgeL[0], scanEdgeR[0]);
+            Guswap(scanEdgeL[1], scanEdgeR[1]);
+            Guswap(scanLimitMapL[0], scanLimitMapR[0]);
+            Guswap(scanLimitMapL[1], scanLimitMapR[1]);
+            // FIXME I'm sure there is a more efficient way to check this.
+          }
+
+          //std::cout << "triangle " << i << "\t (" <<xdbl[0]<<", "<<ydbl[0] <<");   (" << xdbl[1] <<", "<<ydbl[1] <<");   (" << xdbl[2]<<", "<<ydbl[2]<<")\n" << "         \t (" <<x[0]<<", "<<y[0] <<" [" << color[0] <<"]);   (" << x[1] <<", "<<y[1] <<" [" << color[1] <<"]);   (" << x[2]<<", "<<y[2]<<" [" << color[2] <<"])" << std::endl;
+          //std::cout << "scanEdgeL = " << scanEdgeL[0] << " " << scanEdgeL[1] << std::endl;
+          //std::cout << "scanEdgeR = " << scanEdgeR[0] << " " << scanEdgeR[1] << std::endl;
+
+		  // Same game: we can linearly interpolate the color based on the
+		  // current y coordinate (that's correct for triangle
+		  // interpolation due to linearity. We could also have done it in
+		  // barycentric coordinates, but that's slightly more involved)
+          scanColorMapL[0] = (color[scanEdgeL[1]]  - color[scanEdgeL[0]]) / (y[scanEdgeL[1]]  - y[scanEdgeL[0]] );
+          scanColorMapL[1] = color[scanEdgeL[0]]  - y[scanEdgeL[0]]  * scanColorMapL[0];
+          scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+          scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+
+
+          Y = y[0];
+          Yt= y[2];
+          hasFurtherSegment = (y[1] < y[2]);
+          scanLineOff = Y * rowSize;
+
+          for( Y = y[0]; Y <= y[2]; ++Y, scanLineOff+=rowSize ) {
+            if( hasFurtherSegment && Y == y[1] ) {
+			  // SWEEP EVENT: we encountered the next segment.
+			  //
+              // switch to next segment, either at left end or at right
+              // end:
+              if( scanEdgeL[1] == 1 ) {
+                scanEdgeL[0] = 1;
+                scanEdgeL[1] = 2;
+                scanLimitMapL[0] = double(x[scanEdgeL[1]]  - x[scanEdgeL[0]]) / (y[scanEdgeL[1]]  - y[scanEdgeL[0]] );
+                scanLimitMapL[1] = x[scanEdgeL[0]]  - y[scanEdgeL[0]]  * scanLimitMapL[0];
+                
+                scanColorMapL[0] = (color[scanEdgeL[1]]  - color[scanEdgeL[0]]) / (y[scanEdgeL[1]]  - y[scanEdgeL[0]] );
+                scanColorMapL[1] = color[scanEdgeL[0]]  - y[scanEdgeL[0]]  * scanColorMapL[0];
+                //std::cout << "scanEdgeL = " << scanEdgeL[0] << " " << scanEdgeL[1] << std::endl;
+              } else if( scanEdgeR[1] == 1 ) {
+                scanEdgeR[0] = 1;
+                scanEdgeR[1] = 2;
+                scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+                scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+                scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+                scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+                //std::cout << "scanEdgeR = " << scanEdgeR[0] << " " << scanEdgeR[1] << std::endl;
+              }
+              assert( y[scanEdgeL[0]]  <  y[scanEdgeL[1]] );
+              assert( y[scanEdgeR[0]] <  y[scanEdgeR[1]] );
+              hasFurtherSegment = false;
+            }
+
+            yt = Y;
+
+            xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
+            xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
+
+            ca = yt * scanColorMapL[0] + scanColorMapL[1];
+            ct = yt * scanColorMapR[0] + scanColorMapR[1];
+
+            scanLimitL=splashRound(xa);
+            scanLimitR=splashRound(xt);
+
+			// Ok. Now: init the color interpolation depending on the X
+			// coordinate inside of the current scanline:
+            scanColorMap[0] = (scanLimitR==scanLimitL) ? 0. : ( (ct - ca) / (scanLimitR - scanLimitL) );
+            scanColorMap[1] = ca - scanLimitL * scanColorMap[0];
+
+            //std::cout << "scanline y= "<< Y << " for x = " << scanLimitL <<  " (color " <<ca <<") to " << scanLimitR << "(color " << ct << ") [ " << xa << " = " << scanLimitMapL[0] << "*y + " << scanLimitMapL[1] <<" to " << xt << " = " << scanLimitMapR[0] << "*y + " << scanLimitMapR[1] << "] hasFurtherSegment = " << hasFurtherSegment << std::endl;
+
+            // handled by clipping:
+            // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
+            assert(scanLimitL <= scanLimitR || abs( scanLimitL-scanLimitR)<=2); // allow rounding inaccuracies
+            assert( scanLineOff == Y*rowSize );
+
+			colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1];
+
+            bitmapOff = scanLineOff + scanLimitL * colorComps;
+            for( X = scanLimitL; X<=scanLimitR; ++X, colorinterp+=scanColorMap[0], bitmapOff += colorComps ) {
+              // FIXME : standard rectangular clipping can be done for a
+              // complete scanline which is faster
+              // --> see SplashClip and its methods
+              if( !clip->test(X,Y) )
+                continue;
+
+			  assert( fabs( colorinterp - (scanColorMap[0] * X + scanColorMap[1]) ) < 1e-10 );
+
+              shading->getParameterizedColor(colorinterp, &mappedColor);
+
+              // FIXME : I am pretty sure this works only for RGB color
+              // spaces. 
+              assert( bitmapOff == Y*rowSize + colorComps*X && scanLineOff == Y*rowSize);
+  			  cur = &bitmapData[bitmapOff];
+			  for( m = 0; m<colorComps; ++m )
+				  cur[m] = colToByte(mappedColor.c[m]);
+			  // make the shading visible.
+			  // Note that opacity is handled by the bDirectBlit stuff, see
+			  // above for comments and below for implementation.
+			  if(hasAlpha)
+				  bitmapAlpha[ Y*bitmapWidth + X ] = 255;
+            }
+
+          }
+    }
+
+  } else {
+    return false;
+  }
+  if( !bDirectBlit ) {
+	  // ok. Finalize the stuff by blitting the shading into the final
+	  // geometry, this time respecting the rendering pipe.
+	  int W = blitTarget->getWidth();
+	  int H = blitTarget->getHeight();
+	  cur = cSrcVal;
+
+	  for( X = 0; X<W; ++X ) {
+		  for( Y = 0; Y<H; ++Y ) {
+			  if( !bitmapAlpha[ Y*bitmapWidth + X ] )
+				  continue; // draw only parts of the shading!
+              bitmapOff = Y*rowSize + colorComps*X;
+
+			  for( m = 0; m<colorComps; ++m )
+				  cur[m] = bitmapData[bitmapOff+m];
+			  drawPixel(&pipe, X,Y, true ); // no clipping - has already been done.
+		  }
+	  }
+
+	  delete blitTarget; blitTarget=NULL;
+  }
+
+  return true;
+}
+
 SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
 				    int xDest, int yDest, int w, int h) {
   SplashColor pixel;
diff --git a/splash/Splash.h b/splash/Splash.h
index c9d57cc..bc3589b 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -28,6 +28,7 @@
 
 #include "SplashTypes.h"
 #include "SplashClip.h"
+#include "GfxState.h"
 
 class Splash;
 class SplashBitmap;
@@ -209,6 +210,10 @@ public:
 			int xDest, int yDest, int w, int h,
 			GBool noClip, GBool nonIsolated);
 
+  // Draw a triangle shading.
+  // Return true on success and false if the operation is not supported.
+  GBool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading);
+
   // Composite this Splash object onto a background color.  The
   // background alpha is assumed to be 1.
   void compositeBackground(SplashColorPtr color);
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index f983439..4094db9 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -50,6 +50,7 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
   width = widthA;
   height = heightA;
   mode = modeA;
+  this->rowPad = rowPad;// just remember it.
   switch (mode) {
   case splashModeMono1:
     if (width > 0) {
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index e741a91..e42a49d 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -56,6 +56,7 @@ public:
   int getHeight() { return height; }
   int getRowSize() { return rowSize; }
   int getAlphaRowSize() { return width; }
+  int getRowPad() { return rowPad; }
   SplashColorMode getMode() { return mode; }
   SplashColorPtr getDataPtr() { return data; }
   Guchar *getAlphaPtr() { return alpha; }
@@ -73,6 +74,7 @@ public:
 private:
 
   int width, height;		// size of bitmap
+  int rowPad;
   int rowSize;			// size of one row of data, in bytes
 				//   - negative for bottom-up bitmaps
   SplashColorMode mode;		// color mode
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to